vue中el-select 和el-tree二次封裝實(shí)現(xiàn)
前言
本文章是本人在開(kāi)發(fā)過(guò)程中,遇到使用樹形數(shù)據(jù),動(dòng)態(tài)單選或多選的需求,element中沒(méi)有這種組件,故自己封裝一個(gè),歡迎多多指教
開(kāi)發(fā)環(huán)境:element-UI、vue2
組件效果
單選
多選
組件引用
<treeselect v-model="form.parentId" :options="deptOptions" :props="{value:'id',label:'name',children: 'children'}" :placeholder="'選擇上級(jí)部門'" />
組件代碼
<template> <div> <el-select ref="treeSelect" popper-class="custom-select-popper" style="width: 100%" v-model="valueLabel" :clearable="clearable" :placeholder="placeholder" :multiple="multiple" @clear="handleClear" @remove-tag="handleRemoveTag" > <el-input v-if="filter" v-model="filterText" :placeholder="filterPlaceholder" style="margin-top: -6px;" /> <el-option :value="value" :label="option.name" class="select-options"> <el-tree id="tree-option" ref="treeSelectTree" :accordion="accordion" :data="options" :props="props" :node-key="props.value" :highlight-current="!multiple" :show-checkbox="multiple" :check-strictly="checkStrictly" :default-expand-all="expandAll" :expand-on-click-node="multiple" :filter-node-method="filterNode" @node-click="handleNodeClick" @check="handleNodeCheckbox" > <span slot-scope="{ node, data }" class="tree_label"> {{ node.label }} </span> </el-tree> </el-option> </el-select> </div> </template> <script> export default { name: 'TreeSelect', model: { prop: 'value', event: 'change' }, props: { value: { type: [String, Number, Object, Array], default: () => { return '' } }, clearable: { type: Boolean, default: true }, placeholder: { type: String, default: '請(qǐng)選擇' }, multipleLimit: { type: Number, default: 2 }, //--------- filter props ----- filter: { type: Boolean, default: true }, filterPlaceholder: { type: String, default: '請(qǐng)輸入關(guān)鍵字' }, //----- tree props ----- accordion: { type: Boolean, default: false }, options: { type: Array, default: () => { return [] } }, props: { type: Object, default: () => { return { value: 'id', label: 'label', children: 'children' } } }, expandAll: { type: Boolean, default: false }, checkStrictly: { type: Boolean, default: false } }, data() { return { tp: { value: 'id', label: 'label', children: 'children', prentId: 'parentId' }, multiple: false, valueLabel: [], option: { id: '', name: '' }, filterText: undefined, valueId: [], treeIds: [] } }, watch: { valueId() { if (this.multiple) { let valueStr = '' if (this.value instanceof Array) { valueStr = this.value.join() } else { valueStr = '' + this.value } if (valueStr !== this.valueId.join()) { this.$emit('change', this.valueId) } } else { let id = this.valueId.length > 0 ? this.valueId[0] : undefined if (id !== this.value) { this.$emit('change', id) } } }, value: { handler(newVal, oldVal) { if (newVal !== oldVal) { this.init() } } }, filterText: { handler(newVal, oldVal) { if (newVal !== oldVal) { this.$refs.treeSelectTree.filter(newVal) } } } }, mounted() { for (let key in this.tp) { if (this.props[key] !== undefined) { this.tp[key] = this.props[key] } } this.multiple = this.multipleLimit > 1 this.init() this.$nextTick(() => { if (this.multiple) { document.getElementsByClassName('el-select__tags')[0].style.maxHeight = document.getElementsByClassName('el-select')[0].offsetHeight * 2 - 4 + 'px' } }) }, methods: { init() { if (this.value instanceof Array) { this.valueId = this.value } else if (this.value === undefined) { this.valueId = [] } else { this.valueId = [this.value] } if (this.multiple) { for (let id of this.valueId) { this.$refs.treeSelectTree.setChecked(id, true, false) } } else { this.$refs.treeSelectTree.setCurrentKey(this.valueId.length > 0 ? this.valueId[0] : undefined) } this.initValueLabel() this.initTreeIds() this.initScroll() }, // 初始化滾動(dòng)條 initScroll() { this.$nextTick(() => { let scrollWrap = document.querySelectorAll('.el-scrollbar .el-select-dropdown__wrap')[0] scrollWrap.style.cssText = 'margin: 0px; max-height: none; overflow: hidden;' let scrollBar = document.querySelectorAll('.el-scrollbar .el-scrollbar__bar') scrollBar.forEach((ele) => (ele.style.width = 0)) }) }, initTreeIds() { let treeIds = [] let _this = this function traverse(nodes) { for (let node of nodes) { treeIds.push(node[_this.tp.value]) if (node[_this.tp.children]) { traverse(node[_this.tp.children]) } } } traverse(this.options) this.treeIds = treeIds }, initValueLabel() { let labels = [] let _this = this for (let id of this.valueId) { let node = this.traverse(this.options, node => node[_this.tp.value] === id) if (node) { labels.push(node[_this.tp.label]) } } if (this.multiple) { this.valueLabel = labels this.option.name = labels.join() } else { this.valueLabel = labels.length > 0 ? labels[0] : undefined this.option.name = this.valueLabel } }, traverse(tree, func) { for (let node of tree) { if (func(node)) { return node } if (node[this.tp.children]) { let result = this.traverse(node[this.tp.children], func) if (result !== undefined) { return result } } } return undefined }, handleClear() { this.valueLabel = [] this.valueId = [] if (this.multiple) { for (let id of this.treeIds) { this.$refs.treeSelectTree.setChecked(id, false, false) } } else { this.$refs.treeSelectTree.setCurrentKey(null) } }, /* 樹filter方法 */ filterNode(value, data) { if (!value) return true return data[this.props.label].indexOf(value) !== -1 }, /* 樹節(jié)點(diǎn)點(diǎn)擊事件 */ handleNodeClick(data, node) { if (!this.multiple) { this.filterText = '' this.valueId = [data[this.tp.value]] } if(node.childNodes){ node.expanded = true } }, handleNodeCheckbox(data, node) { if (this.multiple) { if (this.multipleLimit >= node.checkedKeys.length) { this.valueId = node.checkedKeys } else { this.$refs.treeSelectTree.setChecked(data, false, !this.checkStrictly) this.$message.error('最多選擇' + this.multipleLimit + '項(xiàng)') } } }, handleRemoveTag(tag) { let n = this.traverse(this.options, node => node[this.tp.label] === tag) if (n) { this.$refs.treeSelectTree.setChecked(n[this.tp.value], false, !this.checkStrictly) } this.valueId = this.$refs.treeSelectTree.getCheckedKeys() } } } </script> <style scoped lang="scss"> ::v-deep .el-select__tags { overflow: auto; } .custom-select-popper{ } .el-scrollbar { .el-scrollbar__view { .el-select-dropdown__item { height: auto; max-height: 300px; padding: 0; overflow: hidden; overflow-y: auto; } .el-select-dropdown__item.selected { font-weight: normal; } } } ul li { .el-tree { .el-tree-node__content { height: auto; padding: 0 20px; } .el-tree-node__label { font-weight: normal; } .is-current > .el-tree-node__label{ color: #409eff; font-weight: 700; } } } .tree_label { line-height: 23px; .label_index { background-color: rgb(0, 175, 255); width: 22px; height: 22px; display: inline-flex; border-radius: 4px; .label_index_font { color: #ffffff; width: 100%; text-align: center; } } } </style>
到此這篇關(guān)于vue中el-select 和el-tree二次封裝實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)vue el-select 和el-tree封裝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于element?ui中的el-scrollbar橫向滾動(dòng)問(wèn)題
這篇文章主要介紹了關(guān)于element?ui中的el-scrollbar橫向滾動(dòng)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08vue + element-ui的分頁(yè)問(wèn)題實(shí)現(xiàn)
這篇文章主要介紹了vue + element-ui的分頁(yè)問(wèn)題實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12Vue3?封裝擴(kuò)展并簡(jiǎn)化Vuex在組件中的調(diào)用問(wèn)題
這篇文章主要介紹了Vue3?封裝擴(kuò)展并簡(jiǎn)化Vuex在組件中的調(diào)用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-01-01Vue3實(shí)現(xiàn)九宮格抽獎(jiǎng)的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Vue3實(shí)現(xiàn)九宮格抽獎(jiǎng)的功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的可以了解一下2022-09-09Vue3中SetUp函數(shù)的參數(shù)props、context詳解
我們知道setup函數(shù)是組合API的核心入口函數(shù),下面這篇文章主要給大家介紹了關(guān)于Vue3中SetUp函數(shù)的參數(shù)props、context的相關(guān)資料,需要的朋友可以參考下2021-07-07vue3中實(shí)現(xiàn)異步組件的方法實(shí)例
前端開(kāi)發(fā)經(jīng)常遇到異步的問(wèn)題,請(qǐng)求函數(shù)、鏈接庫(kù)等,下面這篇文章主要給大家介紹了關(guān)于vue3中實(shí)現(xiàn)異步組件的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06