欢迎进入Wiki » FAQ » Sencha Touch 中,如何开发 nestedList 查询功能?

Sencha Touch 中,如何开发 nestedList 查询功能?

在2014-01-07 11:17上被李小翔修改
评论 (0) · 附件 (1) · 记录 · 信息

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: ' 姓名..'
        },...
    ]
}

添加了查询框后,界面如下图所示:

通讯录查询.png

然后,修改控制器,添加查询和重置事件:

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 后,可以调用其 filterfind 方法执行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子节点,这才是正确结果。
标签: Sencha Touch
在2014-01-07 11:17上被李小翔创建

Copyright © 2013 北京博瑞开源软件有限公司
京ICP备12048974号