el-select+el-tree实现树形下拉选择
前言
项目需求所需,记录下el-select+el-tree实现树形下拉选择
一、使用步骤
1.封装
<template><div style="display: flex"><el-selectv-model="insideValue":multiple="multiple":disabled="disabled":placeholder="placeholder":collapse-tags="collapseTags"@visible-change="handleVisibleChange"v-on="$listeners"style="width: 100%"ref="treeSelect"><!-- 添加实际的 el-option 用于显示标签 --><el-optionv-for="item in selectedOptions":key="item.value":label="item.label":value="item.value"style="display: none"/><!-- 树形选择器 --><el-option style="height: auto; padding: 0" :value="insideValue"><el-treev-show="showTree":data="options":show-checkbox="multiple":props="defaultProps"v-on="$listeners":highlight-current="true"node-key="orgCode"ref="tree":check-strictly="checkStrictly"@node-click="handleNodeClick"@check="handleCheckChange":default-expanded-keys="defaultExpandedKeys"></el-tree></el-option></el-select></div>
</template><script lang="ts">
import { Vue, Component, Prop, Watch, Ref } from 'vue-property-decorator'interface TreeNode {orgCode: stringorgName: stringchildren?: TreeNode[]
}interface SelectOption {value: stringlabel: string
}@Component({name: 'comTreeSelect'
})
export default class ComTreeSelect extends Vue {@Prop({ type: [String, Array] }) value!: string | string[]@Prop({ type: Boolean, default: false }) disabled!: boolean@Prop({ type: Boolean, default: false }) multiple!: boolean@Prop({ type: String, default: '请选择' }) placeholder!: string@Prop({ type: Boolean, default: false }) collapseTags!: boolean@Prop({ type: Boolean, default: true }) selectShow!: boolean@Prop({ type: Boolean, default: true }) checkStrictly!: boolean@Ref('treeSelect') treeSelectRef!: any@Ref('tree') treeRef!: anycomponentInit = falseinsideValue: string | string[] = this.multiple ? [] : ''options: TreeNode[] = []selectedOptions: SelectOption[] = [] // 用于存储选中的选项loading = falseshowTree = falsedefaultProps = {children: 'children',label: 'orgName',value: 'orgCode'}searchMap = {pageIndex: 1,pageSize: 999,search: {}}get selectedLabelText(): string {return this.selectedOptions.map((option) => option.label).join(', ')}get defaultExpandedKeys(): any {const keys = []this.options.forEach((node) => {keys.push(node.orgCode)})return keys}@Watch('value', { immediate: true })onValueChange(newVal: string | string[]): void {this.insideValue = this.multiple ? newVal || [] : newVal || ''// 如果组件已经初始化,需要同步树的选择状态if (this.componentInit) {this.syncTreeSelection()}}@Watch('insideValue')onInsideValueChange(newVal: string | string[]): void {this.$emit('input', newVal)}async getRemoteList(): Promise<void> {try {this.loading = trueconst { code, result } = await this.$agencyManage.list(this.searchMap, { isLoading: false })if (code === 200) {this.options = result ? result.items || [] : []// 数据加载完成后同步选择状态this.syncTreeSelection()}} catch (error) {console.error('获取机构列表失败:', error)} finally {this.loading = false}}// 同步树的选择状态syncTreeSelection(): void {this.$nextTick(() => {if (this.multiple && Array.isArray(this.insideValue)) {this.treeRef?.setCheckedKeys(this.insideValue)this.updateSelectedOptions()this.$emit('change', this.insideValue)} else if (!this.multiple && typeof this.insideValue === 'string') {this.treeRef?.setCurrentKey(this.insideValue)this.updateSelectedOptions()this.$emit('change', this.insideValue)}})}// 更新选中的选项updateSelectedOptions(): void {if (this.multiple) {const checkedNodes = this.treeRef?.getCheckedNodes() || []this.selectedOptions = checkedNodes.map((node: TreeNode) => ({value: node.orgCode,label: node.orgName}))} else {const currentNode = this.treeRef?.getCurrentNode()console.log('currentNode', currentNode)this.selectedOptions = currentNode ? [{ value: currentNode.orgCode, label: currentNode.orgName }] : []}}handleVisibleChange(visible: boolean): void {this.showTree = visibleif (visible) {this.$nextTick(() => {this.syncTreeSelection()})}}handleNodeClick(node: TreeNode): void {if (!this.multiple) {this.insideValue = node.orgCodethis.selectedOptions = [{value: node.orgCode,label: node.orgName}]this.$emit('input', this.insideValue)this.$emit('change', this.insideValue)this.showTree = falsethis.treeSelectRef.blur()}}handleCheckChange(): void {if (this.multiple) {const checkedNodes = this.treeRef?.getCheckedNodes() || []this.insideValue = checkedNodes.map((node: TreeNode) => node.orgCode)this.selectedOptions = checkedNodes.map((node: TreeNode) => ({value: node.orgCode,label: node.orgName}))this.$emit('input', this.insideValue)this.$emit('change', this.insideValue)}}mounted(): void {this.$nextTick(() => {if (!this.componentInit) {this.getRemoteList()}})}activated(): void {this.componentInit = truethis.getRemoteList()}handleChange(): void {this.insideValue = this.multiple ? [] : ''}
}
</script><style scoped lang="scss">
.el-select {.el-input--mini .el-input__inner {height: 28px !important;line-height: 28px !important;}/* 修复树形选择器的样式 */.el-tree {padding: 5px;min-width: 100%;box-sizing: border-box;}
}
</style>
2.使用
<com-tree-selectv-model="value":disabled="false":multiple="true":collapseTags="true":checkStrictly="true/>
总结
以上是我封装的组件,如有问题,可以提出。