背景
后台管理系统菜单权限的配置通常使用el-tree组件进行展示,而el-tree默认展示节点方式是纵向排版的,而UI设计的权限菜单排版有时可能是横向分布的,此时不仅需要自定义el-tree的节点,而且还用通过js操作el-tree的dom方式动态设定样式才能达到预期的UI效果。
实现el-tree横向排列
效果
先看看要实现菜单权限树横向排列的效果吧:
实现
- 思路
使用el-tree的render-content属性通过函数式的方式自定义树节点,当中通过操作el-tree的dom的方式动态改变el-tree的样式,动态添加元素达到预期的效果 - 实现代码
html代码
<el-tree :data="menuTree" :props="defaultProps" default-expand-all :expand-on-click-node="false"
show-checkbox node-key="id" ref="menuTree" @check="getcheckNode"
:render-content="renderContent"
>
</el-tree>
js代码
renderContent(h, { node, data, store }){
console.log(node)
node.isLeaf=true
let classname=''
if(node.level==2){
classname='firstname'
}
if(node.level==4){
classname='levelname'
}
if(node.level==3){
classname='displayname'
}
if(this.isHasRadio(data)&&!this.isCheckBoxIdAryLoad&&this.getCheckedKeysArr.includes(data.id)){
return (
<p class={classname} style="display:flex;">
{node.label}
<div class="nodeCt">
<div class="nodeRight">
<el-checkbox style="margin-left:10px;" on-change={(v)=>{this.checkChange(v,data)}} checked={this.isSelCheck(this.isHasRadio(data))}></el-checkbox>
<span>管理者</span>
<el-tooltip class="item" effect="dark" placement="top">
<div slot="content" style="width:120px;">
{this.isHasRadio(data).remark}
</div>
<i style="color:grey;" class="el-icon-question"></i>
</el-tooltip>
</div>
</div>
</p>
)
}else{
return (
<p class={classname}>
{node.label}
</p>
)
}
},
changeCss() {
let levelName = document.getElementsByClassName('levelname') // levelname是上面的最底层节点的名字
let displayName=document.getElementsByClassName('displayname')
let firstName=document.getElementsByClassName('firstname')
for (let i = 0; i < levelName.length; i++) {
// cssFloat 兼容 ie6-8 styleFloat 兼容ie9及标准浏览器
levelName[i].parentNode.style.cssFloat = 'left' // 最底层的节点,包括多选框和名字都让他左浮动
levelName[i].parentNode.style.paddingLeft='1px'
levelName[i].parentNode.style.styleFloat = 'left'
levelName[i].parentNode.parentNode.parentNode.style.display='flex'
}
for(let i=0;i<displayName.length;i++){
displayName[i].parentNode.parentNode.style.display='flex'
displayName[i].parentNode.insertAdjacentHTML('afterend', `<span style="color: #C8C8C8;padding-left:20px;">|</span>`)
}
for(let i=0;i<firstName.length;i++){
if(firstName[i].parentNode.textContent!='首页'){
firstName[i].parentNode.insertAdjacentHTML('afterend',`<div style="color: #C8C8C8;border:solid 1px #EFEFEF;margin-left:60px;margin-top: 5px;margin-bottom: 5px;"></div>`)
}
firstName[i].parentNode.parentNode.insertAdjacentHTML('afterend',`<div style="color: #C8C8C8;border:solid 1px #EFEFEF;margin-top: 5px;margin-bottom: 5px;"></div>`)
}
},
showDialog(){
setTimeout(this.changeCss(),500)
}
- 代码解释
(1)首先需要更改el-tree不同层级的节点布局,为不同层级设置不同的类名,然后操作dom节点动态设置flex布局改变el-tree为横向布局。
let levelName = document.getElementsByClassName('levelname') // levelname是上面的最底层节点的名字
let displayName=document.getElementsByClassName('displayname')
let firstName=document.getElementsByClassName('firstname')
for (let i = 0; i < levelName.length; i++) {
// cssFloat 兼容 ie6-8 styleFloat 兼容ie9及标准浏览器
levelName[i].parentNode.style.cssFloat = 'left' // 最底层的节点,包括多选框和名字都让他左浮动
levelName[i].parentNode.style.paddingLeft='1px'
levelName[i].parentNode.style.styleFloat = 'left'
levelName[i].parentNode.parentNode.parentNode.style.display='flex'
}
for(let i=0;i<displayName.length;i++){
displayName[i].parentNode.parentNode.style.display='flex'
displayName[i].parentNode.insertAdjacentHTML('afterend', `<span style="color: #C8C8C8;padding-left:20px;">|</span>`)
}
(2)为一级菜单和每个模块添加下划线同样操作dom动态的在这些元素后插入下划线元素。
for(let i=0;i<displayName.length;i++){
displayName[i].parentNode.parentNode.style.display='flex'
displayName[i].parentNode.insertAdjacentHTML('afterend', `<span style="color: #C8C8C8;padding-left:20px;">|</span>`)
}
for(let i=0;i<firstName.length;i++){
if(firstName[i].parentNode.textContent!='首页'){
firstName[i].parentNode.insertAdjacentHTML('afterend',`<div style="color: #C8C8C8;border:solid 1px #EFEFEF;margin-left:60px;margin-top: 5px;margin-bottom: 5px;"></div>`)
}
firstName[i].parentNode.parentNode.insertAdjacentHTML('afterend',`<div style="color: #C8C8C8;border:solid 1px #EFEFEF;margin-top: 5px;margin-bottom: 5px;"></div>`)
}
(3)注意自定义节点函数中return中返回的html代码需要条件做判断时需要写在return外层不能写在return内部即根据不同条件返回不容模板内容。
if(this.isHasRadio(data)&&!this.isCheckBoxIdAryLoad&&this.getCheckedKeysArr.includes(data.id)){
return (
<p class={classname} style="display:flex;">
{node.label}
<div class="nodeCt">
<div class="nodeRight">
<el-checkbox style="margin-left:10px;" on-change={(v)=>{this.checkChange(v,data)}} checked={this.isSelCheck(this.isHasRadio(data))}></el-checkbox>
<span>管理者</span>
<el-tooltip class="item" effect="dark" placement="top">
<div slot="content" style="width:120px;">
{this.isHasRadio(data).remark}
</div>
<i style="color:grey;" class="el-icon-question"></i>
</el-tooltip>
</div>
</div>
</p>
)
}else{
return (
<p class={classname}>
{node.label}
</p>
)
}
(4)为防止样式不能更新到dom上建议设置延时器,指向样式变更相关操作。
showDialog(){
setTimeout(this.changeCss(),500)
}
(5)UI设计中没有el-tree的选择下拉按钮并且默认展开,处理设置el-tree默认展开,还要去除el-tree子节点的下拉箭头图标,只需在defaultProps中添加isLeaf属性,同时自定义节点将其设置为true即可。
data(){
return {
defaultProps: {
children: 'children',
label: 'label',
isLeaf: 'isLeaf'
},
}
}
methods:{
renderContent(h, { node, data, store }){
console.log(node)
node.isLeaf=true
}
}