VUE + Element UI 树形 table 懒加载问题
这两天项目用到了 element ui 的树形结构做菜单,使用了懒加载机制,导致新增和删除菜单时无法正确加载菜单问题,网上文章找了一大圈,全是同样解决方法,记录一下投机取巧的解决方案:
直接上代码:
<template>
<el-table:data="dataList"
row-key="id"
lazy
:load="load"
node-key="id"
ref="tree"
:expand-on-click-node="true"
:tree-props="{children:'children', hasChildren:'hasChildren'}"
>
<!-- 列表主体 -->
<el-table-column>
<template slot-scope="scope">
<el-button @click="createChildren(scope.row,true)">添加下级
</el-button>
<el-button @click="deleteVerify(scope.row.id)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
createChild: '',
treeNodeMap: new Map()
}
},
methods: {
// 删除
deleteHandle (id) {
this.deleteHandle(id).then(({ data: res }) => {
// 刷新父级节点
this.refreshNode(this.deletePid)
}).catch(() => {})
},
// 添加下级
createChildren(row, unDown) {
// 这里只是保存一下当前行
this.createChild = row
},
createChildrenHandle: function (){
// 如果当前菜单不存在下级菜单则添加
// 这个是添加下级菜单时,如果当前菜单不存在下级菜单,需要将右边小三角加载出来,这个hasChildren 控制当前菜单是否存在下级菜单
// 不过这样加载其实也有一个问题,就是在刷新节点的时候,如果当前菜单没有点击 load 进行加载,则 treeNodeMap 中就没有缓存到节点信息(这个暂时不知道怎么解决),导致刷新节点无法获取到数据,
// 增加第一个子节点的时候无法自动展开
if (this.createChild.hasChildren !== true){
this.createChild.hasChildren = true
// 添加下级菜单并展开当前级别
this.refreshNode(this.createChild.id)
}
},
// 刷新节点
refreshNode:function (key) {
// 刷新节点是根据 id 获取节点数据,然后手动触发 load 事件
const node = this.treeNodeMap.get(key)
if (node === undefined){
return
}
// 获取需要刷新节点
const { row, treeNode, resolve } = node
// 重新展开节点
this.load(row, treeNode, resolve);
},
load(row, treeNode, resolve) {
// 缓存当前 Node **重要
this.treeNodeMap.set(row.id,{row,treeNode,resolve})
let myChild = [];
this.getChildren(id).then(({data: res}) => {
if (res.code == 0) {
myChild = res.data
// 当删除本级菜单下最后一个子菜单后,会遇到不会重新刷新菜单问题
// 这个 resolve 实现时判断myChild.length 是否有值,如果有值就会重新给父级菜单赋值并刷新页面,如果 myChild.length == 0 则不会刷新
// 这个地方只是投机取巧了
if (res.data.length === 0){
myChild.length = 1
}
}
resolve(myChild);
}).catch(() => {
});
},
}
}
</script>
效果:
添加下级:
展开:
删除唯一子节点:
需要注意的地方就是添加第一个,或者删除最后一个子节点时,需要处理一下父级菜单状态。
load(row, treeNode, resolve)
中 resolve 实现:
loadData: function loadData(row, key, treeNode) {
var _this = this;
var load = this.table.load;
var _states6 = this.states,
lazyTreeNodeMap = _states6.lazyTreeNodeMap,
treeData = _states6.treeData;
if (load && !treeData[key].loaded) {
treeData[key].loading = true;
load(row, treeNode, function (data) {
if (!Array.isArray(data)) {
throw new Error('[ElTable] data must be an array');
}
treeData[key].loading = false;
treeData[key].loaded = true;
treeData[key].expanded = true;
// 这里是判断当前节点是否重新加载子节点判断方式,
// 上边取巧给 data.length 赋了值,这个地方就能进入判断了, 注意,只是给 data.length = '1' 并不是真正的给 data 赋值
// 然后就会自动加载空数据
if (data.length) {
_this.$set(lazyTreeNodeMap, key, data);
}
_this.table.$emit('expand-change', row, true);
});
}
}
最后还是希望杜绝网络文章一大抄,哪怕自己写的不好也要自己多想多写!!