阅读量:0
目录
简述
基于Element UI内置的Select下拉和Tree树形组件,组合封装的树状下拉选择器。
效果
先看效果:
下拉状态:
选择后状态:
选择的数据:
功能描述
1、加载树结构,实现树状下拉选择器;
2、可通过关键词实现本地和远程过滤;
3、高亮选择行;
4、设置默认选择行;
5、可直接应用在form表单;
代码实现
树状下拉组件代码:
<!-- 树状下拉选择框: 1、加载树结构,实现树状下拉选择组件; 2、可通过关键词实现本地和远程过滤; 3、高亮选择行; 4、设置默认选择行; 5、可直接应用在form表单; --> <template> <el-select ref="selectRef" clearable filterable :remote="remote" :remote-method="selectRemoteMethod" v-model="currentLabel" @visible-change="handleVisibleChange" @clear="handleClear" > <el-option style="height: 100%; padding: 0" value="" v-loading="loading" element-loading-text="加载中..." element-loading-spinner="el-icon-loading" > <el-tree ref="treeRef" :data="dataOfTree" :node-key="defaultProps.value" :props="defaultProps" highlight-current default-expand-all :current-node-key="selectedNode.value" :expand-on-click-node="false" @node-click="handleNodeClicked" :filter-node-method="filterNode" > </el-tree> </el-option> </el-select> </template> <script> export default { name: 'SelectTree', components: {}, model: { prop: 'inputValue', event: 'myInputEvent' }, props: { // 默认选中值 defaultValue: { type: Number }, // 是否远程搜索 remote: { type: Boolean, default: false }, // 远程方法 remoteMethod: { type: Function }, treeOptions: { type: Array, default: () => { return [] } }, defaultProps: { type: Object, default: () => { return { children: 'children', label: 'label', value: 'value' } } } }, watch: { treeOptions: { handler(newValue) { this.dataOfTree = JSON.parse(JSON.stringify(newValue)) // 保留源数据; this.dataSource = JSON.parse(JSON.stringify(newValue)) }, deep: true, immediate: false }, defaultValue: { handler(newValue) { this.selectedNode = {} this.currentLabel = undefined this.currentValue = newValue this.$nextTick(() => { // 过滤方式是通过value还是label; this.isFilterWithValue = true if (this.dataOfTree) { this.$refs.treeRef.filter(newValue) } }) }, deep: true, immediate: true } }, data() { return { selectedNode: {}, loading: false, currentValue: undefined, currentLabel: undefined, dataOfTree: [] } }, created() { this.dataOfTree = JSON.parse(JSON.stringify(this.treeOptions)) // 保留源数据; this.dataSource = JSON.parse(JSON.stringify(this.treeOptions)) }, mounted() { }, methods: { selectRemoteMethod(val) { this.isFilterWithValue = false if (this.remote) { // 远程搜索 this.remoteMethod(val) } else { // 本地过滤 this.$refs.treeRef.filter(val) } }, handleClear() { // 如果内容被清空 this.selectedNode = {} this.currentLabel = undefined this.currentValue = undefined const result = this.buildEmptyResult() this.$emit('myInputEvent', result) this.$emit('onNodeSelectEvent', result) }, handleVisibleChange(visible) { if (!visible) { // 先移除所有数据; this.dataOfTree.splice(0) // 恢复原来的所有数据; this.dataOfTree.splice(0, 0, ...this.dataSource) // 本地过滤 this.$refs.treeRef.filter('') } }, filterNode(value, data) { if (!value) { return data } if (this.isFilterWithValue) { if (data[this.defaultProps.value] === value) { this.selectedNode = data this.currentLabel = data[this.defaultProps.label] this.$refs.treeRef.setCurrentKey(this.selectedNode[this.defaultProps.value]) const result = this.buildResultByNodeData(data) this.$emit('myInputEvent', result) } } else { return data[this.defaultProps.label].indexOf(value) !== -1 } return data }, closeSelect() { this.$refs.selectRef.blur() }, /** * @param data * @param node * @param comp */ handleNodeClicked(data, node, comp) { this.selectedNode = data this.currentLabel = data[this.defaultProps.label] this.currentValue = data[this.defaultProps.value] const result = this.buildResultByNodeData(data) this.$emit('myInputEvent', result) this.$emit('onNodeSelectEvent', result) this.closeSelect() }, buildResultByNodeData(data) { return { node: data[this.defaultProps.value], data: { label: data[this.defaultProps.label], value: data[this.defaultProps.value] }, meta: data } }, buildEmptyResult() { return { node: undefined, data: { label: undefined, value: undefined }, meta: undefined } } } } </script> <style lang='scss' scoped> </style>
应用示例:
<template> <div> <div>测试表单</div> <el-form ref="demandFormRef" :model="form" label-suffix=":" status-icon label-position="left" > <el-form-item label="树" label-width="85px" prop="tree"> <select-tree v-model="form.tree" :tree-options="treeOptions" :default-value="form.tree.node" @onNodeSelectEvent="handleNodeSelectEvent($event)" /> </el-form-item> </el-form> <div> <el-button @click="reset">重置</el-button> <el-button @click="submit">提交</el-button> </div> </div> </template> <script> import {Message} from 'element-ui' import SelectTree from '@/components/SelectTree/index' export default { components: { SelectTree }, props: {}, data() { return { form: { tree: {node: undefined, data: {}} }, treeOptions: [{ value: 1, label: '一级 1', children: [{ value: 11, label: '二级 1-1', children: [{ value: 111, label: '三级 1-1-1' }] }] }, { value: 2, label: '一级 2', children: [{ value: 21, label: '二级 2-1' }] }, { value: 3, label: '一级 3', children: [{ value: 31, label: '二级 3-1', children: [{ value: 311, label: '三级 3-1-1' }] }, { value: 32, label: '二级 3-2', children: [{ value: 321, label: '三级 3-2-1' }] }] }] } }, mounted() { // 模拟接口请求,反显选择数据 // setTimeout(() => { // this.form.tree.node = 2 // }, 1000) }, methods: { reset() { this.form.tree = {node: undefined, data: {}} }, submit() { const data = this.form.tree.data Message.info(`选中节点名称是${data.label},值是${data.value}`) }, handleNodeSelectEvent(dataSelected){ } } } </script> <style lang='scss' scoped> </style>
总结
本示例中,部分实现细节或者写法,可根据实际需要调整,树状下拉的实现方式有多种,这只是其中一种,只要符合实际需求就可以。
如果发现问题,欢迎随时提出,共同改进。