vue多级权限组件的实现
2019-04-07 00:34

首先实现递归checkbox的组件

假定,我们要实现的权限组件效果是这样的:

webwxgetmsgimg (1).jpg

要实现点击系统,下面的都全选,点击基础功能,用户管理半选,系统半选。点击新增组织,如果基础功能没有选中,则基础功能改为选中。

<template>
<div class="permit_cont">
	<div v-if="datas.childResoList.length>0" :class="{'top_check':datas.parentId==0}">
		<el-checkbox :indeterminate="isIndeterminate" v-model="datas.checkState" @change="handleCheckAllChange">{{datas.title}}</el-checkbox>
	</div>
	<el-checkbox v-else v-model="datas.checkState">{{datas.title}}</el-checkbox>
	<div v-if="datas.childResoList.length>0">
	<el-checkbox v-model="based" v-if='datas.parentId!=0' @change='basecheck'>基础功能</el-checkbox>
		<template v-for="d in datas.childResoList">
		<permitnode :datas="d" v-if="d.childResoList.length>0" @pchange="permitCheck" :key="d.id"></permitnode>
		<el-checkbox v-else v-model="d.checkState" @change="leafcheck">{{d.title}}</el-checkbox>

		<div v-if="datas.parentId==0" class="permit_hr"></div>
	</template>
	</div>
	
</div>
</template>
<script>
export default{
	name:"permitnode",
	props:{
		datas:{
			type:Object,
			default:{}
		}
	},
	data(){
		return {
			isIndeterminate:false,
			childClick:true,
			based:true
		};
	},
	mounted(){
		this.based=this.datas.checkState;
		let count=0;
		//初始化时判断自身时全选还是半选
		this.datas.childResoList.forEach(it=>{
				if(it.checkState){
					count++;
				}
		});
		if(count>0&&count<this.datas.childResoList.length){
			this.isIndeterminate=true;
			this.datas.indeter=true;
		}
		if(count==0){
			this.isIndeterminate=false;
			this.datas.indeter=false;
		}
		if(count==this.datas.childResoList.length){
			this.isIndeterminate=false;
			this.datas.indeter=false;
		}
	},
	//watch是监听数据的变化,所以change引起树的下级变化,
	//下级变化调用leafcheck方法改变上层数据时,上层数据的值没有变,所以不会死循环
	watch:{
		"datas.checkState":function(val){
			//如果是半选状态,则表明是由子组件引起的变化,不进行全选操作
			if(this.datas.indeter==true){
				return ;
			}
			//递归watch过来时,取消本身的半选状态。
			this.isIndeterminate=false;
			this.based=val;
			//遍历全选子组件数据,子组件watch到变化全选算子组件
			for(let i=0;i<this.datas.childResoList.length;i++){
				let tmp=this.datas.childResoList[i];
				tmp.checkState=this.datas.checkState?true:false;
				if(tmp.childResoList&&tmp.childResoList.length>0){
					tmp.indeter=false;
					//全选时改变半选状态
				}
				this.datas.childResoList.splice(i,1,tmp);
			}
		}
	},
	methods:{
		handleCheckAllChange(val){
			//点击上面的全选按钮时,改变全选状态,出发watch变化
			this.isIndeterminate=false;//取消自身的半选状态
			this.datas.indeter=false;
			//向上触发事件,改变上层checkbox的变化
			this.$emit("pchange");
		},
		//子组件变化时触发的pchange事件
		permitCheck(){
			this.leafcheck();
		},
		//基础权限选中,则父权限选中,基础权限取消,则全部取消选中。
		basecheck(){
			if(this.based==false){
				this.datas.checkState=false;
				this.isIndeterminate=false;
				this.datas.indeter=false;
			}else{
				this.datas.checkState=true;
				this.isIndeterminate=true;
				this.datas.indeter=true;
			}
			this.$emit("pchange");
		},
		//叶子checkebox变化时,包括子组件变化
		leafcheck(val){
			let count=0;
			let hasIndeter=false;
			//计算选中的数值,是不是达成了全选的状态
			this.datas.childResoList.forEach(it=>{
				if(it.checkState){
					//判断其中是否有半选的
					if(it.indeter!=undefined){
						if(it.indeter==true){
							hasIndeter=true;
						}
					}
					count++;
				}
			});
			//parentId!=0不是第一级权限
			if(this.datas.parentId!=0){
				if(val&&this.based==false){
					this.based=true;
					this.datas.checkState=true;
				}
				//当checkbox选中时,这时候based必为true
				
				if(count<this.datas.childResoList.length){
					//this.datas.checkState=true;
					//indeter用来表示数据是否是显示为半选状态
					this.datas.indeter=true;
					this.isIndeterminate=true;
				}else{
					if(hasIndeter){
						this.datas.indeter=true;
						this.isIndeterminate=true;
					}else{
						this.datas.indeter=false;
						this.isIndeterminate=false;
					}
				}
			}else{
				console.log("count:"+count);
				if(count>0&&count<this.datas.childResoList.length){
					this.datas.indeter=true;
					this.isIndeterminate=true;
					this.datas.checkState=true;
					//indeter用来表示数据是否是显示为半选状态
					
				}
				//基础权限也没选中时
				if(count==0){
					this.datas.indeter=false;
					this.isIndeterminate=false;
					this.datas.checkState=false;
					
				}
				//因为选中和半选都是选中状态,所以要做一下半选显示状态的区分
				//全部选中,且没有半选显示状态的。
				if(count==this.datas.childResoList.length&&hasIndeter==false){
					this.datas.indeter=false;
					this.isIndeterminate=false;
					this.datas.checkState=true;
					
				}
				//全部选中,但是有是半选显示状态的
				if(count==this.datas.childResoList.length&&hasIndeter==true){
					this.datas.indeter=true;
					this.isIndeterminate=true;
					this.datas.checkState=true;
				}
			}
			//向上层反馈变化
			this.$emit("pchange");
		}
	}
}
</script>
<style scoped>
.permit_cont{color:#fff;font-size:12px;line-height: 2;}
.permit_hr{border-bottom: 1px solid #2F3B52;margin:10px 0;}
.top_check{margin-bottom:20px;}
</style>

之后需要在这个组件外面套一层组件,提供一个方法来获取选中的checkbox

<template>
<div>
    <permitNode v-if="c.id==rootId" :datas="c" v-for='c in chess' :key="c.id"></permitNode>
</div>
</template>
<script>
import permitNode from '@/components/public/permit_node'
export default{
	props:{
		chess:{
			type:Array,
			default:[]
		},
		rootId:{
			type:Number,
			defualt:0
		}
	},
	components:{
		permitNode
	},
	data(){
		return {
		};
	},
	methods:{
		//遍历获取树型数据中选中的checkbox的id
		getCheckedKey(){
			let arr=[];
			let keyarr=this.getCheckedByCircle(this.chess,arr);
			return keyarr;
		},
		getCheckedByCircle(keys,arr){
			for(let i=0;i<keys.length;i++){
				let tmp=keys[i];
				if(tmp.checkState){
					arr.push(tmp.id);
				}
				if(tmp.childResoList.length>0){
					this.getCheckedByCircle(tmp.childResoList,arr);
				}
			}
			return arr;
		}
	}
}
</script>

第二个组件上面的v-for是因为权限要像tab页签一样分多个模块,根据模块的选中状态展现不同的权限选项。

原创文章,转载请注明来自:妹纸前端-www.webfront-js.com.
阅读(318)
辛苦了,打赏喝个咖啡
微信
支付宝
妹纸前端
妹纸前端工作室 | 文章不断更新中
京ICP备16005385号-1