el-tree中支持Shift多选时统一改变背景颜色的自定义实现
背景
在搜索了半个小时后,发现并没有现成的关键词来简单实现在el-tree中用键盘shift
执行多选。
于是考虑自定义实现。
上述功能有两个方面:
- 按住
Shift
键多选后,el-tree对应详情内容的选择,以执行批量操作。 - 按住
Shift
键多选后,el-tree上背景颜色的改变,以使用户感知到多选的功能。
其中,第1点极度依赖业务逻辑,但是第2点倒可以提取出来统一性的实现方式。
其难点在于:
- 需要使用CSS的动态绑定类选择器控制是否展示对应样式。
- el-tree自动生成的DOM结构是有复杂的包含结构的,怎么通过子选择器控制父选择器的样式(下文的“需求分析”有解释)。
实现代码之HTML
话不多说,实现代码粘贴如下,后跟解释。
<el-tree
:data="dataList"
node-key="index"
highlight-current
check-on-click-node
default-expand-all
:props="{ label: 'name' }"
>
<div class="data-list" slot-scope="{ node, data }" >
<div
:class="{ active: data.isSelected }"
@click="handleSelectData(data, node)"
>
<div class="data-list-item-content">
<span class="data-list-item-content-icon">
<i class = "icon"></i>
</span>
<span class="data-list-item-content-name">{{node.label}}</span>
</div>
<div class = "multiBackChange"></div>
</div>
</div>
</el-tree>
代码逐行解释
首先,前8行是el-tree
组件的引用,使用方式可见Tree树形控件官方文档。
<div class="data-list" slot-scope="{ node, data }" >
然后,使用 scoped slot 会传入两个参数node
和data
,分别表示当前节点的 Node 对象和当前节点的数据。(tree 组件依赖 data 数据,所以需要把数据从数组结构转成 tree 结构)
<div
:class="{ active: data.isSelected }"
@click="handleSelectData(data, node)" >
再然后,诶!到了一个精巧之处,使用isSelected
这个变量值来控制是否展示active
类的样式。并设置点击事件handleSelectData
,在此方法中完成根据Shift键改变isSelected
的值(True/False)。
<div class="data-list-item-content">
<span class="data-list-item-content-icon">
<i class = "icon"></i>
</span>
<span class="data-list-item-content-name">{{node.label}}</span>
</div>
此处的内容为每一个树节点所需要展示的内容,不必过多解释。
<div class = "multiBackChange"></div>
那么问题来了,这里为什么需要加这么一个只有class的div
?
需求分析
还记得我们的需求吗?我们需要的是当Shift
执行多选时,已选中的内容的背景颜色要改变。
- 假如没有特定背景色改变的需求,那么el-tree中有默认的单独选中的背景色(浅灰色)。
- 假如没有支持
Shift
多选的需求,那么如下代码可修改单选的背景色。
.el-tree-node:focus > .el-tree-node__content {
background: red
}
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
background: red
}
- 现在既有特定背景色的需求,又要支持多选。
实现思路:
我们在代码里通过绑定active
类来覆盖掉el-tree中默认背景色的改变,并且支持多选。
通过上面的代码分析,active
绑定在了data-list
的子元素内,如果只是设置active
的背景色,下图红色区域的背景色并不会改变。

然而我们想要的效果是树结构中的整个节点的背景色都改变(包括箭头区域),如下图所示。

但是,看控制台里的el-tree的结构,发现我们要实现的功能其实是“在CSS中实现父选择器的效果”!
如何在CSS中实现父选择器效果
实现方式为:
- 新建一个
multiBackChange
元素负责外观,放置在active
元素后,用absolute
拉伸和el-tree-content尺寸一致。 - 通过相邻兄弟选择器,控制样式变化。
所以,代码如下。
<div class = "multiBackChange"></div>
<style>
.attr-list {
...
z-index: 1;//这里要设置此元素在multiBackChange的上面,防止点击失效
...
}
.multiBackChange {
position : absolute;
right: 0;
top: 0;
height: 35.2px;
width: 238px;
display: none;
z-index: -1;
}
.active + .multiBackChange{
display: block;
background: rgba(44,104,255,0.1);
}
</style>
另外,别忘了重置el-tree里默认的背景颜色修改。
.el-tree-node:focus > .el-tree-node__content {
background: white
}
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
background: white
}
最后,全部代码如下所示。
<el-tree
:data="dataList"
node-key="index"
highlight-current
check-on-click-node
default-expand-all
:props="{ label: 'name' }"
>
<div class="data-list" slot-scope="{ node, data }" >
<div
:class="{ active: data.isSelected }"
@click="handleSelectAttr(data, node)"
>
<div class="data-list-item-content">
<span class="data-list-item-content-icon">
<i class = "icon"></i>
</span>
<span class="data-list-item-content-name">{{node.label}}</span>
</div>
<div class = "multiBackChange"></div>
</div>
</div>
</el-tree>
<style>
.attr-list {
...
z-index: 1;//这里要设置此元素在multiBackChange的上面,防止点击失效
...
}
.multiBackChange {
position : absolute;
right: 0;
top: 0;
height: 35px;
width: 238px;//这里的height和width大小都和el-tree中每个节点的大小一致
display: none;
z-index: -1;
}
.active + .multiBackChange{
display: block;
background: rgba(44,104,255,0.1);
}
//重置el-tree中默认的点击效果
.el-tree-node:focus > .el-tree-node__content {
background: white
}
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
background: white
}
</style>
<script>
handleSelectAttr(attr, node) {
...
attr.isSelected = true;
...//这里的逻辑自己写吧~~~
}
</script>
转载自:https://juejin.cn/post/7143230878213226509