web technology sharing | virtual tree

After searching for a long time, I feel that the Tree control in Ant Design Vue is used.
Due to project requirements, the movement of nodes does not need to be moved by dragging, but needs to be moved through pop-up windows, so it is based on adding and deleting.
Currently only node addition, deletion, movement (deletion+addition) and lazy loading are used.

Pay attention to the value of lazy loading when moving during development, otherwise, the expanded nodes cannot be expanded normally after moving

Use Tree

tree import

Use the Tree control in Ant Design Vue to introduce Tree

  • See the Ant Design Vue documentation for the specific import method

Component usage

template

  • expandedKeys expands the specified tree node

  • loadedKeys The loaded node needs to be used in conjunction with loadData (to control whether to perform lazy loading, required for moving (delete+add)): saving the key indicates that the node has been lazy loaded (if the node is deleted, it will be lazy loaded again)

  • height fixed height, virtual scrolling

Relevant code:

  <a-tree
          v-model:expandedKeys="MonitorArea.expandedKeys"
          v-model:loadedKeys="MonitorArea.loadedKeys"
          :height="510"
          :tree-data="MonitorArea.options"
          :load-data="onLoadData"
        >
        <-- 展开折叠自定义 -->、
         <template #switcherIcon="{ expanded }">
            <img
              v-if="expanded"
              class="w-5 h-5"
              src="@/assets/img/spread.png"
              draggable="false"
              alt=""
            />
            <img
              v-else
              class="w-5 h-5"
              src="@/assets/img/fewer.png"
              draggable="false"
              alt=""
            />
          </template>
           <template #title="item">
             ...内容自定义...
           </template>
  </a-tree>

ts related methods

in vue3 setup

  • Save already loaded nodes in lazy loading
const MonitorArea = reactive({
  // 默认展开指定节点
   expandedKeys: [""],
   loadedKeys: [""],     
   // 内容     
   options: [] as any[],  
   // 字段替换    
   fieldNames: {     
    children: "children",    
    title: "name",   
    key: "deviceId",
  },
};
/** 懒加载 **/
const onLoadData: TreeProps["loadData"] = (treeNode) => {
  return new Promise(async (resolve) => {
    // 是否是子叶点(无 childern)
    if (treeNode.dataRef?.isLeaf) {
      resolve();
      return;
    }
    // 保存 key 表示该节点已进行懒加载(如果删除该节点将会重新懒加载)
    MonitorArea.loadedKeys.push(对应节点的key);
    treeNode.dataRef!.children = 对应节点的子节点列表
    MonitorArea.options = [...MonitorArea.options];
    resolve();
  }
}
/** 创建子节点 **/
searchOption(
          Object.assign(子节点信息, {
            isLeaf: true,
          }),
          MonitorArea.options,
          "add"
        );
/** 删除子节点 **/
searchOption(子节点信息, MonitorArea.options);
/** 移动(删除+添加)节点 **/
// 删除老数据
await searchOption(老数据, MonitorArea.options);

// 过滤掉旧的节点以及父节点相关懒加载
MonitorArea.loadedKeys = MonitorArea.loadedKeys.filter((item) => {
            return 过滤;
          });
// 同上
MonitorArea.expandedKeys = MonitorArea.expandedKeys.filter((item) => {
            return 过滤;
          });

// 添加移动后的数据
 searchOption(
            Object.assign(移动后的数据, {
              isLeaf: 判断是否存在childern,
            }),
            MonitorArea.options,
            "add"
          );

Encapsulate recursive query

const searchOption = (
  option: { deviceId: string; parentId: string; name: string },
  arr: any[],
  type = "delect"
) => {
  for (let s = 0; s < arr.length; s++) {
    // console.log(type, option.deviceId, arr[s].deviceId);

    if (type === "edit" && arr[s].deviceId === option.deviceId) {
      // 编辑
      arr[s].name = option.name;
      break;
    } else if (type !== "edit" && arr[s].deviceId === option.parentId) {
      // 父节点-添加
      if (type === "add") {
        if (!arr[s].children) {
          arr[s].children = [];
        }
        const isExist = arr[s].children.some((item: { deviceId: string }) => {
          return item.deviceId === option.deviceId;
        });
        if (!isExist) {
          arr[s].childIsNull = 0;
          arr[s].isLeaf = false;
          arr[s].class = "show_line";
          arr[s].children.unshift(option);
        }
      }
      // 父节点-删除
      if (type === "delect") {
        arr[s].children = arr[s].children.filter(
          (item: { deviceId: string }) => {
            return item.deviceId !== option.deviceId;
          }
        );
        if (arr[s].children.length == 0) {
          arr[s].isLeaf = true;
          arr[s].class = "";
          arr[s].childIsNull = 1;
        }
      }
      break;
    } else if (arr[s].children && arr[s].children.length > 0) {
      // 递归条件
      searchOption(option, arr[s].children, type);
    } else {
      continue;
    }
  }
};

insert image description here

Guess you like

Origin blog.csdn.net/anyRTC/article/details/127508585