实现 select 中嵌套 tree 外加搜索
参考地址实现地址
代码
<el-form-item label="考核人员" prop="userIdArr" v-if="title == '发起考核'"><el-popover v-model="popoverVisible" placement="bottom" trigger="click" ref="popover">// click:点击select时弹出框显示// popover+tree用于选择,树形控件放在弹出框中<el-input class="input" placeholder="此处键入'关键词'搜索查询" prefix-icon="el-icon-search" v-model="treeFilter"size="mini" v-focus clearable /><!-- 通过 checkbox 进行选择,通过 checkChange 来进行保存值 --><el-tree :data="deptOptions" :props="defaultProps" show-checkbox @check="checkChange":default-checked-keys="this.form.userIdArr" ref="tree" node-key="iid" :filter-node-method="filterNode":default-expand-all="false" :style="`max-height: ${treeMaxHeight}px; overflow-y: auto;`" />// select展示选择结果,储存选择值typeValue<el-select slot="reference" multiple collapse-tags v-model="form.userIdArr" placeholder="请选择"popper-class="hiddenSel" clearable @clear="clearTag" @remove-tag="removeTag"><el-option v-for="item in typeOption" :key="item.iid" :label="item.label" :value="item.iid" /></el-select></el-popover>
</el-form-item>
data 数据
// 需把数据整理成以下结构
// tree数据(children的id第一位为父级id,用于在select中清除某一点,可找到其父级去掉全选)
deptOptions: [], // tree 的数据
typeOption: [], // select 选择框一维数据
defaultProps: {// tree 的显示类名children: "children",label: "label",
},
treeFilter: "", // 搜索框绑定值,用作过滤
// 选中数组ids: [],
methods 方法:
watch: {// 搜索过滤,监听input搜索框绑定的treeFiltertreeFilter(val) {this.$refs.tree.filter(val);// 当搜索框键入值改变时,将该值作为入参执行树形控件的过滤事件filterNode},
}
methods: {
// 发起考核// select 框部分/** 查询部门下拉树结构 */getDeptTree() {userTreeList().then((response) => {// 将数据 user 添加进 children,并且将字段名更改下this.deptOptions = this.copyAndRenameFieldsInArray(response.data);// 对数据进行添加 iidthis.deptOptions = this.addIid(this.deptOptions);// 处理好的数据 进行扁平化this.typeOption = this.flattenData(this.deptOptions);});},// 将部门tree进行扁平化flattenData(data) {const result = [];function flatten(item) {result.push({ id: item.id, label: item.label, iid: item.iid });if (item.children) {item.children.forEach((child) => {flatten(child);});}}data.forEach((item) => {flatten(item);});return result;},// 将 user 添加进 childrencopyAndRenameFieldsInArray(data) {data.forEach((node) => {if (node.users && node.users.length > 0) {node.children = node.children || [];// 将复制并重命名字段的数据拼接到 children 数组的最前面node.children.unshift(...node.users.map((user) => ({userId: user.userId,id: user.userId,userName: user.userName,label: user.nickName,deptId: user.deptId,nickName: user.nickName,})));node.users = [];}if (node.children && node.children.length > 0) {this.copyAndRenameFieldsInArray(node.children);}});return data;},// 加字段 iidaddIid(data, iidPrefix = "") {return data.map((item) => {const iid = iidPrefix + item.id;const newItem = { ...item, iid };if (item.children) {newItem.children = this.addIid(item.children, iid + "-");}return newItem;});},// tree选择值修改时checkChange() {this.form.userIdArr = [];// 将tree选择的id赋值给selectthis.$refs["tree"]?.getCheckedNodes(true).forEach((value) => {// 父级在select中不展示if (value.iid.indexOf("-") > 0) {this.form.userIdArr.push(value.iid);}});},// 模糊查询(搜索过滤),实质为筛选出树形控件中符合输入条件的选项,过滤掉其他选项filterNode(value, data) {if (!value) return true;let filterRes =data.label.toLowerCase().indexOf(value.toLowerCase()) !== -1;return filterRes;},// 清空selectclearTag() {// 清空tree选择this.$refs["tree"].setCheckedKeys([]);},// 从select中单个移除时,保持tree选择值同步移除removeTag(data) {// 获取tree目前选择的值var chooseData = this.$refs["tree"].getCheckedKeys(true);var deleteIndex = "";// 找到chooseData中与清除的data相同的值chooseData.forEach((value, index) => {if (value === data) {deleteIndex = index;}});// 从tree目前选择值中去掉chooseData.splice(deleteIndex, 1);// 若有全选情况,tree的选择值中有父级id,而select中无父级id,需用children的id找到父级id并去掉// 查找其父级id是否在chooseData中(即原来此父级是否全选),若在则去掉var findFatherData = chooseData.find((element) => element === data.split("-")[0]);if (findFatherData) {chooseData.splice(chooseData.indexOf(findFatherData), 1);}// 将修改后的值再赋给treethis.$refs["tree"].setCheckedKeys(chooseData);},// 时间戳转化为时间formatDate(dateString) {const date = new Date(dateString);const year = date.getFullYear();const month = ("0" + (date.getMonth() + 1)).slice(-2);const day = ("0" + date.getDate()).slice(-2);const hours = ("0" + date.getHours()).slice(-2);const minutes = ("0" + date.getMinutes()).slice(-2);const seconds = ("0" + date.getSeconds()).slice(-2);const formattedDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;return formattedDate;},
}