el-tree树形控件与el-tag标签,自定义封装下拉框

项目场景:

需求:一个下拉框,显示如图内容,点击确认选中数据展示在下拉框中,点击取消保持原数据不变,标签与树联动。


原因分析:

使用select与tree结合,不能完全满足设计图效果。所以选择自定义封装组件,

代码如下(小白一枚,欢迎指正):

<template>
	<div>
		<div ref="frame" class="select-frame" @click="showPanel = !showPanel;">
			<span v-if="sureName != ''" class="text">{{ sureName }}</span>
			<span v-else class="text" placeholder="请选择"></span>
			<i class="el-icon-arrow-down" :class="[showPanel ? 'is' : '']"></i>
		</div>
		<div ref="panel" class="select-panel" v-show="showPanel">
			<el-input v-model="filterText" placeholder="搜索关键字"></el-input>
			<span class="tag-title">已选<i>{{ valueName.length }}</i>人</span>
			<div class="tag-list">
				<el-tag v-for="(item, index) in valueName" :key="index" closable @close="handleChangeTag(item)">{{
					item.label }}</el-tag>
			</div>
			<el-tree ref="tree" class="tree-box" :data="data" show-checkbox node-key="id" :props="defaultProps"
				@check="handleNodeClick" :filter-node-method="filterNode">
			</el-tree>
			<div class="buttons">
				<el-button size="mini" @click="canselChangeNode">取 消</el-button>
				<el-button size="mini" @click="reseSelecttNode">重 置</el-button>
				<el-button type="primary" size="mini" @click="sureSelectNode">确 认</el-button>
			</div>
		</div>
	</div>
</template>

<script>
export default {
	props: {
		// 数据集合
		options: {
			type: Array,
			default: () => {
				return []
			}
		},
		// 初始值
		valueMultiple: {
			type: Array,
			default: () => {
				return []
			}
		}
	},
	data() {
		return {
			filterText: '',
			defaultProps: {
				children: 'children',
				label: 'label'
			},
			valueName: [], // 展示标签集合
			resultValue: [], // 传给父组件的数据集合
			sureName: '', // 下拉框显示数据
			showPanel: false, //显示选择面板
		};
	},
	watch: {
		filterText(val) {
			this.$refs.tree.filter(val);
		}
	},
	mounted() {
		// 监听点击事件
		document.addEventListener('click', this.clickOut, true)
	},
	methods: {
		// 查询节点
		filterNode(value, data) {
			if (!value) return true;
			return data.label.indexOf(value) !== -1;
		},
		// 点击其他地方,关闭选择框
		clickOut(e) {
			let frame = this.$refs.frame;
			let panel = this.$refs.panel;
			if (!frame.contains(e.target) && !panel.contains(e.target)) {
				this.showPanel = false;
			}
		},
		// 监听节点勾选情况
		handleNodeClick(node, select) {
			this.valueName = [];
			this.resultValue = [];
			// 获取目前选中节点
			select.checkedNodes.forEach((item) => {
				if (item.children == null || item.children == undefined) {
					this.valueName.push(item); // 标签集合
					this.resultValue.push(item.id) // 选中节点的id集合
				}
			})
		},
		// 监听选中标签改变 -删除标签
		handleChangeTag(tag) {
			this.valueName = this.valueName.filter((item) => { return item.id != tag.id });
			// 设置删标签对应-节点的勾选状态
			this.$refs.tree.setChecked(tag, false);
		},
		// 取消 不改变原来的选项
		canselChangeNode() {
			this.resultValue = [];
			this.valueMultiple.forEach((item) => { this.resultValue.push(item.id) })
			this.valueName = this.valueMultiple;
			this.sureName = this.valueName;
			// 还原设置选中节点
			this.$refs.tree.setCheckedNodes(this.valueMultiple);
			this.$emit('getValue', this.resultValue, this.valueMultiple)
			// 关闭下拉框
			this.showPanel = false;
		},
		// 重置
		reseSelecttNode() {
			// 清除选中节点
			this.$refs.tree.setCheckedKeys([]);
			this.valueName = [];
			this.resultValue = [];
		},
		// 确认
		sureSelectNode() {
			let name = []
			this.valueName.forEach((item) => { name.push(item.label) })
			this.sureName = name.toString();
			this.$emit('getValue', this.resultValue, this.valueName)
			this.showPanel = false;
		},

	}
}
</script>

<style lang="scss" scoped>
.select-frame {
	height: 34px;
	width: 240px;
	border: 1px solid #dddfe6;
	border-radius: 2px;
	line-height: 30px;
	padding: 0px 10px;
	cursor: pointer;

	i {
		float: right;
		color: #c0c4cc;
		margin-top: 8px;
	}

	.is {
		transform: rotate(-180deg);
		transition: all 0.5s;
	}

	.text {
		width: 180px;
		overflow: hidden;
		white-space: nowrap;
		text-overflow: ellipsis;
	}

	.text:empty::before {
		content: attr(placeholder);
		vertical-align: middle;
		color: #c0c4cc;
	}
}

.select-panel {
	width: 240px;
	margin-top: 5px;
	position: absolute;
	border: 1px solid #dddfe6;
	background-color: #fff;
	border-radius: 7px;
	padding: 10px;

	.tag-title {
		display: block;
		margin: 10px 0px;
		color: #636D91;
		font-size: 12px;

		i {
			color: #3470ff;
			margin: 0px 5px;
		}
	}

	.tag-list {
		max-height: 100px;
		overflow-y: auto;

		.el-tag {
			margin: 5px;
		}
	}

	.tree-box {
		max-height: 240px;
		border-top: 1px solid #Edf0f3;
		padding: 8px;
		overflow-y: auto;
	}

	.buttons {
		display: flex;
		justify-content: space-around;
		margin: 12px 0px;
		border-top: 1px solid #Edf0f3;
		padding-top: 10px;
	}

	::-webkit-scrollbar {
		width: 6px;
		height: 6px;
	}

	::-webkit-scrollbar-thumb {
		background-color: #eceef1;
	}
}
</style>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值