在使用vue2前端页面开发的时候,会用到树形的列表展示数据,使用VueTreeselect可以更加美观的展示数据
VueTreeselect 官方中文地址:Vue-Treeselect | Vue-Treeselect 中文网 (javasoho.com)
默认的基础使用请参考官方的入门文档
很多小伙伴都有使用 RuoYi 框架,其中部门管理中就有使用到本文的主角 VueTreeselect
数据组装
获取数据都是后端返回给我们,但是有些时候后端没有给我们组装好固定的格式,还是需要我们自己手动组装。
其中后端组装数据核心代码
/**
* Stream分组
*/
@Override
public List<Menu> selectMenuTree() {
List<Menu> menus = menuMapper.selectList(null);
//操作所有菜单数据
Map<Long, List<Menu>> groupMap = menus.stream().collect(Collectors.groupingBy(Menu::getParentId));
menus.forEach(menu -> {
menu.setChildren(groupMap.get(menu.getMenuId()));
});
List<Menu> collect = menus.stream().filter(menu -> menu.getParentId().equals(0L)).collect(Collectors.toList());
return collect;
}
很多时候我们前端需求的数据是不需要后端处理好,而是需要自己手动处理。
Javascript核心代码
getDeptList() {
apiGetDeptList().then((res) => {
let { data } = res;
let list = data.map((item) => ({
id: item.deptId,
label: item.deptName,
parentId: item.parentId,
children: []
}));
this.deptOptions = list2tree(list);
});
}
解构 VueTreeselect 需要的字段,然后调用 list2tree 方法,list 转 tree 和 tree 转 list 代码如下
/**
* list 转 tree
* @param list
* @returns {*[]}
*/
export function list2tree(list) {
const [map, tree] = [{}, []];
list.forEach((item) => {
map[item.id] = item;
});
list.forEach((item) => {
const parent = map[item.parentId];
if (parent) {
(parent.children || (parent.children = [])).push(item);
} else {
tree.push(item);
}
});
return tree;
}
/**
* tree 转 list
* @param tree
* @returns {*[]}
*/
export function tree2list(tree) {
const list = [];
const stack = [...tree];
console.log(stack);
while (stack.length) {
const node = stack.pop();
const children = node.children;
if (children) {
stack.push(...children);
}
list.push(node);
}
return list;
}
以上数据就处理好了
样式调整
在调整样式的时候,我们点击后出现选项框,但是用鼠标去选择 class 样式的时候,就自动消息了,可以为其添加 :always-open="true" 属性。这里我直接先贴出我最终修改的样式
.el-input--small ::v-deep .vue-treeselect__control {
height: 32px;
}
.vue-treeselect ::v-deep .vue-treeselect__control {
padding-left: 10px;
border-radius: 4px;
display: flex;
align-items: center;
.vue-treeselect__value-container {
.vue-treeselect__placeholder {
display: flex;
align-items: center;
}
.vue-treeselect-helper-hide {
display: none !important;
}
.vue-treeselect__single-value {
color: #606266;
display: flex;
align-items: center;
}
.vue-treeselect__input-container {
.vue-treeselect__input {
display: flex;
align-items: center;
}
}
}
.vue-treeselect__x-container {
margin-left: -20px;
z-index: 1;
}
}
.vue-treeselect ::v-deep .vue-treeselect__menu-container {
label {
font-weight: normal;
color: #606266;
}
.vue-treeselect__menu {
margin-top: -3px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
.vue-treeselect__list {
padding-left: 5px;
.vue-treeselect__list-item {
.vue-treeselect__option--disabled {
.vue-treeselect__label-container {
label {
background-color: #f5f5f5;
color: rgba(0, 0, 0, 0.25);
}
}
}
}
}
}
}
以上css解决的问题:
- 统一了 vue-treeselect 和 input 的 border-radius 样式
- 调整了 vue-treeselect 默认展开字体加粗
- 统一了 vue-treeselect 和 input 文本内容距离左边的宽度
- 为 vue-treeselect 添加 class 样式,class="el-input--small",统一了长度
- 添加定位,使文本垂直居中对齐
- 修改选项禁用样式统一
最终的样式如下
其他信息记录
- 选项禁用:添加 isDisabled: true
- 默认全部展示::defaultExpandLevel="Infinity"
- 修改无数据的提示信息:noOptionsText="暂无数据"
- 去掉 children=null 的属性
<treeselect
v-model="form.parDeptId"
:defaultExpandLevel="Infinity"
:normalizer="normalizer"
:options="deptOptions"
:show-count="false"
noOptionsText="暂无数据"
placeholder="请选择上级部门"
/>
normalizer(node) {
//去掉children=null的属性
if (node.children == null || (node.children && !node.children.length)) {
delete node.children;
}
},
第一次写作………………