现在的位置: 首页 > 综合 > 正文

让客户端javascript修改的内容在服务端也能记忆的一个简单例子

2013年09月13日 ⁄ 综合 ⁄ 共 3987字 ⁄ 字号 评论关闭
让客户端javascript修改的内容在服务端也能记忆的一个简单例子

在asp.net中,由于微软使用了WebControl控件,利用一种叫做ViewState方式,将服务端设置的内容记录在ViewState中,这样,当每次数据重新提交到客户端后,自动从ViewState中恢复前一次设置的内容。无状态的网页具有了部分记忆功能。

但在用的过程中,为了避免与服务端过多的交互,有时候会直接在客户端使用javascript脚本修改一些网页元素的内容,例如label的text,但在提交到服务端后,系统并不知道客户端的改变,会自动从ViewState中恢复原有内容,造成数据丢失。类似的问题还表现在服务端控件DropDownList, ListBox在客户端增加项后,回到服务端同样会从ViewState中恢复到原来的内容。

目前asp.net中的服务端控件和对应产生的客户端网页元素的关联很弱,几乎是完全割裂的,仅仅依靠原有html的form机制和__doPostBack方法,产生了服务端的事件处理机制。

微软的asp.net还有很大的改善空间,既然利用了ViewState将服务端控件的属性内容存储在客户端页面中,就应该可以改进为它的服务端控件产生客户端对象,允许在客户端直接操作部分属性。
下面介绍一个简单例子,处理label的text在客户端的修改,让服务端"记忆"客户端的改变:

1. 建立一个保持客户端、服务端联系的类
public class WebControlClientClass
{
    private System.Collections.ArrayList m_list = new System.Collections.ArrayList();

    public WebControlClientClass()
    {
    }

    public void Add(System.Web.UI.WebControls.WebControl obj)
    {
        if( obj == null )
        {
        }

        if( m_list.IndexOf(obj) < 0 )
        {
            m_list.Add(obj);
        }
    }

    public void Make(System.Web.UI.Page page)
    {
        System.Type t;
        object obj;
        string s;
        for(int i=0; i<m_list.Count; i++)
        {
            obj = m_list[i];
            t = obj.GetType();
            s = t.ToString();
            switch( s )
            {
                case "System.Web.UI.WebControls.Label":
                {
                    make_LabelClientClass(page, obj as System.Web.UI.WebControls.Label);
                    break;
                }

                default:
                {
                    break;
                }
            }
        }
    }

    public void Restore(System.Web.UI.Page page)
    {
        if( page == null )
        {
            return;
        }

        if( page.IsPostBack == false )
        {
            return;
        }

        System.Type t;
        object obj;
        for(int i=0; i<m_list.Count; i++)
        {
            obj = m_list[i];
            t = obj.GetType();
            switch( t.ToString() )
            {
                case "System.Web.UI.WebControls.Label":
                {
                    restore_LabelClientClass(obj as System.Web.UI.WebControls.Label);
                    break;
                }

                default:
                {
                    break;
                }
            }
        }
    }

    private void restore_LabelClientClass(System.Web.UI.WebControls.Label label)
    {
        string hiddenID = "hidden"+label.ClientID;
        string v = System.Web.HttpContext.Current.Request.Form[hiddenID];
        label.Text = v;
    }

    private void make_LabelClientClass(System.Web.UI.Page page, System.Web.UI.WebControls.Label label)
    {
        string sClass="<script>/n"+
            "function LabelClientClass(id)/n"+
            "{/n"+
            "    this.id = id;/n"+
            "    this.hiddenID = 'hidden'+id;/n"+
            "    this.getText = function()/n"+
            "    {/n"+
            "        return document.getElementById(this.id).innerText;/n"+
            "    }/n"+
            "    this.setText = function(s)/n"+
            "    {/n"+
            "        document.getElementById(this.id).innerText=s;/n"+
            "        document.getElementById(this.hiddenID).value = s;/n"+
            "    }/n"+
            "}/n"+
            "</script>";
        string keyClass = "LabelClientClass";

        if( page.IsClientScriptBlockRegistered(keyClass) == false )
        {
            page.RegisterClientScriptBlock(keyClass, sClass);
        }

        string sLabel, keyLabel;
        sLabel = string.Format("<script>var obj{0}=new LabelClientClass('{0}');</script>", label.ClientID);
        keyLabel = "LabelClientObject"+label.ClientID;

        if( page.IsStartupScriptRegistered(keyLabel) == false)
        {
            page.RegisterHiddenField("hidden"+label.ClientID, label.Text);
            page.RegisterStartupScript(keyLabel, sLabel);
        }
    }
}

2. 在网页的程序部分申明 WebControlClientClass 类的对象 client;
WebControlClientClass client= new WebControlClientClass();

3. 在Page_Load中,将label控件加入client中,并执行 client.Restore方法。

//加入使用客户端的控件列表
client.Add(this.Label1);
client.Restore(this);

4. 在Page的 PreRender 事件中,利用client对象,生成对应的客户端对象。

//必须在服务端修改label内容之后,所以 PreRender 事件最合适。
client.Make(this);

5. 在客户端,用label对应的客户端对象的方法 setText 修改label的text
objLabel1.setText("test");

客户端对象名称与服务端对象名称有关,如果服务端的id=Label1, 则客户端的对象名称为 objLabel1

这里仅仅是简单以Label为例子,大家可以修改、扩展 WebControlClientClass,让它能够处理ListBox, DropDownList, RadioGroup等,产生对应的客户端对象,这样就可以像在服务端一样处理部分属性的方法,甚至事件包装。

【上篇】
【下篇】

抱歉!评论已关闭.