ExtJS——高亮树typeAhead的匹配节点

ExtJS -- highlight matching nodes for tree typeAhead

我正在使用由 Sencha 的一位成员创建的树过滤器插件。这是他的 fiddle 插件:http://jsfiddle.net/slemmon/fSJwF/2/

正如您在 fiddle 中看到的,当 typeAhead 结果是父节点时,它的所有子节点都会展开。所以我想突出显示所有匹配的结果,因为我经常得到许多包含匹配的 typeAhead 搜索词的父节点,并且它们有数百个子节点,因此很难找到匹配的父节点。

复制粘贴来自 fiddle 的片段,因为 SO 抛出 "links to jsfiddle must be accompanied by code" 错误...

filter: function (value, property, re) {
            var me = this
                , tree = me.tree
                , matches = []                                          // array of nodes matching the search criteria
                , root = tree.getRootNode()                                // root node of the tree
                , property = property || 'text'                          // property is optional - will be set to the 'text' propert of the  treeStore record by default
                , re = re || new RegExp(value, "ig")                     // the regExp could be modified to allow for case-sensitive, starts  with, etc.
                , visibleNodes = []                                      // array of nodes matching the search criteria + each parent non-leaf  node up to root
                , viewNode;

            if (Ext.isEmpty(value)) {                                    // if the search field is empty
                me.clearFilter();
                return;
            }

            tree.expandAll();                                            // expand all nodes for the the following iterative routines

            // iterate over all nodes in the tree in order to evalute them against the search criteria
            root.cascadeBy(function (node) {
                if (node.get(property).match(re)) {                         // if the node matches the search criteria and is a leaf (could be  modified to searh non-leaf nodes)
                    matches.push(node)                                  // add the node to the matches array
                }
            });

            if (me.allowParentFolders === false) {                         // if me.allowParentFolders is false (default) then remove any  non-leaf nodes from the regex match
                Ext.each(matches, function (match) {
                    if (!match.isLeaf()) { Ext.Array.remove(matches, match); }
                });
            }

            Ext.each(matches, function (item, i, arr) {                 // loop through all matching leaf nodes
                root.cascadeBy(function (node) {                         // find each parent node containing the node from the matches array
                    if (node.contains(item) == true) {
                        visibleNodes.push(node)                          // if it's an ancestor of the evaluated node add it to the visibleNodes  array
                    }
                });
                if (me.allowParentFolders === true &&  !item.isLeaf()) {    // if me.allowParentFolders is true and the item is  a non-leaf item
                    item.cascadeBy(function (node) {                    // iterate over its children and set them as visible
                        visibleNodes.push(node)
                    });
                }
                visibleNodes.push(item)                                  // also add the evaluated node itself to the visibleNodes array
            });

            root.cascadeBy(function (node) {                            // finally loop to hide/show each node
                viewNode = Ext.fly(tree.getView().getNode(node));       // get the dom element assocaited with each node
                if (viewNode) {                                          // the first one is undefined ? escape it with a conditional
                    viewNode.setVisibilityMode(Ext.Element.DISPLAY);     // set the visibility mode of the dom node to display (vs offsets)
                    viewNode.setVisible(Ext.Array.contains(visibleNodes, node));
                }
            });
        }

谢谢。

解决该问题的方法之一是向匹配的元素追加额外的 class 并按照您想要的方式设置样式。

在下面的源代码中,我将 class 'matched' 添加到每个匹配项。 Fiddle link 是 http://jsfiddle.net/0o0wtr7j/

Ext.define('TreeFilter', {
extend: 'Ext.AbstractPlugin'
    , alias: 'plugin.treefilter'

    , collapseOnClear: true                                             // collapse all nodes when clearing/resetting the filter
    , allowParentFolders: false                                         // allow nodes not designated as 'leaf' (and their child items) to  be matched by the filter

    , init: function (tree) {
        var me = this;
        me.tree = tree;

        tree.filter = Ext.Function.bind(me.filter, me);
        tree.clearFilter = Ext.Function.bind(me.clearFilter, me);
    }

    , filter: function (value, property, re) {
        var me = this
            , tree = me.tree
            , matches = []                                          // array of nodes matching the search criteria
            , root = tree.getRootNode()                                // root node of the tree
            , property = property || 'text'                          // property is optional - will be set to the 'text' propert of the  treeStore record by default
            , re = re || new RegExp(value, "ig")                     // the regExp could be modified to allow for case-sensitive, starts  with, etc.
            , visibleNodes = []                                      // array of nodes matching the search criteria + each parent non-leaf  node up to root
        , matchedClass = 'matched'
        , viewNode;

        if (Ext.isEmpty(value)) {                                    // if the search field is empty
            me.clearFilter();
            return;
        }

        tree.expandAll();                                            // expand all nodes for the the following iterative routines

        // iterate over all nodes in the tree in order to evalute them against the search criteria
        root.cascadeBy(function (node) {
            if (node.get(property).match(re)) {                         // if the node matches the search criteria and is a leaf (could be  modified to searh non-leaf nodes)
                node.set('cls', matchedClass);
                matches.push(node)                                  // add the node to the matches array
            } else {
                node.set('cls', '');
            }
        });

        if (me.allowParentFolders === false) {                         // if me.allowParentFolders is false (default) then remove any  non-leaf nodes from the regex match
            Ext.each(matches, function (match) {
                if (!match.isLeaf()) { Ext.Array.remove(matches, match); }
            });
        }

        Ext.each(matches, function (item, i, arr) {                 // loop through all matching leaf nodes
            root.cascadeBy(function (node) {                         // find each parent node containing the node from the matches array
                if (node.contains(item) == true) {
                    visibleNodes.push(node)                          // if it's an ancestor of the evaluated node add it to the visibleNodes  array
                }
            });
            if (me.allowParentFolders === true &&  !item.isLeaf()) {    // if me.allowParentFolders is true and the item is  a non-leaf item
                item.cascadeBy(function (node) {                    // iterate over its children and set them as visible
                    visibleNodes.push(node)
                });
            }
            visibleNodes.push(item)                                  // also add the evaluated node itself to the visibleNodes array
        });

        root.cascadeBy(function (node) {                            // finally loop to hide/show each node
            viewNode = Ext.fly(tree.getView().getNode(node));       // get the dom element assocaited with each node
            if (viewNode) {                                          // the first one is undefined ? escape it with a conditional
                viewNode.setVisibilityMode(Ext.Element.DISPLAY);     // set the visibility mode of the dom node to display (vs offsets)
                viewNode.setVisible(Ext.Array.contains(visibleNodes, node));
            }
        });
    }

    , clearFilter: function () {
        var me = this
            , tree = this.tree
            , root = tree.getRootNode();

        if (me.collapseOnClear) { tree.collapseAll(); }             // collapse the tree nodes
        root.cascadeBy(function (node) {                            // final loop to hide/show each node
            node.set('cls', '');
            viewNode = Ext.fly(tree.getView().getNode(node));       // get the dom element assocaited with each node
            if (viewNode) {                                          // the first one is undefined ? escape it with a conditional and show  all nodes
                viewNode.show();
            }
        });
    }});