首页 > 分享 > 自定义树状下拉框组件实现

自定义树状下拉框组件实现

前言

项目中有些下拉框的数据需要使用树形结构,但是ElementUI中并没有提供相关功能,如果使用级联选择器,又会显得页面臃肿庞大,极不美观。项目中大佬提供了一个树状下拉框的组件,将代码记下来。

代码

<!-- 树状选择器 --> <template> <el-popover ref="popover" placement="bottom-start" trigger="click" @show="onShowPopover" @hide="onHidePopover"> <el-tree ref="tree" class="select-tree" highlight-current :style="`min-width: ${treeWidth}`" :data="data" :node-key="nodeKey" :props="props" :expand-on-click-node="false" :filter-node-method="filterNode" default-expand-all @node-click="onClickNode"></el-tree> <el-input slot="reference" ref="input" v-model="labelModel" :style="`width: ${width}px`" :class="{ 'rotate': showStatus }" suffix-icon="el-icon-arrow-down" :placeholder="placeholder"></el-input> </el-popover> </template> <script> export default { name: 'SelectTree', props: { // 接收绑定参数 value: String, // 输入框宽度 width: String, // 是否只可以选中叶子节点 onlyLeafNode: Boolean, // 选项数据 options: {type: Array, required: true}, // 输入框占位符 placeholder: {type: String, required: false, default: '请选择'}, // 树节点配置选项 props: { type: Object, required: false, default: () => ({value: 'value', label: 'label', parentId: 'parentId', children: 'children'}) } }, // 设置绑定参数 model: {prop: 'value', event: 'selected'}, computed: { // 是否为树状结构数据 dataType() { this.nodeKey = this.props.value; const jsonStr = JSON.stringify(this.options); return jsonStr.indexOf(this.props.children) !== -1; }, // 若非树状结构, 则转化为树状结构数据 data() { return this.dataType ? this.options : this.switchTree(); } }, data() { return { nodeKey: '', // 树状菜单显示状态 showStatus: false, // 菜单宽度 treeWidth: 'auto', // 输入框显示值 labelModel: '', // 实际请求传值 valueModel: '', // 当前选中是否是叶子节点 hasLeafNode: false }; }, watch: { labelModel(val) { if (!val) { this.valueModel = ''; } this.$refs.tree.filter(val); this.$refs.tree.setCurrentKey(this.valueModel); // 高亮节点 }, value(val) { this.labelModel = this.queryTree(this.data, val); } }, created() { // 检测输入框原有值并显示对应 label if (this.value) { this.labelModel = this.queryTree(this.data, this.value); } // 获取输入框宽度同步至树状菜单宽度 this.$nextTick(() => { let treeWidth = `${(this.width || this.$refs.input.$refs.input.clientWidth) - 24}`; this.treeWidth = treeWidth > 1000 ? '1000px' : treeWidth + 'px'; }); }, methods: { toHighlight(isAdd) { isAdd ? this.$refs.tree.$el.classList.add("el-tree--highlight-current") : this.$refs.tree.$el.classList.remove("el-tree--highlight-current"); }, // 单击节点 onClickNode(node) { // 非叶子节点不可以选择 let childNode = node[this.props.children]; if (this.onlyLeafNode && childNode !== undefined && childNode !== null && childNode.length !== 0) { this.hasLeafNode = false; this.toHighlight(this.hasLeafNode); return; } this.hasLeafNode = true; this.toHighlight(this.hasLeafNode); this.valueModel = node[this.props.value]; this.labelModel = node[this.props.label]; this.onCloseTree(); }, // 偏平数组转化为树状层级结构 switchTree() { return this.cleanChildren(this.buildTree(this.options, '0')); }, // 隐藏树状菜单 onCloseTree() { this.$refs.popover.showPopper = false; }, // 显示时触发 onShowPopover() { this.showStatus = true; this.$refs.tree.filter(false); }, // 隐藏时触发 onHidePopover() { this.showStatus = false; this.$emit('selected', this.valueModel); this.toHighlight(this.valueModel); this.$refs.tree.setCurrentKey(this.valueModel); // 高亮节点 // 非叶子节点不可以调用点击事件 if (this.valueModel || !this.onlyLeafNode || this.hasLeafNode) { this.$emit('click'); } }, // 树节点过滤方法 filterNode(query, data) { if (!query) return true; return data[this.props.label].indexOf(query) !== -1; }, // 搜索树状数据中的 ID queryTree(tree, id) { let stark = []; stark = stark.concat(tree); 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) { // 非叶子节点不可以选择 let childNode = temp[this.props.children]; if (this.onlyLeafNode && childNode !== undefined && childNode !== null && childNode.length !== 0) { this.hasLeafNode = false; return ''; } this.valueModel = id; this.hasLeafNode = true; return temp[this.props.label]; } } return ''; }, // 将一维的扁平数组转换为多层级对象 buildTree(data, id = '0') { const fa = (parentId) => { const temp = []; for (let i = 0; i < data.length; i++) { const n = data[i]; if (n[this.props.parentId] === parentId) { n.children = fa(n.id); temp.push(n); } } return temp; }; return fa(id); }, // 清除空 children 项 cleanChildren(data) { const fa = (list) => { list.map((e) => { if (e.children.length) { fa(e.children); } else { delete e.children; } return e; }); return list; }; return fa(data); } } }; </script> <style> .el-input.el-input--suffix { cursor: pointer; overflow: hidden; } .el-input.el-input--suffix.rotate .el-input__suffix { transform: rotate(180deg); } .select-tree { max-height: 350px; overflow-y: scroll; } /* 菜单滚动条 */ .select-tree::-webkit-scrollbar { z-index: 11; width: 6px; } .select-tree::-webkit-scrollbar-track, .select-tree::-webkit-scrollbar-corner { background: #fff; } .select-tree::-webkit-scrollbar-thumb { border-radius: 5px; width: 6px; background: #b4bccc; } .select-tree::-webkit-scrollbar-track-piece { background: #fff; width: 6px; } </style>

html

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250

相关知识

打造高效项目管理:Vue2自制甘特图组件推荐
Mapbox更换地图组件底图样式
vue3 自定义插件
组件岛Widget Island — 手机桌面美化应用小组件
草图大师的组件
DWZ后台框架,快速搭建你的后台资源
组件Element的入门学习
在Flutter中实现自定义地图标记的最佳实践是什么
雾效的实现方法(自定义方法与内置方法)
做树状图用什么软件2022 哪些软件可以做树状图

网址: 自定义树状下拉框组件实现 https://m.huajiangbk.com/newsview2489505.html

所属分类:花卉
上一篇: 网友推荐:这款年宵花究竟有何魅力
下一篇: 新年新宠:这款年宵花为何成为今年