一、前言
開發過程中,涉及到多級菜單的應用,樹形結構比較常見,今天就做了一個Spring Boot + Vue + Element-UI 實現樹形結構的一個小demo。
Tree組件最適合的結構是無序列列表ul,創建一個遞歸組件Item表示Tree選項,如果當前Item存在 children,則遞歸渲染子樹,以此類推;同時添加一個標識管理理當前層級item的展開狀態。
效果展示:
二、代碼實例
1、數據庫設計
2、實體類
一般樹形結構都是創建若干層實體類,然後通過list結合在一起,面向對象編程
一級實體類
@Data
public class OneSubject {
private String id;
private String title;
private List<TwoSubject> children = new ArrayList<>();
}
二級實體類
@Data
public class TwoSubject {
private String id;
private String title;
}
3、controller
@GetMapping("getAllSubject")
public R getAllSubject(){
List<OneSubject> list = subjectService.getAllOneTwoSubject();
return R.Ok().data("list",list);
}
4、service
//課程分類列表(樹形)
@Override
public List<OneSubject> getAllOneTwoSubject() {
//1 查詢所有一級分類
QueryWrapper<EduSubject> wrapperOne = new QueryWrapper<>();
wrapperOne.eq("parent_id","0");
List<EduSubject> oneSubjectList = baseMapper.selectList(wrapperOne);
//2 查詢所有2級分類
QueryWrapper<EduSubject> wrapperTwo = new QueryWrapper<>();
wrapperTwo.ne("parent_id","0");
List<EduSubject> twoSubjectList = baseMapper.selectList(wrapperTwo);
//創建list集合,用於存儲最終封裝數據
List<OneSubject> finalSubjectList = new ArrayList<>();
//3、封裝一級分類
for (int i = 0; i < oneSubjectList.size(); i++) {
EduSubject eduSubject = oneSubjectList.get(i);
OneSubject oneSubject = new OneSubject();
BeanUtils.copyProperties(eduSubject,oneSubject);
//在一級分類循環遍歷查詢所有的二級分類
//創建list集合封裝每一個一級分類的二級分類
List<TwoSubject> twoFinalSubjectList = new ArrayList<>();
for (int j = 0; j < twoSubjectList.size(); j++) {
EduSubject tSubject = twoSubjectList.get(j);
if(tSubject.getParentId().equals(oneSubject.getId())){
TwoSubject twoSubject = new TwoSubject();
BeanUtils.copyProperties(tSubject,twoSubject);
twoFinalSubjectList.add(twoSubject);
}
}
//把一級下面所有的二級分類放入一級分類中
oneSubject.setChildren(twoFinalSubjectList);
finalSubjectList.add(oneSubject);
}
//4、封裝二級分類
return finalSubjectList;
}
5、前端
JavaScript
import request from '@/utils/request'
export default {
//1 課程分類列表
getSubjectList() {
return request({
url: '/eduservice/subject/getAllSubject',
method: 'get'
})
}
}
Vue頁面
<template>
<div class="app-container">
<el-input v-model="filterText" placeholder="Filter keyword" style="margin-bottom:30px;" />
<el-tree
ref="tree2"
:data="data2"
:props="defaultProps"
:filter-node-method="filterNode"
class="filter-tree"
default-expand-all
/>
</div>
</template>
<script>
import subject from '@/api/edu/subject'
export default {
data() {
return {
filterText: '',
data2: [], //返回所有分類數據
defaultProps: {
children: 'children',
label: 'title'
}
}
},
created() {
this.getAllSubjectList()
},
watch: {
filterText(val) {
this.$refs.tree2.filter(val)
}
},
methods: {
getAllSubjectList() {
subject.getSubjectList()
.then(response => {
this.data2 = response.data.list
})
},
filterNode(value, data) {
if (!value) return true
return data.title.toLowerCase().indexOf(value.toLowerCase()) !== -1
}
}
}
</script>