a-tree树形控件

609 阅读2分钟

"ant-design-vue": "^1.78"

树形控件渲染数据注意

对于异步请求的数据不能刷新页面,渲染数结构。

解决办法

  • 在父组件中请求数据,传入子组件

  • 使用v-if判断请求数据是否完成,然后再进行渲染

搜索

对于antdv@1.7.8版本官网示例有些麻烦,可以考虑用chatGPT实现

原理是:根据输入内容,使用递归方法重新生成树data,形成新的树(并非唯一)

展开指定节点和默认展开

expandedKeys 会覆盖 defaultExpandedKeys

通过给expandedKeys赋值方式实现defaultExpandedKeys

组件封装


<template>
  <a-spin :spinning="confirmLoading">
    <div class="modal-tree">
      <a-input-search placeholder="请输入树节点" v-model="searchValue" />
      <a-tree
        v-model="checkedKeys"
        v-if="orgTree.length > 0"
        :selectedKeys.sync="selectedKeys"
        :show-line="true"
        :show-icon="true"
        :tree-data="filteredData"
        :expanded-keys="expandedKeys"
        :autp-expanded-parent="autoExpandedParent"
        :checkable="checkable"
        :checkStrictly="checkStrictly"
        @select="onSelect"
        @expand="onExpand"
        @check="onCheck"
      >
        <img src="@/assets/gov-icon.png" slot="folder" />
        <!-- title slot仅用于实现字体高亮 -->
        <!-- 通过substr将title分成三部分。将含有搜索条件的字符串高亮显示 -->
        <template slot="title" slot-scope="{ title }">
          <span v-if="title.indexOf(searchValue) > -1">
            {{ title.substr(0, title.indexOf(searchValue)) }}
            <span
              style="color: #f50"
            >{{ searchValue }}</span>
            {{ title.substr(title.indexOf(searchValue) + searchValue.length) }}
          </span>
          <span v-else>{{ title }}</span>
        </template>
      </a-tree>
    </div>
  </a-spin>
</template>

<script>
import { getAction } from "@/api/manage";
export default {
  props: {
    treeType: {
      type: String,
      default: "depart",
      required: true
    },
    checkable: {
      type: Boolean,
      default: false
    },
    hasChecked: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      url: { // 请求路径
        system: ""
      },
      orgTree: [], // 树结构完整数据
      expandedKeys: [], // 展开指定节点
      checkedKeys: [], // 复选框选中的树节点
      autoExpandedParent: false,
      searchValue: "", // 搜索条件
      selectedKeys: [], // 点击某个树节点
      nodeKeys: [], // 默认展开节点
      confirmLoading: false,
      checkStrictly: true // 父子不关联
    };
  },
  computed: {
    // 树实际渲染的数据
    filteredData() {
      if (!this.searchValue) {
        return this.orgTree;
      }
      const filteredNodes = [];
      this.orgTree.forEach(node => {
        this.searchAndFilter(node, this.searchValue, filteredNodes);
      });
      return filteredNodes;
    }
  },

  created() {
    // 获取树数据
    this.getTreeByType();
  },
  methods: {
    // chatGPT生成的树的过滤方法
    searchAndFilter(node, searchText, filteredNodes) {
      // console.log(node)
      if (node.title.includes(searchText)) {
        filteredNodes.push(node);
        // node.setExpanded(true);
      }
      if (node.children) {
        node.children.forEach(childNode => {
          this.searchAndFilter(childNode, searchText, filteredNodes);
        });
      }
    },
    getTreeByType() {
      const body = {};
      this.confirmLoading = true;
      getAction(this.url[this.type], body)
        .then(res => {
          if (res.success) {
            let list = Object.assign([], res.result); // 防止数据污染
            this.eachIt(list);
            this.orgTree = list;
            console.log(this.orgTree, this.treeType);

            // expandedKeys 会覆盖 defaultExpandedKeys
            // 通过给expandedKeys赋值方式实现defaultExpandedKeys
            this.expandedKeys = Object.assign([], this.nodeKeys);

            this.checkedKeys = Object.assign([], this.hasChecked); // 已选中
          } else {
            this.$message.warning(res.message);
          }
        })
        .finally(() => {
          this.confirmLoading = false;
        });
    },

    // 生成树结构
    eachIt(children) {
      children.forEach(item => {
        item["title"] = item.name;
        item["key"] = item.id;
        item["slots"] = { icon: "folder" };
        if (item.level == "1") {
          // 默认展开一级树节点
          this.nodeKeys.push(item.id);
        }
        if (item.children) {
          this.eachIt(item.children);
        }
      });
    },
    /**
     *
     * @param {*} selectedKeys 节点的某种属性
     * @param {*} info 完整数据
     */
    onSelect(selectedKeys, info) {
      this.$emit("select", selectedKeys, info);
    },
    // 实现展开指定节点
    onExpand(expandedKeys) {
      this.expandedKeys = expandedKeys;
      this.autoExpandedParent = false;
    },
    onCheck(checkedKeys, info) {
      if (this.checkStrictly) {
        // 关联和不关联 checkedKeys 可能不同
        this.checkedKeys = checkedKeys.checked;
      } else {
        this.checkedKeys = checkedKeys;
      }
      this.$emit("check", checkedKeys, info, this.checkedKeys);
    }
  }
};
</script>

<style scoped lang="less">
.modal-tree {
  max-height: 679px;
  overflow-y: scroll;
  .search-box {
    display: flex;
  }
}
</style>