el-tree懒加载回显数据
前几天一个月薪35k的兄弟,给我推了一个人工智能学习网站,看了一段时间挺有意思的。包括语音识别、机器翻译等从基础到实战都有,很详细,分享给大家。
描述
懒加载回显,需要两个数据
1、你展开的节点key数组
2、你勾选的节点key数组
- key可以是id,这个在el-tree绑定
- 将这两个数据在保存的时候传给后端
- 点击编辑时,让后端返回对应的这两个数据
- 通过default-checked-keys回显勾选
- 通过default-expanded-keys回显展开过的节点
效果
dom
<el-tree
ref="tree"
:data="treeData"
:load="loadnode"
:lazy="isLazy"
check-on-click-node
check-strictly
:props="defaultProps"
show-checkbox
node-key="nodeId"
@node-expand="keepExpandedNode"
@check-change="hChangeTree"
@check="handleCheckChange"
:default-expanded-keys="defaultExpandedNodes"
:default-checked-keys="defaultCheckedNodes"
></el-tree>
保存展开过的节点数组,保存选中的节点数组
//保存展开过的节点
keepExpandedNode(nodeData, node, tree) {
let newFlag = this.expandedNodes.every(item => {
return item.nodeId !== nodeData.nodeId
});
if (newFlag && !nodeData.isLeaf) {
this.expandedNodes.push(this.cloneObj(nodeData))
}
},
//点击多选框->整理已选选项并保存
handleCheckChange(node, tree) {
let list = this.cloneObj(tree.checkedNodes); //tree.checkedNodes-未展开过的节点的子节点无法获取到
list = list.filter(mItem => {
return this.expandedNodes.every(item => {
return item.nodeId !== mItem.nodeId
})
});
this.value = list;
},
//深度复制对象
cloneObj(obj) {
let newObj = {};
if (typeof obj === "object") {
if (obj instanceof Array) {
newObj = [];
}
for (var key in obj) {
let val = obj[key];
newObj[key] =
typeof val === "object" ? this.cloneObj(val) : val;
}
return newObj;
} else {
return obj;
}
},
data
data() {
return {
expandedNodes: [], // 已经展开过的节点(拿到过下级的节点)
value: [], // 已选节点
defaultCheckedNodes: [], // 最终要回显的勾选key数组
defaultExpandedNodes: [], // 最终要回显的展开过的key数组
openList: [], // 后端返回的展开节点数据(需要处理成key数组)
choliceList: [], // 后端返回的勾选节点数据(需要处理成key数组)
meaningExpandedNum: 0, // 标的
}
}
watch里监听
(非必需,我这里是因为后端返回数据结构问题,所以需要转化)
expandArr: {
handler(newV, oldV) {
if(newV){
this.$nextTick(() => {
this.openList = newV.split(',')
// console.log(this.openList);
})
// console.log(this.defaultExpandedNodes);
}
},
immediate: true,
},
selectArr: {
handler(newV, oldV) {
if(newV){
this.$nextTick(() => {
this.choliceList = newV.split(',')
})
// console.log(this.defaultCheckedNodes);
}
},
immediate: true,
},
回显
async gettreeData(i, p, search) { // 获取tree数据
const res = await getTreeData({
level: i,
parentId: p,
});
if(i == 1){
this.firstTreeData = res.data.content
}
return res.data.content;
},
async loadnode(node, resolve) { // tree懒加载
if (node.level == 0) {
/// 如果需要多次回填,该初始化必需
this.meaningExpandedNum = 0;
this.defaultCheckedNodes = [];
/// 回填展开节点
this.$nextTick(()=>{
this.defaultExpandedNodes = this.openList
})
setTimeout(async() => {
let list = await this.gettreeData(1, "root");
resolve(list);
/// 注意回填要在树渲染后才生效
this.$nextTick(() => {
/// 没展开过节点,则直接在根节点层级回填
if (0 === this.defaultExpandedNodes.length) {
this.defaultCheckedNodes = this.choliceList.map(item => {
return item
});
}
});
},500)
} else {
let search = this.searchVal;
this.gettreeData(node.level + 1, node.data.nodeId,).then(
(res) => {
if (res) {
setTimeout(() => {
resolve(res);
/// 已选节点变成展开节点时、选值自动替换为下层节点;这是为了下次回填做的准备,回填过程中用不到
if(node.checked){
let list = this.$refs.tree.getCheckedNodes();
list = list.filter(mItem => {
return this.expandedNodes.every(item => {
return item.nodeId !== mItem.nodeId
})
})
this.value = list;
}
/// 回填时保证在全部渲染后再回填
this.meaningExpandedNum++;
if (this.meaningExpandedNum === this.defaultExpandedNodes.length) {
/// 回填复选框
this.defaultCheckedNodes = this.choliceList
}
}, 200);
} else {
return resolve([]);
}
}
);
}
},
保存时将展开过的节点和勾选过的节点传给后端
我这里是因为组件封装有些多,所以需要将数据保存到vuex,最后再传给后端。
async hChangeTree(node) {
let cholice = this.$refs.tree.getCheckedNodes()
let choliceArr = [];
cholice.forEach((item)=>{
choliceArr.push(item.entityId)
})
// console.log(choliceArr);
this.$store.commit("uploadCholiceNodeG",choliceArr)
// 保存展开tree节点和勾选tree节点数据
}
遇到问题
懒加载回显,获取节点时,同时调用好几个接口,造成先padding,后500的bug