**问题:
项目需求是 级联选择器懒加载, 并且级联选择器有单选的回显和多选的回显, 一开始 单选还觉得挺容易, 但是多选 就 花了些时间研究才做出了.特地记录一下,因为没有看到讲的比较清楚的**
单选的回显:
注意点:
(1) 单选回显只需要绑定 回显的 id 即可, 会自动根据id发起异步请求
(2) 回显id 要是 一条链, 就是 当前节点di和这个节点所有父级id, 一个数组,如[‘1’,‘2’]
(3) 要触发自动发起异步请求, 需要第一次懒加载中是异步获取数据
(4) 不需要绑定 options 给级联选择器
(5) 手动添加了children属性, 添加过程也会触发懒加载,导致子级数据重复, 这时我们要判断 如有 chidlren属性了就不要进行加载哦.
栗子代码:
xx.vue文件,自行复制测试哈, 关键代码就懒加载那里, 其他是模拟数据.关键代码复制使用就行了,请求方法换成自己的.
先看效果:
<!--
* @Author: wuwle
* @Date: 2020-09-06 23:07:05
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-10-09 19:22:23
* @FilePath: \demo\vue\vue基础\vue-cli\pro_02\src\views\About.vue
-->
<template>
<div class="home">
<el-cascader
:props="props"
clearable
v-model="list"
ref="cdd"
></el-cascader>
{{ list }}
</div>
</template>
<script>
export default {
data() {
return {
list: ["2", "5"], // 回显的id
// list: [],
props: {
// multiple: true,
checkStrictly: true, // 父子不想关联
// emitPath: false,
lazy: true,
lazyLoad: this.lazyLoads,
},
};
},
methods: {
// 懒加载
async lazyLoads(node, resolve) {
if (node.level == 0) {
let res = await this.getfristChild(); // 不存在就默认加载第一集节点
resolve(res);
} else {
// 有children属性了就不要再请求了,不然字节点会重复
if (!node.data.children) {
// 获取子节点数据
let res = await this.getOther(node.data.value);
setTimeout(() => {
resolve(res);
}, 200);
} else {
resolve([]);
}
}
},
// 模拟请求一级节点
async getfristChild() {
return [
{
label: "第一个",
hasChdild: true,
pid: null,
value: "1",
},
{
label: "第2个",
hasChdild: true,
pid: null,
value: "2",
},
{
label: "第3个",
hasChdild: true,
pid: null,
value: "3",
},
];
},
// 模拟请求子级节点
async getOther(value) {
let res = [];
if (value == 1) {
res = [
{
label: "第一个1",
hasChdild: false,
pid: 1,
value: "3",
},
{
label: "第一个2",
hasChdild: false,
pid: 1,
value: "4",
},
];
}
if (value == 2) {
res = [
{
label: "第2个1",
hasChdild: false,
pid: 2,
value: "5",
},
{
label: "第2个2",
hasChdild: false,
pid: 2,
value: "6",
},
];
}
return res;
},
},
};
</script>
多选的回显:
注意点:
(1) 多选要绑定 options 给级联选择器 作为第一次的数据
(2) 回显id 要是 一条链, 就是 当前节点di和这个节点所有父级id, 一个二维数组,如[‘1’,[‘2’,‘5’]]
(3) 实现原理是:
懒加载数据是通过children属性添加的,也就是一般我们获取了一级数据, 点击一级数据懒加载子级数据, 子级数据加载回来是放在一级数据的children属性下的, 那么, 我们为了回显, 我们第一次就手动根据 回显 id 拿 子级数据,添加到chdilren属性下,这样就可以回显了
(4) 当回显后去点击有子级数据的懒加载时, 会发现懒加载后 回显内容丢失, 这时要在懒加载时记录加载器回显id, 加载后还原回来.
(5) 手动添加了children属性, 添加过程也会触发懒加载,导致子级数据重复, 这时我们要判断 如有 chidlren属性了就不要进行加载哦.
栗子代码:
xx.vue文件,自行复制测试哈, 关键代码就懒加载那里, 其他是模拟数据.关键代码复制使用就行了,请求方法换成自己的.
先看效果:
2021-11-17更新
根据评论反馈设置父子节点相关联就会回显失败,经过测试,确实是,目前已经更新,通用了,改动不大,主要加了叶子节点判断,整体思路一样的。
<!--
* @Author: wuwle
* @Date: 2020-09-06 23:07:05
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-10-09 19:36:36
* @FilePath: \demo\vue\vue基础\vue-cli\pro_02\src\views\About.vue
-->
<template>
<div class="home">
<el-cascader :props="props"
clearable
v-model="list"
ref="cdd"
:options="optionsList"></el-cascader>
回显id:{{list}}
</div>
</template>
<script>
export default {
data() {
return {
list: [["1", "11", "111"], ["3"]], // 回显id, 要求是真个节点链, 父级id都要有
// list: [],
props: {
multiple: true,
checkStrictly: true, // 父子相关联
// emitPath: false,
lazy: true,
lazyLoad: this.lazyLoads,
leaf: "leaf", // 需要指定叶子节点,不然显示有问题
},
optionsList: [],
isShow: false,
};
},
mounted() {},
methods: {
async lazyLoads(node, resolve) {
console.log(node);
if (node.level == 0) {
if (this.list.length > 0) {
// 存在回显的id我们才去设置回显
let res = await this.format(); // 这里就是获取第一次要回显的内容了
console.log("00000", res);
this.optionsList = res; // 有回显第一次就直接给绑定的对象,不要resolve
} else {
let res = await this.getfristChild(); // 不存在就默认加载第一集节点
resolve(res);
}
} else {
// 记录选择的,不然会点击字节点加载时丢失数据
let list = this.list;
// 有children属性了就不要再请求了,不然字节点会重复
if (!node.data.children) {
// 获取子节点数据
let res = await this.getOther(node.data.value);
setTimeout(() => {
// 模拟延时,实际不需要
resolve(res);
}, 100);
} else {
resolve([]);
}
// 重新把选择的id放回来-
// this.$nextTick(() => {
// this.list = [...new Set([...this.list, ...list])]; //差别: 合并并且去重
// });
setTimeout(() => {
this.list = [...new Set([...this.list, ...list])]; //差别: 合并并且去重
}, 250);
}
},
// 模拟请求一级节点
async getfristChild() {
return [
{
label: "第一个",
hasChdild: true,
leaf: false,
pid: null,
value: "1",
},
{
label: "第2个",
hasChdild: true,
leaf: false,
pid: null,
value: "2",
},
{
label: "第3个",
hasChdild: true,
leaf: true,
pid: null,
value: "3",
},
];
},
// 模拟请求子级节点
async getOther(value) {
let res = [];
if (value == 1) {
res = [
{
label: "第一个1",
hasChdild: false,
pid: 1,
value: "11",
leaf: false, // 差别: 这里加了是否叶子节点属性,后面都加了
},
{
label: "第一个2",
hasChdild: false,
pid: 1,
value: "12",
leaf: false,
},
];
}
if (value == 2) {
res = [
{
label: "第2个1",
hasChdild: false,
pid: 2,
leaf: true,
value: "5",
},
{
label: "第2个2",
hasChdild: false,
leaf: true,
pid: 2,
value: "6",
},
];
}
if (value == 11) {
res = [
{
label: "第3个1",
hasChdild: false,
pid: 2,
leaf: true,
value: "111",
},
{
label: "第3个2",
hasChdild: false,
leaf: true,
pid: 2,
value: "112",
},
];
}
return res;
},
// 这个方法不变哦
// 根据回显的id获取 第一次的数据, id必须是 一条链, 就是当前节点到此节点的一级节点的整条链 id 都要有
async format() {
let res = await this.getfristChild(); // 拿一级数据
this.list.forEach((item) => {
// 遍历回显的id 二维数组
if (item.length > 1) {
item.forEach(async (sitem, index) => {
if (index == item.length - 1) {
return; // 如果是一级节点就不用查找了
}
let arr = await this.getOther(sitem); // 不是一级,获取子级
findItem(res, arr, sitem); // 判断当前拿到的子级数据属于哪个一级数据下的子级,并且加到当前一级的children属性下
});
}
});
// 递归判断
function findItem(res, arr, id) {
for (let i = 0; i < res.length; i++) {
if (res[i].value === id) {
res[i].children = arr; // 有chidlren 也要判断是不是这个children下的子级
return res;
}
if (res[i].children) {
findItem(res[i].children, arr, id);
}
}
}
return res;
},
},
};
</script>
有问题评论哈