记录一下在Vue2中Element-ui没有树形组件的问题,感觉找的一些解决方案都没有实际解决我的问题
包含功能,树形单选,树形多选,树形关联父级多选,树形不关联父级多选
<template>
<Select ref="selectRef" :value="value" filterable :filter-method="setFilterKeyword" default-first-option clearable
collapse-tags v-bind="selectProps" @remove-tag="(value) => setCheckedKeys(value, { isRemove: true })"
@clear="handleClear" @visible-change="visibleChange">
<template #header>
<slot name="header" />
</template>
<template #content>
<div class="oper-tree-select">
<el-tree ref="treeRef" :data="options" :props="defaultProps" @node-click="selectChange" v-bind="treeProps"
:filter-node-method="filterNode" :expand-on-click-node="treeProps.expandOnClickNode"
:default-checked-keys="currentValue" :render-content="renderContent"
:node-key="treeProps.nodeKey || 'value'"></el-tree>
</div>
</template>
<template #footer>
<slot name="footer" />
</template>
</Select>
</template>
<script>
export default {
name: "TreeSelect",
model: { prop: "value", event: "update", },
props: {
value: {
type: [Array, String],
},
/**
* Select组件属性
*/
selectProps: {
type: Object,
},
/**
* Tree组件属性
*/
treeProps: {
type: Object,
},
/**
* 字段映射
*/
field: {
type: Object,
},
/**
* 排除父级在value的选中
*/
excludeParent: {
type: Boolean,
default: false,
},
/**
* 树形选项
*/
options: {
type: Array,
},
},
emits: ['change', 'update', 'clear'],
data() {
return {
cacheOptions: new Map(),
keyword: '',
}
},
mounted() {
this.$nextTick(() => {
this.setSelectOptions(true)
})
},
computed: {
currentValue() {
return Array.isArray(this.value) ? this.value ?? [] : [this.value]
},
select() {
return this.$refs.selectRef.$refs.selectRef
},
tree() {
return this.$refs.treeRef
},
defaultProps() {
return {
label: (data) => data.label || data.value,
value: 'value',
children: 'children',
...this.field
}
}
},
watch: {
value() {
setTimeout(() => {
this.setSelectOptions()
})
},
options() {
setTimeout(() => {
this.setSelectOptions()
})
}
},
methods: {
renderContent(h, { data, node }) {
const isSelected = this.cacheOptions.has(this.getValue(data, node))
return h('span', {
class: ['el-tree-node__label', { 'is-selected': isSelected }]
}, this.getLabel(data, node))
},
setFilterKeyword(keyword) {
this.keyword = keyword
this.$refs.treeRef.filter(keyword);
this.select.filteredOptionsCount = 1
},
filterNode(value, data, node) {
return this.getLabel(data, node).indexOf(value) !== -1;
},
visibleChange(status) {
if (!status && this.keyword != '') {
setTimeout(() => this.setFilterKeyword(''), 300)
}
},
getNodeValByProp(field) {
const prop = this.defaultProps[field]
return typeof prop === 'function' ? prop : (data) => data[prop]
},
getChildren(data) {
return data && this.getNodeValByProp('children')(data)
},
getLabel(data, node) {
return data && this.getNodeValByProp('label')(data, node)
},
getValue(data, node) {
return data && this.getNodeValByProp('value')(data, node)
},
updateValue(value) {
this.$emit('update', value)
this.$emit('change', value)
if (this.select) this.select.filteredOptionsCount = 1
},
setCheckedKeys(data, node) {
const toValue = (data) => this.getValue(data, node)
const value = node.isRemove ? data : toValue(data)
const { multiple = false } = this.selectProps ?? {}
let values = typeof this.value === 'string' ? [this.value] : (this.value ?? [])
const index = values.findIndex((item) => item === value)
if (multiple) {
(index > -1) ? values.splice(index, 1) : values.push(value)
} else {
values = index === -1 ? [value] : []
}
if (index === -1 && this.cacheOptions.has(value)) {
this.tree.setChecked(data, false, true)
} else {
this.tree.setCheckedKeys(values)
}
let options = this.tree.getCheckedNodes()
if (this.treeProps.autoExpandParent === false || this.excludeParent) {
options = options.filter(item => !this.getChildren(item))
}
const result = multiple ? options.map(item => toValue(item)) : toValue(options[0])
this.updateValue(result)
},
selectChange(data, node) {
const { expandOnClickNode = true } = this.treeProps ?? {}
if ((!expandOnClickNode) || (expandOnClickNode && node.isLeaf)) {
this.setCheckedKeys(data, node)
}
},
setSelectOptions() {
const options = this.tree.getCheckedNodes()
this.cacheOptions = new Map(options.map(item => [this.getValue(item), item]))
let values = this.cacheOptions.values().toArray()
if (this.treeProps.autoExpandParent === false || this.excludeParent) {
values = values.filter(item => !this.getChildren(item))
}
this.select.options = this.cacheOptions.size > 0 ? values : [{}]
this.select.cachedOptions = values.map(item => ({ ...item, value: this.getValue(item), currentLabel: this.getLabel(item) }))
this.select.setSelected()
},
handleClear() {
this.updateValue(undefined)
this.$emit('clear')
this.cacheOptions.clear()
this.tree.setCheckedKeys([])
}
},
};
</script>
<style lang="scss" scoped></style>