<template>
<!-- 该下拉树形组件同时支持单选与多选 -->
<!-- select内展示被选中数据modelValueLabel,单选为对象类型,多选为数组类型 -->
<!-- 单选:{label:'',id:''},多选:[{label:'',id:''},{label:'',id:''}] -->
<!-- select内value-key绑定的值必须与tree内node-key绑定的值为同一值,且在数据中唯一 -->
<div>
<el-select
v-model="modelValueLabel"
:filter-method="selectFilterMethod"
style="min-width: 180px"
:size="size"
:value-key="valueKey"
ref="selectTree"
fit-input-width
:multiple="!isSingleChoice"
:placeholder="placeholderText"
:filterable="isFilter"
:collapse-tags="isTag"
@change="selectChangeMethod"
@visible-change="visibleChange"
>
<el-option
v-for="item in optionList"
:value="item"
:label="item.label"
:key="item[valueKey]"
style="height: 0"
>
</el-option>
<el-option style="height: auto; padding: 0" key="option2" value="option2">
<el-tree
:data="treeData"
:default-expand-all="isDefaultAll"
:expand-on-click-node="true"
:filter-node-method="filterNode"
:show-checkbox="!isSingleChoice"
:node-key="valueKey"
ref="tree"
highlight-current
:props="defaultProps"
@node-click="nodeClick"
@check-change="checkChange"
>
</el-tree>
</el-option>
</el-select>
</div>
</template>
<script>
export default {
name: "MetaSelectTree",
props: {
// 回显数据,单选值为对象,多选为数组
// 单选:{label:'',id:''},多选:[{label:'',id:''},{label:'',id:''}]
echoData: {
type: [Array, Object],
default: null,
},
// 是否开启搜索
isFilter: {
default: true,
},
// 尺寸
size: {
default: "default",
},
placeholderText: {
default: "请选择...",
},
// 多选时是否将选中值按文字的形式展示
isTag: {
default: true,
},
// 是否默认展开所有节点
isDefaultAll: {
default: true,
},
isCheckParent: {
default: false,
},
// 点击节点是否展开
expandClickNode: {
default: false,
},
// 绑定数据的唯一标识所使用的key
valueKey: {
type: String,
default: "id",
},
// 树形结构渲染数据
treeData: {
default: [],
},
// 遍历时字段格式化
defaultProps: {
default: {
children: "children",
label: "label",
},
},
// 是否单选
isSingleChoice: {
default: true,
},
},
data() {
return {
// 实际选中值
modelValue: [],
// 实际选中值的id
arrId: [],
// 下拉框绑定值
modelValueLabel: [],
optionList: [],
};
},
watch: {
treeData(data) {
// 对树形数据增加监听,确保option可被正常创建
if (data && data.length) {
this.optionList = this.getOptionList(this.treeData);
}
},
},
mounted() {
if (this.echoData) {
let echoData = this.echoData;
let valueKey = this.valueKey;
if (this.isSingleChoice) {
this.modelValue = [echoData];
this.modelValueLabel = echoData;
this.arrId = [echoData[valueKey]];
} else if (echoData.length > 0) {
this.modelValue = echoData;
this.modelValueLabel = echoData;
let arrId = [];
echoData.forEach((item) => {
arrId.push(item[valueKey]);
});
this.arrId = arrId;
this.$nextTick(() => {
this.$refs.selectTree.setCheckedKeys(arrId);
});
}
}
},
methods: {
getOptionList(treeData, optionList = []) {
// 递归树形数据,获取所有叶子节点,组成一维数组,作为渲染option的数据。
// 请注意!该处不可省略,因该组件支持多选模式,
// select回显数据配置的为对象数组,必须有相匹配的option才可显示正常
if (treeData.length) {
treeData.forEach((item) => {
if (item.children && item.children.length) {
this.getOptionList(item.children, optionList);
} else {
optionList.push(item);
}
});
return optionList;
}
return [];
},
visibleChange(bool) {
if (bool) {
this.selectFilterMethod("");
}
},
selectFilterMethod(val) {
// 下拉框调用tree树筛选
this.$refs.tree.filter(val);
},
selectChangeMethod(data) {
// 下拉多选内从展示的被选中数据中删除被选中内容
let arrNew = [];
let arrId = [];
data.forEach((item) => {
arrNew.push(item);
arrId.push(item[this.valueKey]);
});
this.modelValue = arrNew;
this.arrId = arrId;
// 设置勾选的值
this.$refs.tree.setCheckedNodes(arrNew);
this.$emit("input", arrId);
},
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
nodeClick(data, node) {
// 树形结构点击节点
let valueKey = this.valueKey;
if (this.isSingleChoice) {
// 单选
if (this.isCheckParent) {
// 允许选中父节点
this.modelValueLabel = data;
this.modelValue = [];
this.arrId = [];
this.modelValue.push(data);
this.arrId.push(data[valueKey]);
this.$emit("input", this.arrId);
this.$emit("nodeClick", this.arrId);
this.$refs.selectTree.blur();
} else if (node.childNodes.length == 0) {
// 选中的是末级节点
this.modelValueLabel = data;
this.modelValue = [];
this.arrId = [];
this.modelValue.push(data);
this.arrId.push(data[valueKey]);
this.$emit("callId", data[valueKey]); // 直接返回字符串
this.$emit("callItem", data); // 直接返回选中对象
this.$emit("input", this.arrId); // 直接返回选中id
this.$refs.selectTree.blur();
}
}
},
checkChange(node, checkedType) {
// 树形结构CheckBox勾选与取消
// this.modelValue内部存储的数据顺序完全遵循勾选的顺序
let nodeInDataIndex = -1;
if (node.children && node.children.length) {
// 当前节点有孩子节点,不是末端的叶子节点
} else {
if (checkedType) {
// 当前节点被选中
nodeInDataIndex = this.nodeInDataIndex(this.modelValue, node);
if (nodeInDataIndex == -1) {
// 该节点未被保存过
this.modelValue.push(node);
this.arrId.push(node[this.valueKey]);
}
} else {
// 当前节点被取消选中
nodeInDataIndex = this.nodeInDataIndex(this.modelValue, node);
if (nodeInDataIndex > -1) {
// 该节点被保存过
this.modelValue.splice(nodeInDataIndex, 1);
this.arrId.splice(nodeInDataIndex, 1);
}
}
this.modelValueLabel = this.modelValue;
this.$emit("input", this.arrId);
}
},
nodeInDataIndex(data, node, key = this.valueKey) {
if (data && data.length && node) {
let dataLen = data.length;
let nodeInDataIndex = -1;
for (let i = 0; i < dataLen; i++) {
if (data[i][key] == node[key]) {
nodeInDataIndex = i;
break;
}
}
return nodeInDataIndex;
}
return -1;
},
},
};
</script>
<style lang="scss" scoped>
</style>
VUE3+Element+下拉树形多选组件
最新推荐文章于 2024-09-14 08:06:34 发布