vue结合element UI做checkbox全选的tree结构

由于element UI中的tree可能不能满足项目中的样式需求,所以自己动手结合element中的checkbox全选功能实现了一个符合项目需求的tree。效果如下:


废话不多说,直接上代码

html部分

<template>  
    <div class="tree-container">    
        <div v-for="(item,index) in menus" :key="index">      
            <p class="toggleIcon" @click="toggleShow(item)">{{item.isShowAll?'-':'+'}}</p>      
            <el-checkbox :indeterminate="item.isIndeterminate" v-model="item.checkAll" @change="((val)=>{handleCheckAllChange(item,val)})">        
                {{item.name}}      
            </el-checkbox>      
            <span class="checkBox-num">{{item.num}}</span>      
            <el-checkbox-group v-model="item.checkedCities" @change="((val)=>{handleCheckedCitiesChange(item,val)})" class="checkGroup"  v-if="item.isShowAll">        
                <el-checkbox v-for="(it,i) in item.userList" :key="i" :label="it.num" @change="((val)=>{handleCheckedOne(it,val)})">          
                    <label class="icon-zhu" v-if="it.telType == '移动电话' && numList.indexOf(it.num)>=0 ">            
                        <span :class="numList[0] === it.num?'colorful-icon':''"></span>          
                    </label>          
                    <label class="tree-text">
                        {{it.telType}}
                        <span v-if="it.cardType">({{it.cardType}})</span>
                    </label>          
                    <label class="tree-text">{{it.num}}</label>          
                    <label class="tree-text">{{it.label}}</label>        
                </el-checkbox>      
            </el-checkbox-group>    
        </div>  
    </div>
</template>复制代码

js部分

export default {
	name: "Tree",
	props: ["menus", "formData", "numList"],
	methods: {
		// 是否展开checkbox      
		toggleShow(item) {
			item.isShowAll = !item.isShowAll;
		}, handleCheckAllChange(item, val) {
			if (val) {
				item.userList.map(it = > {
					let numIndex = this.numList.indexOf(it.num);
					item.checkedCities.push(it.num);
					this.formData.userNum = Array.from(new Set(this.formData.userNum.concat(item.checkedCities)));
					if (it.telType == "移动电话") {
						this.numList.push(it.num);
					}
				});
			} else {
				item.userList.map(it = > {
					let Index = this.formData.userNum.indexOf(it.num);
					let numIndex = this.numList.indexOf(it.num);
					if (Index > -1) {
						this.formData.userNum.splice(Index, 1);
					}
					if (numIndex > -1) {
						this.numList.splice(numIndex, 1);
					}
				});
				item.checkedCities = [];
			}
			item.isIndeterminate = false;
		}, handleCheckedCitiesChange(item, val) {
			let checkedCount = val.length;
			item.checkAll = checkedCount === item.userList.length;
			item.isIndeterminate = checkedCount > 0 && checkedCount < item.userList.length;
		}, handleCheckedOne(item, val) {
			let Index = this.formData.userNum.indexOf(item.num);
			let numIndex = this.numList.indexOf(item.num);
			//如果找到了,有此值        
			if (Index > -1) {
				this.formData.userNum.splice(Index, 1);
			} else {
				this.formData.userNum.push(item.num);
			}
			if (item.telType == "移动电话") {
				if (numIndex > -1) {
					this.numList.splice(numIndex, 1);
				} else {
					this.numList.push(item.num);
				}
			}
		}
	}
};
复制代码

css样式

<style lang="scss" scoped>  @import "../../../assets/css/base.scss";
  .tree-container {
      width: 100%;
      position: relative;
      padding: 10px;
      &>div {      
	margin-left: 20px;
      }

    .toggleIcon {
	width: 14px;
	height: 14px;
	border: 1px solid #dcdcdc;
	@include wordStyle(#dcdcdc, 14px, 600);      text-align: center;
	line-height: 11px;
	cursor: pointer;
	position: absolute;
	left: 10px;
	margin-top: 10px;
    }

    .checkGroup {
	display: flex;
	flex-direction: column;
	padding-left: 20px;
    }
    /deep/ .el-checkbox {
	&+.el-checkbox {        
	    margin-left: 0;
	}    
    }
    /deep/ .el-checkbox__inner {
	&: hover {        
	    border-color: #ed795a;
	}
	&:focus {
	    border: 1px solid #dcdfe6;
	    outline: none;
	}    
    }
    /deep/ .el-checkbox__input {
	&.is-checked,&.is-indeterminate {        
	    .el-checkbox__inner {          
		background-color: #ed795a;
		border-color: #ed795a;
	    }      
	}
	&.is-checked {
	    &+.el-checkbox__label {          
	        color: #ed795a;
	    }      
	}   
    }
    /deep/ .el-checkbox__label {
	font-size: 12px;
	padding-left: 0;
    }
    /deep/ .el-checkbox {
	position: relative;
    }

    .icon-zhu {
	position: absolute;
	left: -24px;
	span {        display: inline-block;
	width: 18px;
	height: 18px;
	line-height: 18px;
	text-align: center;
	border-radius: 100%;
	color: #fff;
	font-weight: bold;
	background-color: #ccc;
    }

    .colorful-icon {
	background-color: #ed795a;
    }  
    .checkBox-num {
	position: absolute;
	right: 10px;
	font-size: 12px;
    }  
}
</style>复制代码

数据类型如下

menus: [{
	id: "1",
	name: "不限量173套餐",
	num: "23789446464646",
	checkAll: false,
	checkedCities: [],
	//v-model绑定          
	isIndeterminate: false,
	//设置 indeterminate 状态,只负责样式控制          
	isShowAll: true,
	//控制展开和收缩的状态          
	userList: [{
		id: "1.1",
		username: "html",
		role: "主管",
		telType: "移动电话",
		cardType: "主号",
		label: "现行",
		num: "17316065935"
	}, {
		id: "1.2",
		username: "vue",
		role: "普通",
		telType: "有线宽带",
		cardType: "",
		label: "现行",
		num: "hz87654321"
	}, {
		id: "1.3",
		username: "vue",
		role: "普通",
		telType: "移动电话",
		cardType: "副号",
		label: "现行",
		num: "17316065937"
	}]
}, {
	id: "1",
	name: "不限量199套餐",
	num: "23789446464646",
	checkAll: false,
	checkedCities: [],
	//v-model绑定          
	isIndeterminate: false,
	//设置 indeterminate 状态,只负责样式控制          
	isShowAll: true,
	userList: [{
		id: "1.1",
		username: "html",
		role: "主管",
		telType: "有线宽带",
		cardType: "",
		label: "现行",
		num: "hz1234567"
	}, {
		id: "1.2",
		username: "vue",
		role: "普通",
		telType: "移动电话",
		cardType: "副号",
		label: "现行",
		num: "19916065934"
	}, {
		id: "1.3",
		username: "vue",
		role: "普通",
		telType: "移动电话",
		cardType: "副号",
		label: "现行",
		num: "19916065936"
	}]
}]
复制代码


转载于:https://juejin.im/post/5c2dc09fe51d45206d1281b9

Vue 3中,Element UI (简称ElTree) 提供了一个树形组件,可以方便地处理节点的选择操作,包括全选功能。要在`<el-tree>`组件中实现全选,通常你需要在数据结构中维护每个节点的选中状态,并配合`@selection-change`事件监听节点选择的变化。 下面是一个简单的例子: ```html <template> <el-tree :data="treeData" ref="treeRef" :check-strictly="true" // 设置严格模式,只允许从根节点开始逐级展开并选中 @selection-change="handleSelectionChange" > <!-- 树节点模板 --> <span slot-scope="{ node, $event }"> {{ node.label }} <el-checkbox v-model="node.checked"></el-checkbox> </span> </el-tree> </template> <script setup> import { ref, onMounted } from 'vue'; const treeData = ... // 你的树形数据结构,其中包含 checked 属性表示是否选中 const treeRef = ref(null); let selectedNodes = ref([]); // 存储当前选中的所有节点 onMounted(() => { // 初始化选中状态,如果需要全选,这里设置所有节点为选中 selectedNodes.value = treeData.map(node => ({ ...node, checked: true })); }) function handleSelectionChange(selection) { // 当节点选中状态发生变化时,更新selectedNodes selectedNodes.value = selection; // 如果你想实现全局的全选/反选,可以在这里判断是否所有节点都被选中 if (selection.length === treeData.length) { // 全选或反选操作 treeRef.value.selectAll(); // 全选 treeRef.value.clearSelection(); // 反选 } } </script> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值