最近的业务需求是在下拉框中展示树形菜单,显然原生element中的select组件无法实现这种功能,我在查找方法的时候发现使用popover可以实现弹出框的样式,接下来的工作就是讲树形菜单封装入popover中。记录一下封装的思考过程。
tree封装
对于element多样的组件中,说到树形菜单当然第一个想到的就原生的tree组件。
于是便先使用tree组件进行树形展示。代码如下:1
2
3
4
5
6<el-popover trigger="click" placement="bottom" :visible-arrow="false"
v-model="treepopover" width="518">
<el-tree :data="treeData" highlight-current></el-tree>
<el-input slot="reference" readonly style="width:517px" placeholder="请选择" v-model="selectData" @node-click="clickTreeNode">
</el-input>
</el-popover>
1 | export default{ |
页面:
原生tree组件页面展示还是很好看的,但是也可以看出此时选中父节点也是会有高亮的。
因为大部分业务需求中父节点一般都只做展示,并不可选,但是tree中父节点高亮选择是无法修改的,如果想要不展示父节点高亮就只能在生成树时添加class并进行一系列处理,过于麻烦。
虽然element原生tree中有一系列的方法和功能,对我之前的业务实现中来说在页面中能直接不作任何修改的使用原生tree组件几乎是不可能的,于是此时我的目光就投向了也能实现树形结构并且功能可控的折叠面板组件。
折叠面板封装
使用折叠面板封装需要对数据进行循环遍历,代码如下:1
2
3
4
5
6
7
8
9
10
11
12<el-popover trigger="click" placement="bottom" :visible-arrow="false"
v-model="collpopover" width="518" class="coll-tree">
<el-collapse class="custom-coll">
<el-collapse-item :show-border="false"
v-for="(item,index) in treeData" :title="item.label" :key="index">
<p v-for="(title,subIndex) in item.children" :class="{'selected-label': title.label === selectData}"
:key="subIndex" @click="selectTitle(title)">{{title.label}}</p>
</el-collapse-item>
</el-collapse>
<el-input slot="reference" readonly style="width:517px" v-model="selectData" placeholder="请选择">
</el-input>
</el-popover>
1 | export default{ |
完成的页面:
可以看出此时选择父节点并不会绑定到model中,已经实现了我的业务需要。
样式优化
虽然使用折叠面板看起来像那么一回事了,但是总觉得有一点丑,再根据原生select下拉框修改一下页面样式,代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38.custom-coll {
border: none;
}
.custom-coll .el-collapse-item__header {
height:30px;
line-height: 30px;
border: none;
}
.custom-coll .el-collapse-item__arrow {
line-height: 30px;
}
.custom-coll .el-collapse-item__content, .custom-coll .el-collapse-item__wrap {
border: none;
}
.custom-coll .el-collapse-item__content {
padding: 0;
}
.custom-coll p {
height:30px;
line-height: 30px;
padding-left: 36px;
margin:0;
}
.custom-coll p:hover {
cursor: pointer;
background-color: #f5f7fa;
}
.custom-coll p.selected-label {
color: #409EFF;
font-weight: 700;
}
页面:
看起来好多了!不过在观察原生select发现它还有一个随着下拉框展开和隐藏时一起动态改变的小箭头。如何实现这个功能呢?
这里提供了两个方法:
使用el-select class
观察原生select组件的css实现可以发现其箭头的转换是通过el-select类选择器定位的:
所以第一种取巧方法是直接在Input上层中添加el-select的class,并在input行添加箭头slot,并使用popover的出现和隐藏对箭头添加is-reverse,便可以直接借用select中的css样式控制箭头的动画了。代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<el-popover trigger="click" placement="bottom" :visible-arrow="false"
v-model="collpopover" width="518" class="el-select">
<el-collapse class="custom-coll">
<el-collapse-item :show-border="false"
v-for="(item,index) in treeData" :title="item.label" :key="index">
<p v-for="(title,subIndex) in item.children" :class="{'selected-label': title.label === selectData}"
:key="subIndex" @click="selectTitle(title)">{{title.label}}</p>
</el-collapse-item>
</el-collapse>
<el-input slot="reference" readonly style="width:517px" v-model="selectData"
placeholder="请选择">
<i slot="suffix" class="el-select__caret el-input__icon el-icon-arrow-up"
:class="{'is-reverse' : collpopover}"></i>
</el-input>
</el-popover>
自定义css样式
第二种方法是在popover中添加自定义的coll-tree class,并在css中自己加入控制箭头动画的css,这种方法比第一种麻烦,但更可控。代码如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15.coll-tree .el-input, .coll-tree .el-input input {
cursor: pointer;
}
.coll-tree .el-input .el-select__caret {
color: #c0c4cc;
font-size: 14px;
transition: transform .3s;
transform: rotate(180deg);
cursor: pointer;
}
.coll-tree .el-input .el-select__caret.is-reverse {
transform: rotate(0deg);
}
页面实现
两种方法实现后的动图如下。大功告成,你已经是一个成熟的树形选择框了。