Element-Plus+Vue3+TS的关于El-Table组件树形结构懒加载的节点增、删、改、查发送异步请求实时刷新节点【解决方案】

Element-Plus对El-Table组件进行了一些调整,以前适用与Vue2+Element Ui版本的相关方法已经有点不适用于Element-Plus。

一、关于树形结构的El-Table组件,实际上会有以下几种情况的操作:

1.新增顶级节点
2.新增非顶级节点
3.移动顶级节点到一个非顶级节点
4.移动非顶级节点到顶级节点
5.移动一个非顶级节点到非顶级节点
6.删除顶级节点
7.删除非顶级节点

这6种情况大致上就可以分为两大类。一是刷新节点(移动、新增节点都属于是刷新节点的操作);二是删除节点(上面提到的删除相关的操作就是这一类的情况)

二、以下是实现步骤:

1.获取到elTable的实例对象,通过ref指令去获取:

<el-table
  ref="elTableRef"
  lazy
  :tree-props="{ children: 'childrenNodes', hasChildren: 'hasChildrenNodes' }"
   row-key="id"
  :load="handleLazyLoadChildrenNodes"
 >...</el-table>

关于这里的El-Table的具体属性的用法和含义,参考Element-Plus的官方文档

2.如果项目里面有多个地方需要使用到El-Table的树化功能的话,建议将刷新树形El-Table节点和删除El-Table节点的方法单独抽出来,以便复用。

废话不多说,直接上代码:
2.1 刷新节点的TS代码

    /**
     * 刷新树形表格的节点
     * @param elTableRef el-table实例
     * @param node 节点
     * @param loadChildrenNodesHandler 加载子节点的函数
     */
    async refreshTreeTableColumnNode(elTableRef:TableInstance,node: { id?: string | number; parentId?: string | number;sourceParentId?:string|number; }, loadChildrenNodesHandler:(parentId?:string|number)=>Promise<any[]>):Promise<void>{
   
        let tableStore = elTableRef.store;
        let lazyTreeNodeMap:{[key:string|number]:any[];} =  (tableStore.states as { lazyTreeNodeMap: { value: {[key:string|number]:any[];} };}).lazyTreeNodeMap?.value || {};
        // 刷新新增或修改的节点的父节点下所有的子节点信息
        if (node.parentId){// 非顶级节点 parentId存在表示非顶级节点,那么就需要处理

            let parentId:number|string|undefined;

            let childrenNodes:any[] =  lazyTreeNodeMap[node.parentId];

            if(childrenNodes && childrenNodes.length > 0){ // 当前节点的父节点是展开的,那么需要刷新当前节点的父节点下的子节点信息
                parentId = node.parentId;
            }else { //当前节点的父节点是收起的,那么需要刷新当前节点的父节点所在的节点,以此来更新当前节点的父节点的状态
                for (const key of Object.keys(lazyTreeNodeMap)) {
                    const index =  lazyTreeNodeMap[key]?.findIndex((item:{id:string|number;parentId:string|number;})=>item.id == node.parentId);
                    console.log('index',index);
                    if(index !== -1){

                        parentId = key;
                        break;
                    }
                }
            }
            // 父节点下的子节点
            if(parentId){

                const data:any[] = await loadChildrenNodesHandler(parentId);
                if(data && data.length > 0){ // 子节点不为空,刷新父节点下的子节点信息
                    (tableStore.states as { lazyTreeNodeMap: { value: {[key:string|number]:any[];} };}).lazyTreeNodeMap.value[parentId] = data;
                }else { // 子节点为空,删除父节点下的子节点信息
                    delete (tableStore.states as { lazyTreeNodeMap: { value: {[key:string|number]:any[];} };}).lazyTreeNodeMap.value[parentId];
                }

            }
        }

        //移动节点到最顶级
        if(node.sourceParentId){
            const data = await loadChildrenNodesHandler(node.sourceParentId);

            if(data && data.length > 0){ // 子节点不为空,那么需要刷新父节点下的子节点信息
                (tableStore.states as { lazyTreeNodeMap: { value: {[key:string|number]:any[];} };}).lazyTreeNodeMap.value[node.sourceParentId] = data;
            }else { // 子节点为空,那么需要删除父节点
                delete (tableStore.states as { lazyTreeNodeMap: { value: {[key:string|number]:any[];} };}).lazyTreeNodeMap.value[node.sourceParentId];
            }


        }


    }

ps:这里我的数据结构里面,关于是否是顶级节点的判定就是parentId是否存在,如果存在parentId那么这个节点就不是顶级节点。大家可以根据自己的数据结构去调整这一段代码对于顶级节点的判断依据。

2.2 移动节点的方法的用法

2.2.1 打开抽屉时(设置sourceParentId (因为这里可能会变更表单中的parentId【移动节点】),因此这里需要记录一下旧的parentId是多少,方便后面同时更新该节点所在的旧的父节点和新的父节点)

async function handleUpdateOperate(row:any){
  
  const entity = JSON.parse(JSON.stringify(row));
  entity.sourceParentId = row.parentId;
  saveOrUpdateDataFormDrawerRef.value.data = entity;
  saveOrUpdateDataFormDrawerRef.value.title = '修改菜单';
  saveOrUpdateDataFormDrawerRef.value.show = true;
}

2.2.2 提交表单时

async function handleSaveOrUpdate(){
	//解除响应式对象
	const sourceMenuData = JSON.parse(JSON.stringify(saveOrUpdateDataFormDrawerRef.value.data));
	//调用接口发送请求保存或修改节点
	const result = await dataApi.saveOrUpdate(saveOrUpdateDataFormDrawerRef.value.data);
	//判断请求是否成功,如果成功了再执行刷新节点的操作
	if(result && result.code === 200){
		await tableHook.refreshTreeTableColumnNode(elTableRef.value,sourceMenuData,(parentId)=>{
        return new Promise<any[]>((resolve, reject)=>{
          dataApi.loadChildrenNodes(parentId).then((result)=>{
            resolve(result.data || []);
          });
        })
      });
	 //刷新分页
      await handlePaging();
      //关闭修改或保存抽屉
      saveOrUpdateDataFormDrawerRef.value.show = false;
	}
}

2.3 删除节点

 deleteTreeTableColumNode(elTableRef: TableInstance, node: { id?: string | number; parentId?: string | number }):void {
        let tableStore = elTableRef.store;
        // 处理删除顶级节点,删除非顶级节点的情况
        if(!node.parentId){ // parentId不存在,或===null表示为顶级节点
            let parentNodes = tableStore.states.data.value;
            const index = parentNodes.findIndex((item:any) =>node.id == item.id);
            if(index !== -1){
                parentNodes.splice(index,1);
            }

        }else {
            // 处理删除子节点
            let childrenNodes =  (tableStore.states as { lazyTreeNodeMap: { value: {[key:string|number]:any[];} };}).lazyTreeNodeMap?.value[node.parentId];
            const index = childrenNodes.findIndex((item:any) =>node.id == item.id);
            if(index !== -1){
                childrenNodes.splice(index,1);
            }
        }
    }

2.4 删除节点的方法的用法

//row是表格行内具体的被操作了某一行的数据对象
async function handleDelete(row:any){
 //发送请求删除某个节点
  const result = await dataApi.delete(row.id||'');
  //判断请求是否成功
  if(result && result.code === 200){
    ElMessage.success('删除成功');
    //操作删除节点
    tableHook.deleteTreeTableColumNode(elTableRef,row as { id: string|number;parentId?: string|number;});
    //刷新分页数据
    await handlePaging();
  }

}

以上就是我关于“Element-Plus+Vue3+TS的关于El-Table组件树形结构懒加载的节点增、删、改、查发送异步请求实时刷新节点”的具体实践,欢迎留言讨论~

当然,我会用 TypeScriptElement Plus树形表格来编写这个组件。以下是一个简单的示例代码,用于展示如何设置 Table 的 lazy 属性为 true,并使用加载函数 load 来实现三级以上的树形表格展开: ```typescript <template> <el-table :data="treeData" :lazy="true" :load="load" :tree-props="{children: &#39;children&#39;, hasChildren: &#39;hasChildren&#39;}"> <el-table-column type="expand"> <template #default="{row}"> <p v-if="row.content">{{ row.content }}</p> <p v-else>暂无内容</p> </template> </el-table-column> <el-table-column prop="name" label="名称"></el-table-column> <el-table-column prop="age" label="年龄"></el-table-column> </el-table> </template> <script lang="ts"> import { defineComponent, ref } from &#39;vue&#39;; import { ElTable, ElTableColumn } from &#39;element-plus&#39;; import { TreeNode } from &#39;element-plus/lib/el-tree&#39;; interface TreeData { name: string; age: number; content?: string; children?: TreeData[]; hasChildren?: boolean; } export default defineComponent({ name: &#39;TreeTable&#39;, components: { ElTable, ElTableColumn, }, setup() { const treeData = ref<TreeData[]>([ { name: &#39;张三&#39;, age: 20, content: &#39;这是张三的介绍&#39;, hasChildren: true, children: [ { name: &#39;李四&#39;, age: 18, content: &#39;这是李四的介绍&#39;, hasChildren: true, children: [ { name: &#39;王五&#39;, age: 22, content: &#39;这是王五的介绍&#39;, hasChildren: false, }, ], }, ], }, ]); const load = async (node: TreeNode<TreeData>) => { if (node.level >= 2) { return; } if (node.data?.children) { node.data.children = []; } for (let i = 0; i < 3; i++) { node.data?.children?.push({ name: &#39;新节点&#39;, age: Math.floor(Math.random() * 100) + 1, hasChildren: node.level < 2, }); } }; return { treeData, load, }; }, }); </script> ``` 这个组件包含一个树形表格,每个节点都可以展开和关闭。当需要展开一个节点时,会调用加载函数 load,该函数会异步加载节点的子节点。如果节点已经有子节点,则不会触发加载函数。在本例中,我们已经设置了 lazy 属性为 true,并将 load 函数传递给了表格。在 load 函数中,我们检节点的层级是否超过三级。如果节点层级已经超过三级,则不会加载子节点。否则,我们将生成三个随机子节点,并将它们添加到节点的 children 属性中。 注意,我们还需要将 TreeData 接口定义为一个 TypeScript 接口,以便在代码中使用。在本例中,TreeData 接口定义了树形表格中每个节点的数据结构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值