我们都知道,Vs.Net这样的工具每次打开时都会记住我们上次关闭时的状态:各个窗口的位置、大小;工具栏状态;自定义菜单项等。这无疑是一个使用的功能。ExtJs也包含提供了状态保存机制,其主要的控件:GirdPanel,FormPanel等,都提供了状态保存的功能。我们需要的仅仅是为其提供适当的Provider。
1,客户端状态的保存
我们先来看一下当一个ExtJs中的控件状态改变时,持久化该控件状态的流程:
流程中的前两步(红色)是控件负责的。当控件状态改变时,会使用JSON串行化自身状态,然后调用Ext.state.Manager.getProvider()这个静态方法取得当前程序配置的Provider,进而调用Provider的set方法,保存自身状态。我们需要做的便是提供一个Provider,当其set方法被调用时,将传递过来的控件状态保存到服务器就可以了。该Provider的代码如下:
1: Srims.providerCtor = Ext.extend(Ext.state.Provider, {
2:
3: get: function(name, defaultValue){
4: //alert('get:' + name + ' : ' + Srims.provider._state[name]);
5: //return defaultValue;
6:
7: if (Srims.provider._state[name])
8: return Ext.util.JSON.decode(Srims.provider._state[name]);
9:
10: return defaultValue;
11: },
12: set: function(name, value){
13: //alert('set:' + name + ' ' + Ext.util.JSON.encode(value));
14: var valueString = Ext.util.JSON.encode(value)
15: Srims.provider._state[name] = valueString;
16:
17: Ext.Ajax.request({
18: url: '/User.asmx/SetExtClientState',
19: method: 'POST',
20: params: {
21: key: name,
22: value: valueString
23: }
24: });
25: },
26: clear: function(name){
27: Srims.provider._state[name] = undefined;
28: }
29: });
30:
31: Srims.provider = new Srims.providerCtor();
32: Srims.provider._state = new function(){
33: };
其中Srims.privoider._state(32行)是本地用于保存状态的对象,相当于一个缓存。set方法首先编码控件状态(14行),然后将控件状态储存在Srims.privoider._state中(15行),进而发起Ajax请求,调用WebService,传递控件ID及其状态,服务器端将根据这两个参数持久化该控件当前状态(17行)。至此是流程图中的第三、四两步(蓝色表示)。
定义了Provider类后,我们就可以把它构造出来(31行),然后调用:
Ext.state.Manager.setProvider(Srims.provider);
将我们的Provider设置为系统公用的,这样ExtJs中的控件就可以使用Ext.state.Manager.getProvider()得到这个Provider了。
服务器端Users.asmx的SetExtClientState'方法负责保存客户端控件的状态,对应流程中最后两步(绿色表示)。使用XML串行化所有控件的状态,形成的XML类似以下样子:
1: <?xml version="1.0" encoding="utf-8"?>
2: <ExtClientState>
3:
4: <ProjectGridPanel_HorizontalList>
5: {"columns":[{"id" :0,"hidden":true},{"id":1,"width":93},......
6: </ProjectGridPanel_HorizontalList>
7:
8: <ProjectGridPanel_VerticalList>
9: {"columns":[{"id":0,"hidden":true},......
10: </ProjectGridPanel_VerticalList>
11:
12: <DivPanelMenu>
13: {"collapsed":false}
14: </DivPanelMenu>
15:
16: </ExtClientState>
其中节点名称是客户端控件的ID,节点的值是该控件的状态。上面的XML描述了三个控件的状态,其中前两个:ProjectGridPanel_HorizontalList和ProjectGridPanel_VerticalList是GridPanel,最后一个DivPanelMenu是Panel。
2,状态的加载与还原
当下一次系统加载的时候,我们在所有控件加载之前,先把这个XML发送给客户端,就可以复原客户端状态了,代码如下:
1: Srims.provider.loadState = function(callback){
2: Ext.Ajax.request({
3: url: '/User.asmx/GetExtClientState',
4: method: 'POST',
5: success: Srims.provider._onLoadState,
6: scope: callback
7: });
8: };
9: Srims.provider._onLoadState = function(response){
10:
11: var rootNode = Ext.DomQuery.selectNode('/ExtClientState', response.responseXML);
12: var nodes = Ext.DomQuery.select('*', rootNode);
13:
14: for (var i = 0; i < nodes.length; i++) {
15: var node = nodes[i];
16: Srims.provider._state[node.tagName] = Ext.DomQuery.selectValue('/', node);
17: //alert(node.tagName + Srims.provider._state[node.tagName]);
18: }
19:
20: this();
21: }
第二行的Ajax请求负责从User.asmx/GetExtClientState读客户端状态,其响应是上面的XML。然后回调函数Srims.provider._onLoadState负责将状态解析还原到Srims.provider._state这个本地缓存中。
客户端状态还原后,控件加载的时候,就可以使用Provider提取上次的状态。状态的加载和恢复的流程总结如下:
本文中出现的代码,去掉注释后结合FireBug可以清楚地了解到整个状态保存和还原的过程。