antd tree 懒加载+局部刷新
针对懒加载的树组件,节点数据发生变化后,只刷新局部数据,拿到最新的节点
思路
antd tree提供的loadData属性,支持传入一个方法,用于异步加载子节点的数据。当某一节点的数据已经加载之后,收起节点再次展开是不会触发异步加载的方法的,因此节点数据不会刷新。需要我们手动变更一些值才能触发该方法。
首先要明确树组件触发懒加载的前提条件:
1. expandedKeys包含节点key值
2. loadedKeys不包含需要刷新的节点的key值,即此前未曾加载过
3. treeData中不包含该节点的children数据,即children=[]
只有以上三点同时满足,才会触发loadData方法。
方法
A节点下新增子节点后,刷新A节点的子节点需要3步:
注意:A节点的所有子孙节点均需要回到收起状态,否则会多次调用接口加载已展开的节点数据
- 1. loadedKeys中移除A节点的key值和其子孙节点的key值
- 2. treeData中将A节点的children赋空
- 3. expandedKeys中移除A节点下的所有子孙节点的key值
代码:
// 获取当前节点id以及下面所有子孙节点的id
getNodeAndChildrenIds (data) {
let temp = [];
const loop = (data) => {
data.map(item => {
temp.push(item.id)
if (item.children && item.children.length) {
loop(item.children);
}
})
}
loop(data);
return temp;
},
// 更新树组件的数据
updateTreeData(id) {
const temp = _.cloneDeep(this.treeData);
let node;
const loopFn = (data, id) => {
if (node) {
return;
}
data.some((item) => {
if (item.id === id) {
node = _.cloneDeep(item.children);
item.children = [];
return true;
}
if (item.children && item.children.length) {
loopFn(item.children, id);
}
});
};
// 获取A节点的子节点,并把A节点的children移除
loopFn(temp, id);
this.treeData = _.cloneDeep(temp);
// 获取A节点下面所有子孙节点的id
const nodeIds = this.getNodeAndChildrenIds(node);
// loadedKeys中移除A节点的key
let loadedKeys = _.cloneDeep(this.loadedKeys.filter(item => item !== id));
// 去掉A下面已加载的子孙节点的key
loadedKeys = _.cloneDeep(loadedKeys.filter(item => !nodeIds.includes(item)));
this.loadedKeys = _.cloneDeep(loadedKeys);
// 去掉A下面已展开的子孙节点id
this.expandedKeys = _.cloneDeep(this.expandedKeys.filter(item =>
!nodeIds.includes(item)));
}
以上是刷新子节点的方法。
当A节点本身发生变更或删除时,则需要刷新A节点的数据,此时同样可以通过上面的方法。但是这里推荐另一种方式,即手动更新数据,不走接口,这种方式更为简单。
代码:
/** 找到对应的节点执行某操作 */
treeAction (node, id, fn) {
node.some((item,index) => {
if (item.id === id) {
fn(node, item, index)
return true;
}
if (item.children && item.children.length) {
treeAction(item.children, id, fn);
}
});
},
// 删除树节点
async deleteTreeNode(data) {
await api.deleteFn(data.id);
this.$message.success('删除成功!');
// 手动删除A节点和其子孙节点
treeAction(this.treeData, data.id, (node, item, index) => {
node.splice(index, 1);
});
},
// 重命名树节点
async editTreeNode(data, form) {
const params = {
...
};
await api.editFn(params);
this.$message.success('重命名成功!');
// 手动重置A节点名称
treeAction(this.treeData, data.id, (node, item, index) => {
item.name = form.name;
});
},