網(wǎng)站開發(fā)招標(biāo)網(wǎng)絡(luò)輿情軟件免費(fèi)入口
文章目錄
- tree-selector
- 1. 新增表單組件
- 2. 在父組件中引用
- 3. 父組件添加新增按鈕
- 4. 樹形組件
- 4.1 前端代碼
- 4.2 后端代碼
前言:最近寫項(xiàng)目,發(fā)現(xiàn)了一些很有意思的功能,想寫文章,錄視頻把這些內(nèi)容記錄下。但這些功能太零碎,如果為每個(gè)功能都單獨(dú)搭建一個(gè)項(xiàng)目,這明顯不合適。于是我想,就搭建一個(gè)項(xiàng)目,把那些我想將的小功能全部整合到一起。實(shí)現(xiàn) 搭一次環(huán)境,處處使用。
本文主要實(shí)現(xiàn)一下兩個(gè)功能
- 新增表單, 更新表單組件編寫
- treeSelect樹形結(jié)構(gòu)編寫
環(huán)境搭建
文章鏈接
已錄制視頻
視頻鏈接
tree-selector
這個(gè)功能是table-tree功能的附屬產(chǎn)品。是為了能在新增表單中,更方便選擇上級(jí)節(jié)點(diǎn)所開發(fā)的功能。因此,我們得先把新增表單組件
開發(fā)出來
新增、修改邏輯
tree形組件
1. 新增表單組件
/src/views/welcome/treeAddOrUpdate.vue
<script setup lang="ts">
import { UnitEntity } from "@/api/tree";
import { ref, reactive } from "vue";
const dialogVisible = ref(false);let form = reactive(new UnitEntity());
const title = ref("新增表單");// 定義init方法, 讓父組件調(diào)用
const init = data => {console.log(data);if (data) {form = data;title.value = "編輯表單";} else {title.value = "新增表單";}dialogVisible.value = true;
};// 暴露方法
defineExpose({ init });// 提交表單
const submit = () => {console.log(form);
};
</script><template><el-dialog v-model="dialogVisible" :title="title"><el-form :model="form"><el-form-item label="單元"><el-input v-model="form.unit" /></el-form-item><el-form-item label="父id"><el-input v-model="form.pid" /></el-form-item></el-form><el-button @click="submit">提交</el-button></el-dialog>
</template><style lang="scss" scoped></style>
2. 在父組件中引用
/src/views/welcome/index.vue
<script setup lang="ts">
import { ref, onMounted, nextTick } from "vue";
import TreeAddOrUpdate from "./treeAddOrUpdate.vue";const dialogVisible = ref(false);// 引用子組件
const treeAddOrUpdateRef = ref();// ...
</script><template><!--ref引用組件--><tree-add-or-update v-if="dialogVisible" ref="treeAddOrUpdateRef" />
</template>
3. 父組件添加新增按鈕
/src/views/welcome/index.vue
<script setup lang="ts">
// 新增/修改 都可以使用該方法
const addOrUpdate = data => {console.log(data);dialogVisible.value = true;// nextTick保證treeAddOrUpdateRef能夠引用到子組件nextTick(() => {// 調(diào)用子組件暴露的init方法, 設(shè)置數(shù)據(jù)treeAddOrUpdateRef.value.init(data);});
};
</script><template><el-button type="primary" @click="addOrUpdate">新增</el-button>
</template>
完成以上步驟,我們就可以點(diǎn)擊新增表單,但這個(gè)界面對(duì)于用戶來說其實(shí)并不美好。誰知道父id是什么?因此我們采用tree-select的形式來提高界面的可使用性
4. 樹形組件
我們使用的是element plus的TreeSelect組件,具體文檔如下:[TreeSelect 樹形選擇 | Element Plus (element-plus.org)]()
4.1 前端代碼
- /src/api/tree.ts
export class LabelVo {
id: Number;
label: String;
value: String;
children: Array<LabelVo>;
}/** 獲取全部的treeLabel */
export const getLabelTree = () => {
return http.request<R<Array<LabelVo>>>("get",baseUrlApi("unit/listTreeSelect")
);
};/** 根據(jù)id查詢節(jié)點(diǎn) */
export const getNodeById = (id: Number) => {
return http.request<R<LabelVo>>("get", baseUrlApi(`unit/listNode?id=${id}`));
};
- /src/views/welcome/treeAddOrUpdate.vue
<template>
<el-tree-selectv-model="value":data="data"check-strictlyshow-checkbox@check-change="handleCheckChange"style="width: 240px"/>
</template><script>
// 定義init方法, 讓父組件調(diào)用
const init = data => {console.log(data);if (data) {form = data;title.value = "編輯表單";// 查詢上級(jí)節(jié)點(diǎn)數(shù)據(jù)(根據(jù)id返回{value, label, id})getNodeById(form.pid).then(res => {if (res.code === 0) {value.value = res.data.value;}});} else {title.value = "新增表單";}console.log(form);dialogVisible.value = true;
};const value = ref();
const data = ref<Array<LabelVo>>();const handleCheckChange = (data: LabelVo, checked, indeterminate) => {console.log(data);console.log(checked);if (checked) {form.pid = data.id;}
};
</script>
tip: init方法改動(dòng)
4.2 后端代碼
- 定義實(shí)體類
package com.fgbg.demo.vo;import lombok.Data;import java.util.List;@Data
public class LabelVo {private String label;private String value;private Integer id;private Integer pid;private List<LabelVo> children;
}
-
返回tree-selector展示所需數(shù)據(jù)
@RequestMapping("/listTreeSelect")public R listTreeSelect() {List<TbUnit> tbUnitList = unitService.list();List<LabelVo> list = tbUnitList.stream().map(e -> {LabelVo vo = new LabelVo();vo.setValue(e.getUnit());vo.setLabel(e.getUnit());vo.setId(e.getId());vo.setPid(e.getPid());return vo;}).collect(Collectors.toList());// TbUnit -> LabelVo// 建立map映射(id->index)HashMap<Integer, Integer> map = new HashMap<>();for (int index = 0; index < list.size(); index++) {Integer id = list.get(index).getId();map.put(id, index);}// ...for (int i = 0; i < list.size(); i++) {LabelVo node = list.get(i);Integer pid = node.getPid();// 有父親if (pid != null) {// 找到pid的父親, 并把當(dāng)前節(jié)點(diǎn)(node)添加到父親節(jié)點(diǎn)的children里面Integer indexParent = map.get(pid);// 獲取父親節(jié)點(diǎn)LabelVo parent = list.get(indexParent);if (parent.getChildren() == null) {parent.setChildren(new ArrayList<>());}// 向父親節(jié)點(diǎn)的children字段添加當(dāng)前nodeparent.getChildren().add(node);}}// 過濾出一級(jí)節(jié)點(diǎn)List<LabelVo> ans = list.stream().filter(e -> e.getPid() == null).collect(Collectors.toList());return R.ok().put("data", ans);}
-
根據(jù)id查詢數(shù)據(jù)
// 根據(jù)id查詢節(jié)點(diǎn)數(shù)據(jù){value id label}@RequestMapping("/listNode")public R listNode(@RequestParam Integer id) {TbUnit unit = unitService.getById(id);LabelVo labelVo = new LabelVo();labelVo.setLabel(unit.getUnit());labelVo.setValue(unit.getUnit());labelVo.setId(unit.getId());return R.ok().put("data", labelVo);}