element-ui Cascader 组件官方地址Element - The world's most popular Vue UI framework
该组件,运用在现实场景中依旧不满足甲方的胃口。
改呀~改呀~改呀~改呀~改呀~改呀~改呀~改呀~改呀~改呀~改呀~改呀~改呀~改呀~改呀~改呀!
最终效果
代码实现
<template>
<div>
<el-select
:title="multiple? optionData.name : ''"
ref="select"
:value="value"
:placeholder="placeholder"
clearable
:disabled="disabled"
:filterable="filterable"
:filter-method="filterMethod"
style="width: 100%;"
@clear="clear"
@visible-change="visibleChange"
>
<el-option
ref="option"
class="tree-select__option"
:value="optionData.id"
:label="optionData.name"
>
<el-tree
style="max-height: 150px;overflow: auto"
ref="tree"
class="tree-select__tree"
:class="`tree-select__tree--${multiple ? 'checked' : 'radio'}`"
:node-key="nodeKey"
:data="data"
:props="props"
:default-expanded-keys="[value]"
:show-checkbox="multiple"
:highlight-current="!multiple"
:expand-on-click-node="multiple"
:filter-node-method="filterNode"
@node-click="handleNodeClick"
@check-change="handleCheckChange"
></el-tree>
</el-option>
</el-select>
</div>
</template>
<script>
export default {
name: 'TreeSelect',
props: {
placeholder:{
type:String
},
// v-model绑定
value: {
type: [String, Number],
default: ''
},
multiple: {
type: Boolean,
default: true
},
// 树形的数据
data: {
type: Array,
default: function () {
return []
}
},
// 每个树节点用来作为唯一标识的属性
nodeKey: {
type: [String, Number],
default: 'id'
},
filterable: {
type: Boolean,
default: true
},
disabled: {
type: Boolean,
default: false
},
// tree的props配置
props: {
type: Object,
default: function () {
return {
label: 'deptName',
children: 'children'
}
}
}
},
data() {
return {
optionData: {
id: '',
name: ''
},
filterFlag: false
}
},
watch: {
value: {
handler(val) {
if (!this.isEmpty(this.data)) {
this.init(val)
}
},
immediate: true
},
data: function (val) {
if (!this.isEmpty(val)) {
this.init(this.value)
}
}
},
created() {},
methods: {
// 是否为空
isEmpty(val) {
for (let key in val) {
return false
}
return true
},
handleNodeClick(data) {
if (this.multiple) {
return
}
this.$emit('input', data[this.nodeKey])
this.$refs.select.visible = false
},
handleCheckChange() {
let arr=[]
const nodes = this.$refs.tree.getCheckedNodes()
nodes.map((item) => arr.push(item[this.nodeKey]))
const value = nodes.map((item) => item[this.nodeKey]).join(',')
this.$emit('input', arr)
},
init(val) {
// 多选
if (this.multiple) {
const arr = val
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(arr)
const nodes = this.$refs.tree.getCheckedNodes()
this.optionData.id = val
this.optionData.name = nodes
.map((item) => item[this.props.label])
.join(',')
})
}
// 单选
else {
val = val === '' ? null : val
this.$nextTick(() => {
this.$refs.tree.setCurrentKey(val)
if (val === null) {
return
}
const label = this.props.label || 'name'
const node = this.$refs.tree.getNode(val)
this.optionData.id = val
this.optionData[label] = node.label
})
}
this.flag=true
},
visibleChange(e) {
if (e) {
const tree = this.$refs.tree
this.filterFlag && tree.filter('')
this.filterFlag = false
let selectDom = null
if(this.multiple) {
selectDom = tree.$el.querySelector('.el-tree-node.is-checked')
} else {
selectDom = tree.$el.querySelector('.is-current')
}
setTimeout(() => {
this.$refs.select.scrollToOption({ $el: selectDom })
}, 0)
}
},
clear() {
this.$emit('input', [])
},
filterMethod(val) {
this.filterFlag = true
this.$refs.tree.filter(val)
},
filterNode(value, data) {
if (!value) return true
const label = this.props.label || 'name'
return data[label].indexOf(value) !== -1
}
}
}
</script>
<style lang="scss">
.tree-select__option {
&.el-select-dropdown__item {
height: auto;
line-height: 1;
padding: 0;
background-color: #fff;
}
}
.tree-select__tree {
color: #333333;
padding: 4px 20px;
font-weight: 400;
&.tree-select__tree--radio {
.el-tree-node.is-current > .el-tree-node__content {
font-weight: 700;
}
}
}
</style>
标签引用
<els-tree-select :placeholder="'请选择数据'" :multiple="true" v-model="dataForm.datas" :data="Options"></els-tree-select>