el-cascader懒加载+多选+回显+远程搜索(vue3+element plus)
el-cascader引用地址
<template>
<el-cascader v-model="dataVal"
:debounce="600"
:options="options"
:props="propsLazy" clearable
:teleported="false"
:filterable="false"
:before-filter="beforeFilter"
:filter-method="filterMethod"
@change="valChange" />
</template>
<script setup>
import { computed, nextTick, onMounted, reactive, ref, watch } from "vue";
let dataVal=ref([])
let options=ref([])
let optionsRaw=ref([])
let searchShow=ref(false)
const loadOptions = async (node, resolve) => {
if (node.value && !searchShow.value) {
const fetchedOptions = await getTypeData({ parent_id: node.value });
optionsRaw.value = setOptions(
node.pathValues,
optionsRaw.value,
0,
fetchedOptions
);
resolve(fetchedOptions);
}
resolve();
};
const propsLazy = {
checkStrictly: true,
lazy: true,
lazyLoad: loadOptions,
value: "id",
leaf: "leaf",
multiple: true,
checkStrictly: true,
};
const setOptions = (idArr, arr, num, addData) => {
for (let item of arr || []) {
if (item.id == idArr[num]) {
if (num == idArr.length - 1) {
item["children"] = JSON.parse(JSON.stringify(addData));
} else {
item = setOptions(idArr, item["children"], num + 1, addData);
}
break;
}
}
return arr;
};
const getDataOpen = async (val) => {
options.value = await getTypeData();
optionsRaw.value = JSON.parse(JSON.stringify(options.value));
dataVal.value=val
};
const getTypeData = async (param = {}) => {
let list = [];
await api.$getCategory(param).then((res) => {
if (res.Status == 0) {
list = getChildren(res.data || []);
}
});
return list;
};
const getChildren = (arrData) => {
if (arrData && arrData.length > 0) {
let data = arrData.map((el) => {
let obj = {
id: el.id,
label: el.label,
leaf: !(Number(el.child_num) > 0),
child_num: el.child_num,
};
if (el.children && el.children?.length > 0) {
obj["children"] = getChildren(el.children);
}
return obj;
});
return data;
} else {
return arrData;
}
};
const beforeFilter = async (val) => {
searchShow.value = true;
let obj = await getTypeData({search:val});
obj.map((item) => {
for (let el of optionsRaw.value) {
if (el.id == item.id) {
el = addItem(el, item);
return;
}
}
});
options.value = JSON.parse(JSON.stringify(optionsRaw.value));
};
const addItem = (goal = {}, obj = {}) => {
if (obj.children && obj.children.length > 0) {
if ((goal.children || []).length == 0) {
goal.children = JSON.parse(JSON.stringify(obj.children));
} else {
obj.children.map((item) => {
for (let el of goal.children) {
if (el.id == item.id) {
el = addItem(el, item);
return;
}
}
});
}
}
return goal;
};
const filterMethod = (node, val) => {
return node.label.toLowerCase().includes(val.toLowerCase());
};
const visibleChange = async (bool) => {
if (!bool) {
if (searchShow.value) {
searchShow.value = false;
}
}
};
const expandChange = (val) => {
let childArr = JSON.parse(JSON.stringify(optionsRaw.value));
val.forEach(async (el, index) => {
let res = getItem(el, childArr);
childArr = res.childArr;
if (index == val.length - 1) {
if (res.child_num > childArr.length) {
const fetchedOptions = await getTypeData({ parent_id: el });
options.value = setOptions( val, options.value, 0, fetchedOptions );
categoryOptionsRaw.value = JSON.parse(JSON.stringify(categoryOptions.value));
}
}
});
};
const getItem = (val, arr) => {
let childArr = [];
let child_num = 0;
for (let item of arr) {
if (val == item.id) {
childArr = JSON.parse(JSON.stringify(item.children || []));
child_num = item.child_num;
break;
}
}
return { childArr, child_num };
};
</script>