el-select 和el-tree二次封装

devtools/2024/11/25 6:06:21/

前言

本文章是本人在开发过程中,遇到使用树形数据,动态单选或多选的需求,element中没有这种组件,故自己封装一个,欢迎多多指教

开发环境:element-UI、vue2

组件效果

单选

多选

组件引用

<treeselect v-model="form.parentId":options="deptOptions":props="{value:'id',label:'name',children: 'children'}":placeholder="'选择上级部门'"/>

组件代码

<template><div><el-selectref="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-treeid="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: '请选择'},multipleLimit: {type: Number,default: 2},//--------- filter props -----filter: {type: Boolean,default: true},filterPlaceholder: {type: String,default: '请输入关键字'},//----- 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] : undefinedif (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 > 1this.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()},// 初始化滚动条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 = thisfunction 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 = thisfor (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 = labelsthis.option.name = labels.join()} else {this.valueLabel = labels.length > 0 ? labels[0] : undefinedthis.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 truereturn data[this.props.label].indexOf(value) !== -1},/* 树节点点击事件 */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 + '项')}}},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>

http://www.ppmy.cn/devtools/136765.html

相关文章

C++知识整理day2类与对象(上)——类的定义、实例化、this指针、构造、析构、拷贝构造函数

文章目录 1.类的定义1.1 类定义的格式1.2 访问限定符1.3 类域 2.实例化2.2 对象大小 3.this指针4.类的默认成员函数5.构造函数6. 析构函数7.拷贝构造函数 1.类的定义 1.1 类定义的格式 class为定义类的关键字&#xff0c;Stu为类的名字&#xff0c;{}中为类的主体&#xff0c;…

C++ 编程指南06 - 不要泄漏任何资源

一&#xff1a;概述 资源泄漏是指程序在运行过程中分配了某些资源&#xff08;如内存、文件句柄、网络连接等&#xff09;&#xff0c;但未正确释放或归还&#xff0c;导致这些资源持续占用&#xff0c;无法被其他部分使用。 例如&#xff1a; 动态分配的内存未释放。打开的文…

理解设计模式与 UML 类图:构建稳健软件架构的基石

在软件开发的广阔天地里&#xff0c;设计模式与 UML&#xff08;统一建模语言&#xff09;类图犹如两座灯塔&#xff0c;为开发者照亮前行的道路&#xff0c;指引着我们构建出高质量、可维护且易于扩展的软件系统。今天&#xff0c;就让我们一同深入探索单一职责、开闭原则、简…

SouVR Feedback force7 力反馈设备

Feedback force7力反馈的末端执行器涵盖了人类手部的自然运动范围&#xff0c;设计与双手控制的操作台兼容。 全重力补偿和无漂移校准相结合有助于提高用户的舒适度和准确性&#xff0c;专为对于性能和可靠性至关重要的苛刻应用而设计。 产品的可靠性、可操作性、先进性 独特的…

读写分库分表

主数据库负责写&#xff0c;从数据库负责读&#xff0c;主库和从库间会进行数据同步&#xff0c;以保证库中数据的准确性。 读写分离&#xff08;极客时间Mysql45讲读写分离&#xff09; 如何实现&#xff1f; 步骤&#xff1a; 部署多台数据库&#xff0c;选择其中的一台作…

Perforce《2024游戏技术现状报告》Part3:生成式AI、版本控制、CI/CD等游戏技术的未来趋势与应用

游戏开发者一直处于创新前沿。他们的实践、工具和技术受到各行各业的广泛关注&#xff0c;正在改变着组织进行数字创作的方式。 近期&#xff0c;Perforce发布了《2024游戏技术现状报告》&#xff0c;通过收集来自游戏、媒体与娱乐、汽车和制造业等高增长行业的从业者、管理人…

241124_文本解码原理

241124_文本解码原理 一个文本序列的概率分布可以分解为每个词基于其上文的条件概率的乘积。 Greedy search 就是每步都选择概率最大的&#xff0c;不会去考虑全局 按照贪心搜索输出the nice woman 的概率就是0.5*0.40.2 这种方法简单&#xff0c;但也存在问题&#xff0c;比…

ubuntu 交叉编译arm架构的mysql

在 Ubuntu 上使用 gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu 交叉编译 MySQL demo 应用到 ARM 开发板,涉及多个步骤。以下是详细步骤,从安装交叉编译工具链,到编写和编译 MySQL demo 代码,并最终将其部署到 ARM 开发板。 设置交叉编译工具链 首先,确保已经安装了…