使用element-ui的时间不短了,它的大部分功能都是很好用的,基本囊括了大部分常见的使用场景组件,最近项目上需要用到权限树这一块,但是element-ui的<el-tree>只是能展现和勾选,项目中要求将勾选的在右侧显示,于是在<el-tree>的基础上改造了一下,做成公用的组件,以便调用和扩展,先来图片欣赏下:
不多说,直接上代码:
//html部分
<template>
<div class="operation-tree-box" :style="boxStyle" :class="boxClass">
<el-form ref="operationForm" :model="userOperationForm" :rules="rules" label-width="0" class="operation-form">
<el-form-item label="" prop="defaultCheckedKeysArr">
<el-col :span="treeColspanNum">
<div class="tree-title" v-if="showTreeTitle"><slot :row="treeTitle" name="treeTitle">{{treeTitle}}</slot></div>
<div class="tree-box" :style="treeStyle">
<el-tree
ref="tree"
class="tree-content"
v-loading="vloading"
:default-expand-all="expandAll"
:show-checkbox="showCheckbox"
:node-key="nodeKey"
:data="treeData"
:default-checked-keys="userOperationForm.defaultCheckedKeysArr"
:props="props"
:render-content="renderContents"
@check="handleCheck"
></el-tree>
</div>
</el-col>
<el-col :span="hadChoseColspanNum" v-if="showHadChose">
<div class="had-chose-title" v-if="showHadChoseTitle">
<slot :row="hadChoseTitle" name="hadChoseTitle">{{hadChoseTitle}}</slot></div>
<div class="had-chose-box" :style="hadChoseStyle">
<ol class="had-chose-content">
<li v-for="item in hadChoseData" :key="item" >{{item.name}}</li>
</ol>
</div>
</el-col>
</el-form-item>
</el-form>
</div>
</template>
//js部分
import {Tree} from 'element-ui'
export default {
name:"operation-tree",
mixins:[Tree],
data(){
return {
vloading:false,
userOperationForm:{
defaultCheckedKeysArr:[]
},
rules:{
defaultCheckedKeysArr:[
{
validator:this.validator
}
]
},
treeData:[],
hadChoseData:[]
}
},
props:{
outData:{
type:Array,
default:()=>{
return []
}
},
originOperationIdArr:{
type:Array,
default:()=>{
return []
}
},
renderContents:{
type:Function,
default:(h, { node, data, store })=>{
if(node.level == 1){
if(node.expanded){
return (
<span class="custom-tree-node">
<i class="el-icon-folder-opened"></i>
<span class="label-item">{node.label}</span>
</span>
);
}else{
return (
<span class="custom-tree-node">
<i class="el-icon-folder"></i>
<span class="label-item">{node.label}</span>
</span>
);
}
}else if(node.level == 2){
return (
<span class="custom-tree-node">
<i class="el-icon-notebook-1"></i>
<span class="label-item">{node.label}</span>
</span>
);
}else{
return (
<span class="custom-tree-node">
<i class="el-icon-document"></i>
<span class="label-item">{node.label}</span>
</span>
);
}
}
},
expandAll:{
type:Boolean,
default:true
},
showCheckbox:{
type:Boolean,
default:true
},
props:{
type:Object,
default:()=>{
return {
label:'name'
}
}
},
loading:{
type:Boolean,
default:false
},
nodeKey:{
type:String,
default:'id'
},
validator:{
type:Function,
default:(rule,value,callback)=>{
if(value && value.length == 0){
return callback(new Error("至少选择一个权限!"))
}else{
return callback();
}
}
},
treeColspanNum:{
type:Number,
default:12
},
hadChoseColspanNum:{
type:Number,
default:12
},
boxStyle:{
type:Object,
default:()=>{
return {
width:'100%'
}
}
},
treeStyle:{
type:Object,
default:()=>{
return {}
}
},
hadChoseStyle:{
type:Object,
default:()=>{
return {}
}
},
boxClass:{
type:String,
default:''
},
showHadChose:{
type:Boolean,
default:true
},
showTreeTitle:{
type:Boolean,
default:true
},
showHadChoseTitle:{
type:Boolean,
default:true
},
treeTitle:{
type:String,
default:'所有权限'
},
hadChoseTitle:{
type:String,
default:'已选权限'
},
allDisabled:{
type:Boolean,
default:false
},
operationThen:{
type:Function,
default:()=>{
}
}
},
watch:{
loading(val){
this.vloading = val;
}
},
mounted(){
if(this.outData && this.outData.length){
this.setData(this.outData,this.originOperationIdArr);
}else{
this.loadRole(this.originOperationIdArr);
}
},
methods:{
deepForEachDisabled(rows){
rows.forEach((item,i)=>{
item.disabled = true;
if(item.children && item.children.length){
this.deepForEachDisabled(item.children);
}
})
},
setData(treeData,originOperationIdArr){
this.treeData = treeData;
this.userOperationForm.defaultCheckedKeysArr = originOperationIdArr;
if(this.showHadChose){
this.setHadChose();
}
if(this.allDisabled){
this.deepForEachDisabled(treeData);
}
this.$emit('operationThen',this.outData || treeData);
this.vloading = false;
},
loadRole(originOperationIdArr){
this.vloading = true;
this.$axios.get('/system/operation',{
params:{}
}).then(res=>{
this.$common.thenFactory({
res:res,
t:this
}).then((res)=>{
this.setData(res.data.content,originOperationIdArr);
})
}).catch(err=>{
this.$common.systemCatch(err,this)
})
},
setHadChose(){
this.$nextTick(()=>{
let tempChose = [];
this.$refs.tree.getCheckedNodes().forEach((item)=>{
if(item.leaf){
tempChose.push(item);
}
})
this.hadChoseData = tempChose;
})
},
handleCheck(currentNode,allCheckedNode){
let keys=[];
this.hadChoseData=[];
allCheckedNode.checkedNodes.forEach((item)=>{
keys.push(item.id);
if(item.leaf){
this.hadChoseData.push(item);
}
})
this.userOperationForm.defaultCheckedKeysArr = keys;
this.$refs.operationForm.validateField('defaultCheckedKeysArr');
this.$emit("check",currentNode,allCheckedNode);
}
}
}
//css部分
.operation-tree-box{
text-align: center;
}
.operation-tree-box .tree-box{
height:398px;
border:1px solid #DCDFE6;
overflow-y:auto;
overflow-x:hidden;
}
.operation-tree-box .tree-content{
padding:6px;
}
.operation-tree-box .operation-form{
display:inline-block;
width:100%;
min-width:25rem;
max-width:80rem;
}
.operation-tree-box /deep/ .el-tree-node .el-tree-node__content:hover,
.operation-tree-box /deep/ .el-tree-node .el-tree-node__content:active,
.operation-tree-box /deep/ .el-tree-node .el-tree-node__content:visited,
.operation-tree-box /deep/ .el-tree-node .el-tree-node__content:focus{
background-color:#FFF;
}
.operation-tree-box /deep/ .el-tree-node__expand-icon{
color:#000;
}
.operation-tree-box /deep/ .el-tree-node__expand-icon.is-leaf{
color:transparent;
}
.operation-tree-box /deep/ .custom-tree-node .label-item{
padding-left:5px;
}
.operation-tree-box .had-chose-box{
height:398px;
border:1px solid #DCDFE6;
border-left:none;
overflow-y:auto;
overflow-x:hidden;
}
.operation-tree-box .tree-title{
font-weight:bold;
border:1px solid #DCDFE6;
border-bottom:none;
}
.operation-tree-box .had-chose-title{
font-weight:bold;
border:1px solid #DCDFE6;
border-bottom:none;
border-left:none;
}
.operation-tree-box .had-chose-content{
text-align: left;
}
.operation-tree-box .had-chose-content >li{
height:1.625rem;
line-height: 1.625rem;
}
//引用
<template>
<v-operationtree
ref="operationTree"
:originOperationIdArr="originOperationIdArr"
:hadChoseTitle="hadChoseTitle"
@check="checkOperation"
></v-operationtree>
</template>
import vOperationtree from './operation-tree'
注意事项:
1、loadRole方法的请改成你自己的默认权限树请求链接,本组件支持外传数据进来的,可以在引用的时候传值给outData:[{},{},…]这样的形式即可;
2、其他参数多是沿用原来<el-tree>的参数,对照官网参数即可扩展,其中originOperationIdArr是默认选中的数据[1212,11212,21212]数组;allDisabled意思是所有checkbox都禁用,在仅支持查看的时候用到;
3、组件的具名slot插槽都是可以直接替换用的;
4、this.$common.thenFactory是小编自己的公共方法,你们只要拿到数据给setData()方法就可以了;
5、至于mixins混入Tree这个可以不要的,混入可以也有延迟,小编是经常执行了Tree里的方法拿不到值的,比如混入之后直接this.getCheckedNodes()去拿已选中的所有节点数组,经常拿到是空,方法调用没报错,但是取不到值,估计组件里面已经用过$nextTick;还是用ref稳妥点,使用过程自己感受下;
6、小编更愿意给demo的,可vue组件运行需要安装node环境,这样就很为难了,不像以前只要个html静态文件就可以了,慢慢看吧;