<!--el-select+el-tree -->
<template>
<el-select
ref="select"
popper-class="TREE_SELECT_POPPER"
:value="showLabel"
:size="size"
:placeholder="placeholder"
:clearable="clearable"
:disabled="disabled"
:filterable="filterable"
:filter-method="selectFilter"
@visible-change="visibleChange"
@focus="selectFocus"
@clear="emitVal"
>
<el-option class="option_li" :value="showLabel" :label="showLabel" :style="{height: optionHeight+'px'}">
<el-scrollbar class="option_li_scroll">
<el-tree
ref="tree"
:accordion="accordion"
:data="options"
:props="props"
:node-key="props.value"
:show-checkbox="multiple"
:default-expanded-keys="(multiple && Array.isArray(value)) ? value : [value]"
:default-checked-keys="(multiple && Array.isArray(value)) ? value : []"
:expand-on-click-node="false"
:check-strictly="checkStrictly"
:filter-node-method="treeFilter"
@node-click="nodeClick"
@check="nodeCheck"
/>
</el-scrollbar>
</el-option>
</el-select>
</template>
<script>
import pinyinMatch from 'pinyin-match'
export default {
name: 'TreeSelect',
props: {
props: { // 配置項
type: Object,
default() {
return {
value: 'value',
label: 'label',
children: 'children'
}
}
},
options: { // 選項列表數據
type: Array,
default() {
return []
}
},
value: { // 綁定值
type: [String, Number, Array],
default: ''
},
accordion: { // 是否每次只展開一個同級樹節點
type: Boolean,
default: false
},
size: {
type: String,
default: ''
},
multiple: { // 是否可多選
type: Boolean,
default: false
},
filterable: { // 是否可搜索
type: Boolean,
default: true
},
clearable: { // 是否可清空
type: Boolean,
default: true
},
disabled: { // 是否禁用
type: Boolean,
default: false
},
placeholder: {
type: String,
default: ''
},
checkStrictly: { // 父子是否不互相關聯
type: Boolean,
default: false
},
lastLevel: {
type: String,
default: ''
},
infoError: {
type: String,
default: ''
},
popHeight: {
type: [String, Number],
default: 247
}
},
data() {
return {
optionHeight: 247
}
},
computed: {
showLabel() {
let label = ''
const value = this.value
if (this.multiple) { // 多選
if (Array.isArray(value) && value.length > 0) {
const labelArr = []
value.forEach(value => {
labelArr.push(this.queryTree(this.options, value))
})
label = labelArr.join(',')
}
} else { // 單選
if (value) {
label = this.queryTree(this.options, value)
}
}
return label
}
},
methods: {
// 搜索樹狀數據中的 ID,獲取label
queryTree(tree, id) {
let stark = []
stark = stark.concat(tree)
let label = ''
while (stark.length) {
const temp = stark.shift()
if (temp[this.props.children]) {
stark = stark.concat(temp[this.props.children])
}
if (temp[this.props.value] === id) {
label = temp[this.props.label]
}
}
return label
},
// 提交值
emitVal(val) {
if (!val) {
val = this.multiple ? [] : ''
}
this.$emit('input', val)
},
// select框獲得焦點
selectFocus() {
this.$refs.tree.filter('')
this.$emit('on-focus')
},
// select option過濾
selectFilter(label) {
this.$refs.tree.filter(label)
return true
},
// 樹過濾方法
treeFilter(query, data) {
if (!query) {
return true
} else {
const labelArray = query.split(',')
// 拼配全有科室 誤刪
// return labelArray.some(value => {
// return value && data[this.props.label].includes(value)
// })
return labelArray.some(value => {
return value && pinyinMatch.match(data[this.props.label], value)
})
}
},
// 下拉框出現/隱藏
visibleChange(show) {
if (show) {
this.$nextTick(() => {
const tree_H = this.$refs.tree.$el.clientHeight
if (tree_H < this.optionHeight) {
this.optionHeight = this.popHeight
}
})
}
},
// 點擊節點
nodeClick(node) {
if (!this.multiple) {
if (node[this.lastLevel] === 0) {
this.$message.error(this.infoError)
this.emitVal()
return false
}
this.emitVal(node[this.props.value])
this.$emit('info', node)
this.$refs.select.blur() // 使select失去焦點 隱藏下拉框
}
},
// 點擊復選框
nodeCheck(node, data) {
this.emitVal(data.checkedKeys)
}
}
}
</script>
<style lang="scss" type="text/scss">
.TREE_SELECT_POPPER>.el-scrollbar {
>.el-scrollbar__bar.is-vertical {
right:10px;
display: none;
}
}
.TREE_SELECT_POPPER .el-select-dropdown__item{
background: #fff;
}
</style>
<style scoped lang="scss" type="text/scss">
.el-select-dropdown__item {
height: auto;
padding: 0;
&.selected {
font-weight: normal;
}
}
.el-tree /deep/ .el-tree-node__content {
height: 34px !important;
padding: 0 10px 0 0;
}
.option_li {
padding: 0;
background-color: #fff;
&.selected {
font-weight: normal;
}
.option_li_scroll {
height: 100%;
/deep/ .el-scrollbar__wrap{
overflow-x: hidden;
}
}
}
.el-tree {
box-sizing: border-box;
padding: 0 12px;
}
</style>
使用
<tree-select
v-model="departValue"
:options="departmentList"
:props="{
label: 'treedatacodeandname',
value: treeValue,
children: 'childList'
}"
:disabled="disabled"
filterable
last-level="blnisdetail"
info-error="請選擇末級"
@input="onChange"
@info="onChangeInfo"
/>