Touch中,定义了一个通讯录的面板,面板中包含了一个 nestedList,同时还定义了一个 TreeStore,通过ajax的方式加载远程数据并显示,代码片段如下:
// 定义通讯录面板
Ext.define('MyApp.view.AddressPanel', {
extend: 'Ext.Panel',
config: {
itemId: 'addressPanel',
items: [
{
xtype: 'nestedlist',
store: 'AddressJsonTreeStore',
title: '通讯录',
...
}, ...
], ...
}, ...
};
// 定义 TreeStore
Ext.define('MyApp.store.AddressJsonTreeStore', {
extend: 'Ext.data.TreeStore',
config: {
model: 'MyApp.model.AddressModel',
storeId: 'AddressJsonTreeStore',
proxy: {
type: 'ajax',
url: 'address',
reader: {
type: 'json'
}
}, ...
}, ...
});
现在,需要在这个面板的title bar上,添加一个查询框,以实现根据名称查询的功能,由于数据库比较大,并且都是延迟加载,因此仍然采用ajax的加载方式。
首先,我们在通讯录面板的title bar上添加一个查询框searchfield:
...
title: '通讯录',
toolbar: {
xtype: 'titlebar',
items: [
{
xtype: 'searchfield',
align: 'right',
itemId: 'seaerchAddressField',
maxWidth: '130px',
label: '',
placeHolder: ' 姓名..'
},...
]
}
添加了查询框后,界面如下图所示:

然后,修改控制器,添加查询和重置事件:
Ext.define('MyApp.controller.AddressController', {
extend: 'Ext.app.Controller',
config: {
refs: {
// 定义一个属性,便于使用
addressNestedList: 'addresspanel nestedlist[itemId=addressNestedList]',
...
},
control: {
// 定义两个事件
"addresspanel [itemId=seaerchAddressField]": {
action: 'onSeaerchAddressFieldAction', // 点击查询后的事件
clearicontap: 'onSeaerchAddressFieldClearicontap' // 点击重置图标后的事件
}, ...
}
},
/**
* 点击查询后的事件
*/
onSeaerchAddressFieldAction: function(textfield, e, eOpts) {
this.searchAction( textfield.getValue().trim() );
},
/**
* 点击重置图标后的事件
*/
onSeaerchAddressFieldClearicontap: function(textfield, e, eOpts) {
this.searchAction();
},
/**
* 执行查询或重置
*/
searchAction: function(val) {
......
}
});
上面的控制器代码中,关键就是下面那个 searchAction 方法,这里将执行查询操作:
- 方案1:TreeStore 有一个 remoteFilter 属性,设置为 true 后,可以调用其 filter 或 find 方法执行ajax查询。
但是在实际测试中,这种方法的性能非常低下,基本不可用 - 方案2:每次查询时,重新创建一个新的 store 对象,并设置为 nestedList 的 store,执行ajax查询与重新渲染。
这中方案执行效率相当高,最终的代码示例如下。
searchAction: function(val) {
if ( val ) {
val = val.replace(/['"\/\\\s]/g, '');
if ( val.length < 2 ) {
return Ext.Msg.alert("请输入至少两个字");
}
}
var list = this.getAddressNestedList();
var storeId = "AddressJsonTreeStore_" + val;
if ( !val ) { // 重置
store = Ext.getStore("AddressJsonTreeStore");
} else { // 搜索
store = Ext.getStore(storeId);
if ( !store ) {
// 不同的查询条件,后台返回的机构id必须不一样,否则可能显示后台数据中没有的机构节点
store = Ext.create("MyApp.store.AddressJsonTreeStore", { storeId: storeId });
store.getProxy().setExtraParam('find', val); // 设置远程查询参数
list.getStore().setAutoDestroy(true);
list.setEmptyText("没有找到您想要的数据!");
}
}
list.updateStore( store ); // 速度最快
list.setStore( store );
}
在上面的最终代码中,需要注意后台返回的查询结果 json 数据中,如果仍然为树形结构,那么每个节点(非叶子节点)的id建议保持不一样,例如:
- 不是查询时,有如下的结构:{ data:{id:'foo', name:'foobar', data:{...}}, ... }
- 则查询结果应为:{ data:{id:'bar', name:'foobar', data:{...}}, ... }
原因在于 nestedList 的渲染缓存,如:
- 点开节点foobar,可以看到子节点 foo 与 bar
- 查询后,如果返回结果中的节点foobar的id保持不变,且子节点只有foo了,但此时点开节点foobar,仍然会显示出节点 foo 与 bar,这显然是错误的
- 若查询的返回结果中的节点foobar的id设置为一个新的值,则点开节点foobar后,只会显示出一个foo子节点,这才是正确结果。