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组件树形结构懒加载的节点增、删、改、查发送异步请求实时刷新节点”的具体实践,欢迎留言讨论~