The Ant Design TreeSelect tree selection control has been wrapped in a basic package. The Ant Design TreeSelect tree selection control has been wrapped in a basic package. The Ant Design TreeSelect tree selection control has been wrapped in a basic package. The Ant Design TreeSelect tree selection control has been wrapped in a basic package.

Reasons for encapsulation: Before, the department tree data was loaded at one time, which had performance problems. When there was a large amount of data, the loading was very slow, and the components might crash. So change to asynchronous loading data, the system is used in many places, it is impossible to change every place, packaging unified processing.

Ant Design TreeSelect: juejin.cn/post/700328…

Component packaging

  1. departSource: Data source, which displays the root department and primary department data by default
  2. onLoadData: Asynchronously loads data. Query subdepartment data based on the department ID and load it to the data source
  3. treeExpandedKeys: Expanded tree node. The root department is expanded by default
<template>
  <a-tree-select
    v-bind="$attrs"
    v-on="selectListeners"
    class="m-width"
    placeholder="Please select"
    searchPlaceholder="Please enter department name"
    :treeDefaultExpandAll="false"
    :treeData="departSource"
    :load-data="onLoadData"
    @treeExpand="handleExpand"
    :treeExpandedKeys="treeExpandedKeys"
    :dropdownStyle="{ maxHeight: '400px' }"
    show-search
    treeNodeFilterProp="title"
  >
  </a-tree-select>
</template>
Copy the code

Simulated data

Simulated data

const tree = [
  {
    id: 1.name: "Root department".departNumber: 6.children: [{id: 11.pid: 1.name: "Division I 1".departNumber: 2.children: [{id: 111.pid: 11.name: "Department 2 1".departNumber: 0 },
          { id: 112.pid: 11.name: "Department ii 2".departNumber: 0},],}, {id: 21.pid: 1.name: "Division I 2".departNumber: 0 },
      { id: 31.pid: 1.name: "Division I 3".departNumber: 0 },
      { id: 41.pid: 1.name: "Division I 4".departNumber: 0 },
      { id: 51.pid: 1.name: "Division 1 5".departNumber: 0 },
      {
        id: 61.pid: 1.name: "Division I 6".departNumber: 2.children: [{id: 611.pid: 61.name: "Department 2 3".departNumber: 0 },
          { id: 612.pid: 61.name: "Department 2 4".departNumber: 0},],},],},];Copy the code

Depth-first traversal (DFS)

DFS — Depth First Search: Starting from the root node, a complete subtree is accessed First, and then adjacent unaccessed subtrees are accessed until all subtrees are accessed. Access to the subtree is the same as before, until all nodes are accessed.

Simple graphical display:

Function code display:

/** * depth-first traversal *@params {Array} Tree Indicates the tree data@params {Array} Func operator function */
const dfsTransFn = (tree, func) = > {
  tree.forEach((node) = > {
    func(node);
    // If the subtree exists, call recursively
    if(node.children && node.children.length) { dfsTransFn(node.children, func); }}); };// Example 1: Print a node
dfsTransFn(tree, (node) = > {
  console.log(`${node.id}.${node.name}`);
});

// Example 2: Tree to list
let treeList = [];
dfsTransFn(tree, (node) = > {
  treeList.push(node);
});
console.log(treeList);
Copy the code

Function running effect display:

Breadth-first traversal (BFS)

BFS — Breadth First Search: Starting from the root node, First visit the initial queue where the root node is located, carry out operations, and add all the children of the node into the queue; It then accesses the first element in the queue and performs operations until the queue is empty. That is, the NTH layer must be visited before accessing the NTH +1 layer of the tree structure, and the entire tree structure must be thoroughly searched until the result is found.

Simple graphical display:

Function code display:

/** * width first traversal *@params {Array} Tree Indicates the tree data@params {Array} Func operator function */
const bfsTransFn = (tree, func) = > {
  let node,
    list = [...tree];
  // shift()- take the first; Pop ()- take the last one
  while ((node = list.shift())) {
    func(node);
    // If the subtree exists, call recursively
    node.children && list.push(...node.children);
  }
};

// Example 1: Print a node
bfsTransFn(tree, (node) = > {
  console.log(`${node.id}.${node.name}`);
});
// Example 2: Tree to list
let treeList = [];
bfsTransFn(tree, (node) = > {
  treeList.push(node);
});
console.log(treeList);
Copy the code

Function running effect display:

The difference between

  1. Depth-first: no need to remember all nodes, small space; Stack form, first in last out
  2. Breadth first: all nodes need to be recorded, occupying large space; Queue format, first in, first out

Real data

Initialization processing

During initialization, the root department data and primary department data need to be requested

  1. queryRootDepartDetail: This interface is used to obtain detailed data of the root department.
  2. queryChildDeparts: The interface obtains the data of the subdepartment based on the department ID.
  3. isLeaf: whether it is a leaf node, through whether there are subdepartments (o.departNumber>0) to determine
<script>
  import * as R from "ramda";
  // Conversion function: converts interface fields into data required by the component
  // Add the isLeaf parameter
  const tranFn = (data) = > {
    if (R.type(data) === "Array" && R.length(data) > 0) {
      return R.map(
        (o) = > ({
          value: o.id,
          key: o.id,
          title: o.name,
          children: [].// Whether it is a leaf node: Check whether there are sub-departments
          isLeaf: !o.departNumber,
        }),
        data
      );
    } else {
      return[]; }};export default {
    created() {
      this.queryAsyncDeparts();
    },
    methods: {
      async queryAsyncDeparts() {
        let res = await queryRootDepartDetail();

        // Request root department data
        let departId = R.path(["data"."id"], res);
        // Request root department data
        this.departSource = tranFn([res.data]);
        // The root node is expanded by default
        this.treeExpandedKeys = [departId];
        // Use the root department ID to load data of sub-departments and display data of the root department and primary department initially
        this.queryMoreData(departId);
      },
      queryMoreData(departId){},}};</script>
Copy the code

Realization effect display:

Load tree nodes asynchronously

There are two ways to add data to the corresponding department tree node: depth-first and breadth-first traversal

<script>
  /** * Load data asynchronously (depth-first traversal) *@params {Array} Tree Indicates the tree data@params {number} DepartId Specifies the department ID *@params {Array} ChildList loaded data */
  const transTreeFn = (tree, departId, childList) = > {
    return R.map((o) = > {
      if (o.key === departId) {
        o.children = tranFn(childList);
      } else if (o.children && o.children.length) {
        transTreeFn(o.children, departId, childList);
      }
      return o;
    }, tree);
  };

  export default {
    methods: {
      // Load more events
      onLoadData(treeNode) {
        const { key } = treeNode.dataRef;
        this.queryMoreData(key);
      },
      // Asynchronous data loading
      queryMoreData(departId) {
        // Find the corresponding data in the data source based on the department ID and populate the sub-department data
        queryChildDeparts(departId).then((res) = > {
          // Simulate data
          // let childList = [
          // {id: 1001, name: "add department 1", departNumber: 0},
          // {id: 1002, name: "add department 2", departNumber: 0},
          // ];

          let childList = R.pathOr([], ["data"], res);
          this.departSource = transTreeFn(
            this.departSource,
            departId,
            childList
          );
        });
      },
      // Control the expansion node
      handleExpand(expandedKeys) {
        this.treeExpandedKeys = expandedKeys; ,}}};</script>
Copy the code