首先实现递归checkbox的组件
假定,我们要实现的权限组件效果是这样的:
要实现点击系统,下面的都全选,点击基础功能,用户管理半选,系统半选。点击新增组织,如果基础功能没有选中,则基础功能改为选中。
{{datas.title}}
{{datas.title}}
基础功能
0" @pchange="permitCheck" :key="d.id">
{{d.title}}
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.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
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.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.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");
}
}
}
.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;}
之后需要在这个组件外面套一层组件,提供一个方法来获取选中的checkbox
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
let tmp=keys[i];
if(tmp.checkState){
arr.push(tmp.id);
}
if(tmp.childResoList.length>0){
this.getCheckedByCircle(tmp.childResoList,arr);
}
}
return arr;
}
}
}
第二个组件上面的v-for是因为权限要像tab页签一样分多个模块,根据模块的选中状态展现不同的权限选项。