BasicTree懒加载模式下,节点增删改后动态刷新
jeecgboot在antv树控件基础删封装了BasicTree,懒加载模式下,节点增删改后动态刷新
起源
使用jeecgboot开发一个左树右表的页面,树和列表都需要增删改的功能,树采用懒加载模式,在生成的代码基础上改造。
先说问题
- 问题一(直接问题):树节点增、删、改后,怎样动态刷新
- 问题二(间接问题,要填坑):展开节点时出现浏览器卡死、无响应的情况
问题一解题
解题思路和过程
编辑(含删除、添加,下文统称编辑)节点后,重新加载当前节点所在的层级,并展开一展开的节点
在编辑成功的success回调里,调用updateNodeByKey方法可更新节点数据:
tree.updateNodeByKey(key, { children: records });
调用后编辑的节点更新了,但是这个节点的子节点(如果有子节点,并且是展开过的)没了,变成了leaf状态
原因:antv判断是否有子节点用的isLeaf属性,而jeecgboot封装的basicTree用的是hasChild属性。不知道是封装没处理好还是我哪里没写对,通过编辑回调的时候就会变leaf,但是展开的时候又正常
解决方法:在编辑回调的时候手动给数据增加isLeaf属性
let records = res.records;
for (let i = 0; i < records.length; i++) {
if (records[i].hasChild == '1') records[i].isLeaf = false;
}
这时候可以正常判断leaf了。但节点下的数据没了
- antv使用expandedKeys保存已展开的节点
- loadedKeys保存已“展开过”的节点
节点展开过,antv在loadedKeys保存了这些key,再次展开会从缓存数据读取。但更新过节点数据,缓存里没有children,所以出现这种情况。
处理方法就是重新加载的时候在loadedKeys里删除涉及的key
(部分关键代码)
//BasicTree的属性绑定loadedKeys
<BasicTree
...
:loadedKeys="loadedKeys"
///
/>
//定义loadedKeys变量
let loadedKeys = ref<any[]>([]);
//加载的时候删除key
loadedKeys.value.splice(0, 1, parId);
至此,理论上应该解决问题了。但是出现了新问题,也就是前面提到的“问题二”
问题二,展开节点时出现浏览器卡死、无响应的情况
现象:展开节点,页面卡死,无响应。如果在展开节点事件的方法打了console.log,可以看到控制台在疯狂输出。
解决:应该是展开时没有更新loadedKeys,导致antv认为还没展开。所以把展开的key加入到loadedKeys即可:
loadedKeys.value = uniq([...loadedKeys.value, parId]);
最后贴上代码
加载树节点代码(这里要返回Promise对象)
function loadChildDataByTreeNode(treeNode) {
return new Promise((resolve) => {
if (treeNode.dataRef.children) {
resolve(true);
return;
}
let parId = treeNode.dataRef.id;
let param = {
parId: treeNode.dataRef.id,
};
loading.value = true;
getChildList(param)
.then((res) => {
if (!Array.isArray(res.records) || res.records.length == 0) {
loadedKeys.value = uniq([...loadedKeys.value, parId]);
resolve(true);
return false;
}
let records = res.records;
for (let i = 0; i < records.length; i++) {
if (records[i].hasChild == '1') records[i].isLeaf = false;
}
let tree = getTree();
tree.updateNodeByKey(treeNode.eventKey, { children: records });
tree.setExpandedKeys(uniq([treeNode.eventKey, ...tree.getExpandedKeys()]));
resolve(true);
})
.finally(() => (loading.value = false));
});
}
编辑后动态刷新代码
async function loadChildDataByParId(parId) {
loading.value = true;
let param = {
parId: parId,
};
const res = await getChildList(param);
if (!Array.isArray(res.records)) {
return;
}
let records = res.records;
for (let i = 0; i < records.length; i++) {
if (records[i].hasChild == '1') records[i].isLeaf = false;
}
let tree = getTree();
//处理loadedKeys
loadedKeys.value.splice(0, 1, parId);
tree.updateNodeByKey(parId, { children: records });
tree.setExpandedKeys(uniq([parId, ...tree.getExpandedKeys()]));
loading.value = false;
}
补充代码getTree()
const asyncTreeRef = ref<Nullable<TreeActionType>>(null);
function getTree() {
const tree = unref(asyncTreeRef);
if (!tree) {
throw new Error('tree is null!');
}
return tree;
}
<BasicTree
<!--其他部分省略-->
ref="asyncTreeRef"
/>
最后
大家如果有其他思路,欢迎交流