blog icon indicating copy to clipboard operation
blog copied to clipboard

ElementUI Tree 组件节点筛选显示所有后代节点

Open ryancui92 opened this issue 5 years ago • 0 comments

ElementUI 提供的 Tree 组件中有一个 filter-node-method 的 props, 可以配合 filter 方法来做树的查找筛选功能,具体的用法是:

<template>
  <el-tree
    ref="tree"
    :data="data"
    node-key="id"
    :filter-node-method="filterTree"
  />
</template>
<script>
  export default {
    data() {
      return [/* 一堆树结构数据 */]
    },
    methods: {
      filterTree(value, data, node) {
        return data.label.includes(value)
      }
    }
  }
</script>

定义了 filterTree 方法后,使用 this.$refs.tree.filter(value) 方法可以对树节点进行筛选,这个 value 会传到 filterTree 中,对每个树节点调用一次该方法,根据返回的结果决定是否显示。

因此像上面的实现,只保证了命中的节点会被显示,当然 Element 保证了命中的节点的所有祖先节点都会被显示,不然很突兀地出现了嵌套在里面几级的节点也有点奇怪。然而经常会有一种需求,需要显示命中节点的所有后代节点,上面的写法就需要改造了。

最直观的想法是这里的返回不能只根据自己是否命中,应该考虑该节点的所有祖先节点是否命中。即:

是否显示 = 我命中了 || 我的祖先命中了

这里涉及到了状态保存与遍历方式的问题,于是观察一下 Element 对这个筛选 filter-node-method 的调用,不难发现这是个 DFS 的树遍历,正合我意啊。同时也在内部维护的 node 中找到了 node.visible 的标记,保存了筛选结果啊。

这样一来,这个方法就很好写了,但是要注意 Element 内部会给第一层的所有节点给一个虚拟的 root, 而且这个 root 的 visible 默认是 true 的,因此对第一层要做点特别处理:

function filterTree(value, data, node) {
  // 第一层的节点,只需要考虑自己是否命中就好了
  if (node.parent && !node.parent.parent) {
    return data.label.includes(value)
  }
  return data.label.includes(value) || node.parent.visible
}

问题解决。

ryancui92 avatar Nov 14 '19 06:11 ryancui92