elementUI有select组件也有tree组件,但是就是没有下拉框和tree组件的结合体,那么这次我们就自定义一个。
效果图
引入组件
<select-tree ref="selectTree" @treeChange="treeChangeFun" :dataArray="orgList" :value="currentValue" />
import selectTree from '@/components/selectTree.vue'
components: {
selectTree
},
treeChangeFun (val) {
console.log(val)
},
注意点:
- treeChange为子组件的emit函数
- dataArray为tree的数据,形式为父子嵌套结构
- value为默认选中的节点id(也可能是其他key,以node-key定义的值为准),如果没有默认选中节点的需求,也可以不考虑此参数
编写组件js
源码如下:
<template>
<div class="selectTree">
<el-select class="main-select-tree" ref="selectTree" v-model="transitValue">
<el-option v-for="item in selectOptions" :key="item.id" :label="item.name" :value="item.id" style="display: none;" />
<el-tree class="main-select-el-tree" ref="selecteltree" :highlight-current="true" :data="dataArray" :props="defaultProps" :expand-on-click-node="false" node-key="id" @node-click="handleNodeClick" :current-node-key="currentKey" :default-expanded-keys="[value]" />
</el-select>
</div>
</template>
<script>
export default {
name: 'selectTree',
props: {
dataArray: Array,
value: [Number, String]
},
data () {
return {
transitValue: '',
selectOptions: [],
currentKey: null,
defaultProps: {
label: 'name',
children: 'children'
}
}
},
computed: {
formatData () {
let result = []
function getChild (item) {
item.forEach((i, x) => {
if (Array.isArray(i['children'])) {
result.push(i)
getChild(i['children'])
} else {
result.push(i)
}
})
}
getChild(this.dataArray)
return result
}
},
methods: {
handleNodeClick (node) {
this.$emit('treeChange', node)
this.transitValue = node.id
this.$refs.selectTree.blur()
}
},
watch: {
formatData (n) {
if (n.length > 0) {
this.selectOptions = n
} else {
this.selectOptions = []
}
},
value: {
// immediate: true,
// deep: true,
handler: function (n) {
if (n.toString()) {
this.$nextTick(() => {
this.transitValue = n
this.currentKey = this.value
this.$refs['selecteltree'].setCurrentKey(this.currentKey)
})
} else {
this.$nextTick(() => {
this.transitValue = n
this.currentKey = this.value
this.$refs['selecteltree'].setCurrentKey(null)
})
}
}
}
}
}
</script>
<style lang="less" scoped>
/deep/ .el-tree-node.is-current>.el-tree-node__content {
color: #409EFF;
}
</style>
注意点:
- 可以看到我们在select里面正常的包裹了option,这是为了依靠option来撑起下拉区域高度,设置样式为display:none。
- 同时和option平级的地方包裹了tree组件,这是实际要展示的效果组件。
- transitValue是select组件的model值,selectOptions是option的值数组,currentKey是初始化时默认选中节点,defaultProps是tree数据的映射对象。
- formatData函数的功能是将嵌套数组转化成平铺为一级的一维数组,方便option组件遍历展示。
- handleNodeClick是tree的单击事件,这里触发子组件的emit事件。
- watch里的formatData用于检测数据变化动态渲染option。
- watch里的value用于实时检测value值,用来确定子组件tree的选中项(此操作用于初始化组件时,或者父组件重置条件,或者其他不通过直接点击子组件tree节点改变选中项值的操作)。