AntD-V实现Tree树形控件模糊搜索功能

需求是要在树形控件上方做个搜索功能,可以模糊搜索到树中对应的节点,右侧会有另一个面板记录所有被选择的节点,antd 官方文档刚好有个例子是可以实现这个需求的,打算直接拿来用。

官方文档地址:https://www.antdv.com/components/tree-cn/#components-tree-demo-searchable

<a-input
  placeholder="请输入部门名称"
  @pressEnter="onSearchDepartment"
  v-model.trim="searchValue"
  allowClear
>
  <a-icon slot="prefix" type="search" />
</a-input>
<a-tree
  checkable
  checkStrictly
  :expanded-keys="expandedKeys"
  :auto-expand-parent="autoExpandParent"
  :treeData="treeData"
  @expand="onExpand"
>
  <a-icon slot="switcherIcon" type="down" />
  <!--用作用域插槽自定义树组件的标题部分-->
  	<template #custom="{title}">
			<!--如果模糊查询到了则高亮显示-->
  	  <span v-if="title.indexOf(searchValue) > -1">
  	    {{ title.substring(0, title.indexOf(searchValue)) }}
  	    <span style="color: #1A90FF">{{ searchValue }}</span>
  	    {{ title.substring(title.indexOf(searchValue) + searchValue.length) }}
  	  </span>
  	  <span v-else>{{ title }}</span>
  	</template>
</a-tree>

实现思路: 请求后台树状数据时,留存一份平面化的数据,在用户搜索时,找到对应项的父节点展开,并且 tree 组件中搜索字高亮显示。

export default {
  data() {
    return {
      treeData: [], // tree组件的数据
      searchValue: '', // 搜索框的内容
      expandedKeys: [], //展开的树节点
      autoExpandParent: true, // 是否自动展开父节点
      treeDataList: [], //平面的部门信息列表
    };
  },
  watch: {
    searchValue: function() {
      this.onSearchDepartment();
    },
  },
  methods: {
    // 从后台获取树形数据
    getTreeData() {
      this.$http
        .xxxx()
        .then({data} => {
        	//给tree组件递归赋值 设置作用域插槽的name
					this.treeData = this.dataFormat(data);
        	//留存一份平面的数据
          this.generateList(data);
        })
        .catch(response => {
          this.$message.error(response.errorMessage);
        });
    },
    dataFormat(data){
      return data.map(item => {
        if(item.children){
        	item.children = this.dataFormat(item.children);
        }
      	return {
        	...item,
          scopedSlots: { title: 'custom' },
        }
      });
    },
    // 树状数据平面化
    generateList(data) {
      data.forEach(item => {
        const key = item.key;
        this.treeDataList.push({ key, title: item.title });
        if (node.children) {
          this.generateList(node.children);
        }
      });
    },
    // 搜索时触发
    onSearchDepartment() {
      // 在平面数据中找到搜索的项 再把对应项的父节点key赋值给 控制展开节点的列表
      this.expandedKeys = this.treeDataList
        .map(item => {
          if (item.title.indexOf(this.searchValue) > -1)
            return this.getParentKey(item.key, this.treeData);
          return null;
        })
        .filter((v, i, ary) => v && ary.indexOf(v) === i);
      //启用自动展开父节点
      this.autoExpandParent = true;
    },
    // 在树状数据中 找到搜索节点的父节点的key
    getParentKey(key, tree) {
      let parentKey;
      tree.forEach(item => {
        const node = item;
        if (node.children) {
          if (node.children.some(v => v.key === key)) {
            parentKey = node.key;
          } else if (this.getParentKey(key, node.children)) {
            parentKey = this.getParentKey(key, node.children);
          }
        }
      });
      return parentKey;
    },
    // 树节点展开/收起时触发
    onExpand(expandedKeys) {
      // 树节点手动展开/关闭时 以用户操作的为准
      this.expandedKeys = expandedKeys;
      this.autoExpandParent = false;
    },
  },
};