elementUI实现selecttree自定义下拉框树形组件支持多选和搜索
- 效果图
- 定义子组件
- 父组件应用
效果图
定义子组件
主要结合el-select和el-tree两个组件改造的。
<template>
<div class="selectTree">
<el-select filterable :filter-method="filterMethod" class="main-select-tree" ref="selectTree" multiple v-model="transitValue" @remove-tag="removeTag" clearable @clear="clearInput" @focus="blurInput">
<el-option v-for="item in selectOptions" :key="item.department_id" :label="item.name" :value="item.department_id" style="display: none;" />
<el-tree class="main-select-el-tree" ref="selecteltree" :filter-node-method="filterNode" show-checkbox @check-change="handleCheckChange" :highlight-current="true" :data="dataArray" :props="defaultProps" :expand-on-click-node="false" node-key="department_id" @node-click="handleNodeClick" :current-node-key="currentKey">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span :title="data.description">{{ node.label }}</span>
</span>
</el-tree>
</el-select>
</div>
</template>
<script>
export default {
name: 'selectTree',
props: {
dataArray: Array
},
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: {
filterMethod (value) {
this.$refs['selecteltree'].filter(value.trim())
},
blurInput () {
console.log('1213')
this.$refs['selecteltree'].filter('')
},
filterNode(value, data) {
if (!value) return true
return data.name.indexOf(value) !== -1
},
clearInput () {
this.$refs['selecteltree'].setCheckedKeys([])
},
removeTag (e) {
this.$refs['selecteltree'].setChecked(e, false)
},
handleCheckChange () {
let check = this.$refs['selecteltree'].getCheckedNodes()
console.log(check)
let arr = check.filter((i) => !i.children)
this.transitValue = arr.map((i) => {
return i.department_id
})
this.$emit('treeChange', arr)
}
},
watch: {
formatData: {
immediate: true,
handler: function (n) {
if (n.length > 0) {
this.selectOptions = n
} else {
this.selectOptions = []
}
}
}
}
}
</script>
<style lang="less" scoped>
.main-select-el-tree {
max-height: 300px;
overflow-y: auto;
}
.el-select-dropdown.is-multiple .el-select-dropdown__item {
display: none;
}
</style>
父组件应用
<div>
<template>
<p class="pTitle">{{ 选择团队 }}</p>
<select-tree ref="selectTree" @treeChange="treeChangeFun" :dataArray="orgList" />
</template>
</div>
import selectTree from '@/components/selectTreeMulti.vue'
data(){
orgList: [],
},
mounted(){
this.orgList = translateDataToTree(data).treeData // data数据格式参看备注1
},
components: {
selectTree
},
methods: {
treeChangeFun(val) {
console.log(val)
},
translateDataToTree(data) {
data = JSON.parse(JSON.stringify(data))
// 删除所有 children,以防止多次调用
let checkArr = []
data.forEach(function (item) {
delete item.children;
if (item.is_bind) {
checkArr.push(item.department_id)
}
});
let map = {}; // 构建map
data.forEach(i => {
map[i.department_id] = i; // 构建以id为键 当前数据为值
});
let treeData = [];
data.forEach(child => {
const mapItem = map[child.parent_id]; // 判断当前数据的parentId是否存在map中
if (mapItem) { // 存在则表示当前数据不是最顶层数据
// 注意: 这里的map中的数据是引用了arr的它的指向还是arr,当mapItem改变时arr也会改变,踩坑点
// 这里判断mapItem中是否存在children, 存在则插入当前数据, 不存在则赋值children为[]然后再插入当前数据
(mapItem.children || ( mapItem.children = [] )).push(child)
} else { // 不存在则是组顶层数据
treeData.push(child);
}
});
return {
treeData: treeData,
checkArr: checkArr
};
}
}
data格式: