extjs7 combobox 根据输入值执行远端查询过滤选项源码分析

版本

extjs 7.4.0 classic

源码

ext-classic/src/form/field/Base.js

// 初始化事件时将onFieldMutation函数绑定到propertychange,textInput事件上
initEvents: function() {
    var me = this,
        inputEl = me.inputEl,
        onFieldMutation = me.onFieldMutation,
        events = me.checkChangeEvents,
        len = events.length,
        i, event;

    if (inputEl) {
        me.mon(
            inputEl, Ext.supports.SpecialKeyDownRepeat ? 'keydown' : 'keypress', me.fireKey, me
        );

        for (i = 0; i < len; ++i) {
            event = events[i];

            if (event === 'propertychange') {
                me.usesPropertychange = true;
            }

            if (event === 'textInput') {
                me.usesTextInput = true;
            }

            me.mon(inputEl, event, onFieldMutation, me);
        }
    }

    me.callParent();
}
  • 在输入事件后通过延时(配置项queryDelay,默认值500)任务执行查询,避免输入过程中无效查询
    ext-classic/src/form/field/ComboBox.js
onFieldMutation: function(e) {
   var me = this,
        key = e.getKey(),
        isDelete = key === e.BACKSPACE || key === e.DELETE,
        rawValue = me.inputEl.dom.value,
        len = rawValue.length;

    // Do not process two events for the same mutation.
    // For example an input event followed by the keyup that caused it.
    // We must process delete keyups.
    // Also, do not process TAB event which fires on arrival.
    if (!me.readOnly && (rawValue !== me.lastMutatedValue || isDelete) && key !== e.TAB) {
        me.lastMutatedValue = rawValue;
        me.refreshEmptyText();

        if (len && (e.type !== 'keyup' || (!e.isSpecialKey() || isDelete))) {
            me.doQueryTask.delay(me.queryDelay);
        }
        else {
            // We have *erased* back to empty if key is a delete,
            // or it is a non-key event (cut/copy)
            if (!len && (!key || isDelete)) {
                // This portion of code may end up calling setValue will check for change.
                // But since it's come from field mutations, we need to respect
                // the checkChangeBuffer, so we suspend checks here, it will be handled
                // by callParent
                ++me.suspendCheckChange;

                // Essentially a silent setValue.
                // Clear our value, and the tplData used to construct a mathing raw value.
                if (!me.multiSelect) {
                    me.value = null;
                    me.displayTplData = undefined;
                }

                // If the value is blank we can't have a value
                if (me.clearValueOnEmpty) {
                    me.valueCollection.beginUpdate();
                    me.pickerSelectionModel.deselectAll();
                    me.valueCollection.removeAll();
                    me.valueCollection.endUpdate();
                }

                // Just erased back to empty. Hide the dropdown.
                me.collapse();

                // There may have been a local filter if we were querying locally.
                // Clear the query filter and suppress the consequences
                // (we do not want a list refresh).
                if (me.queryFilter) {
                    me.clearLocalFilter();
                }

                // When queryCaching if the user deletes the value and then starts typing
                // the same filter again, doQuery can erroneously expand the picker without
                // filtering first.
                me.lastQuery = null;

                --me.suspendCheckChange;
            }

            me.callParent([e]);
        }
    }
}
  • 查询任务
    ext-classic/src/form/field/ComboBox.js
// 初始化查询任务
initComponent: function() {
	...
	me.doQueryTask = new Ext.util.DelayedTask(me.doRawQuery, me);
	...
}
// 获取输入值执行查询
doRawQuery: function() {
    var me = this,
        rawValue = me.inputEl.dom.value;
    if (me.multiSelect) {
        rawValue = rawValue.split(me.delimiter).pop();
    }
    me.doQuery(rawValue, false, true);
}
// 执行查询
doQuery: function(queryString, forceAll, rawQuery) {
    var me = this,
        store = me.getStore(),
        filters = store.getFilters(),
        // 判断是否可以,以及如何执行查询
        queryPlan = me.beforeQuery({
            lastQuery: me.lastQuery || '',
            query: queryString || '',
            rawQuery: rawQuery,
            forceAll: forceAll,
            combo: me,
            cancel: false
        }),
        refreshFilters;
    if (queryPlan !== false && !queryPlan.cancel) {
        // 如果包含查询字符串,并且但钱没有查询过滤器(正在执行查询)或与上次查询的过滤器不同,则执行查询
        refreshFilters = !!queryString && (!me.queryFilter || me.queryFilter &&
                         (filters.indexOf(me.queryFilter) < 0));
        // 如果与上一次查询相同则展开下拉框
        if (me.queryCaching && !refreshFilters && queryPlan.query === me.lastQuery) {
            me.getPicker().refresh();
            me.expand();
            me.afterQuery(queryPlan);
        }
		// 否则执行查询并重新加载store
        else {
            me.lastQuery = queryPlan.query;
            if (me.queryMode === 'local') {
                me.doLocalQuery(queryPlan);

            }
            else {
                me.doRemoteQuery(queryPlan);
            }
        }
        return true;
    }
    else {
        me.startCheckChangeTask();
    }
    return false;
}
// 执行远端查询,将查询字符串加入到store加载参数中
doRemoteQuery: function(queryPlan) {
    var me = this,
        loadCallback = function() {
            if (!me.destroyed) {
                me.afterQuery(queryPlan);
            }
        };
    me.expand();
    if (me.pageSize) {
        me.loadPage(1, {
            rawQuery: queryPlan.rawQuery,
            callback: loadCallback
        });
    }
    else {
        me.store.load({
            params: me.getParams(queryPlan.query),
            rawQuery: queryPlan.rawQuery,
            callback: loadCallback
        });
    }
},
// 分页查询
loadPage: function(pageNum, options) {
    this.isPaging = true;
    this.store.loadPage(pageNum, Ext.apply({
        params: this.getParams(this.lastQuery)
    }, options));
},
  • 默认查询判断函数,如果没有监听事件beforequery,则根据查询字串长度小于最小字符数(配置项minChars,默认值4)则取消查询
    ext-classic/src/form/field/ComboBox.js
beforeQuery: function(queryPlan) {
    var me = this;
    if (me.fireEvent('beforequery', queryPlan) === false) {
        queryPlan.cancel = true;
    }
    else if (!queryPlan.cancel) {
        if (queryPlan.query.length < me.minChars && !queryPlan.forceAll) {
            queryPlan.cancel = true;
        }
    }
    return queryPlan;
}

posted on 2022-04-11 22:38  路过君  阅读(61)  评论(0编辑  收藏  举报

导航