写点什么

web 技术分享| 虚拟 tree

作者:anyRTC开发者
  • 2022-10-25
    上海
  • 本文字数:2221 字

    阅读完需:约 7 分钟

查了好久,觉得使用 Ant Design Vue 中的 Tree 树形控件因项目需求,节点的移动不通过拖拽移动,需要通过弹窗实现节点的移动,因此基于添加、删除实现。当前仅使用节点添加、删除、移动(删除+添加)以及懒加载。


开发中移动时注意懒加载的值,否则移动后,已经展开的节点无法正常展开

使用 Tree

tree 引入

使用 Ant Design Vue 中的 Tree 树形控件 引入 Tree


  • 具体引入方式查看 Ant Design Vue 文档

组件使用

template

  • expandedKeys 展开指定的树节点

  • loadedKeys 已经加载的节点,需要配合 loadData 使用(控制是否进行懒加载,移动(删除+添加)所需):保存 key 表示该节点已进行懒加载(如果删除该节点将会重新懒加载)

  • height 固定高度,虚拟滚动


相关代码:


  <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 相关方法

在 vue3 setup 中


  • 在懒加载中保存已经加载的节点


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" );
复制代码


封装 递归查询


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; } }};
复制代码



发布于: 刚刚阅读数: 4
用户头像

实时交互,万物互联! 2020-08-10 加入

实时交互,万物互联,全球实时互动云服务商领跑者!

评论

发布
暂无评论
web技术分享| 虚拟 tree_Vue_anyRTC开发者_InfoQ写作社区