【前后端的那些事】treeSelect树形结构数据展示

news2024/9/24 15:22:58

文章目录

    • tree-selector
      • 1. 新增表单组件
      • 2. 在父组件中引用
      • 3. 父组件添加新增按钮
      • 4. 树形组件
        • 4.1 前端代码
        • 4.2 后端代码

前言:最近写项目,发现了一些很有意思的功能,想写文章,录视频把这些内容记录下。但这些功能太零碎,如果为每个功能都单独搭建一个项目,这明显不合适。于是我想,就搭建一个项目,把那些我想将的小功能全部整合到一起。实现 搭一次环境,处处使用。

本文主要实现一下两个功能

  1. 新增表单, 更新表单组件编写
  2. treeSelect树形结构编写

环境搭建
文章链接

已录制视频
视频链接

tree-selector

这个功能是table-tree功能的附属产品。是为了能在新增表单中,更方便选择上级节点所开发的功能。因此,我们得先把新增表单组件开发出来

新增、修改逻辑
在这里插入图片描述

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方法, 让父组件调用
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(() => {
    // 调用子组件暴露的init方法, 设置数据
    treeAddOrUpdateRef.value.init(data);
  });
};
</script>

<template>
	<el-button type="primary" @click="addOrUpdate">新增</el-button>
</template>

完成以上步骤,我们就可以点击新增表单,但这个界面对于用户来说其实并不美好。谁知道父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")
);
};

/** 根据id查询节点 */
export const getNodeById = (id: Number) => {
return http.request<R<LabelVo>>("get", baseUrlApi(`unit/listNode?id=${id}`));
};
  • /src/views/welcome/treeAddOrUpdate.vue
<template>
<el-tree-select
          v-model="value"
          :data="data"
          check-strictly
          show-checkbox
          @check-change="handleCheckChange"
          style="width: 240px"
        />
</template>

<script>
// 定义init方法, 让父组件调用
const init = data => {
  console.log(data);
  if (data) {
    form = data;
    title.value = "编辑表单";
    // 查询上级节点数据(根据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方法改动

4.2 后端代码
  • 定义实体类
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展示所需数据

        @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的父亲, 并把当前节点(node)添加到父亲节点的children里面
                    Integer indexParent = map.get(pid);
                    // 获取父亲节点
                    LabelVo parent = list.get(indexParent);
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>());
                    }
                    // 向父亲节点的children字段添加当前node
                    parent.getChildren().add(node);
                }
            }
            // 过滤出一级节点
            List<LabelVo> ans = list.stream().filter(e -> e.getPid() == null).collect(Collectors.toList());
            return R.ok().put("data", ans);
        }
    
    
  • 根据id查询数据

        // 根据id查询节点数据{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);
        }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1380520.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(十一)IIC总线-AT24C02-EEPROM

文章目录 IIC总线篇AT24C02-EEPROM篇主要特性引脚说明AT24Cxx用几位数据地址随机寻址的(存储器组织)AT24C02设备操作AT24CXX设备寻址EEPROM写操作的种类EEPROM读操作的种类实现单字节写实现任意读读写应用 IIC总线篇 前面介绍过了&#xff0c;请参考 (十)IIC总线-PCF8591-ADC/…

高度自适应scroll-view,uniapp项目

中间粉红的区域高度自适应,不管换什么机型&#xff0c;高度都自适应 <template><!-- 合同-待确认 --><view class"viewport"><!-- 上 --><view class"top-box"><!-- tab --><view class"tabs"><te…

Compose中的一些机制验证与总结——remember

最近在搞一个基于 Compose 实现的低代码跨平台项目&#xff0c;涉及到一些 Compose 运行时的一些机制问题&#xff0c;周末写了个 demo 验证总结一下&#xff0c;总体是与过往经验相符的&#xff0c;也发现了一些小的细节是以前不太清楚的&#xff0c;可以一起学习研究一下&…

js动态设置关键侦@keyframes

js动态设置关键侦keyframes 1.前置知识 关键侦keyframes规则通过在动画序列中定义关键侦的样式来控制CSS动画序列的中间步骤 keyframes slidein {from {transform: translateX(0%);}to {transform: translateX(100%);} } // from 等价于 0%&#xff1b;to 等价与 100% // 或…

Nacos下载与安装【windows】

&#x1f95a;今日鸡汤&#x1f95a; 我不知将去何方&#xff0c;但我已经在路上。 ——宫崎骏《千与千寻》 目录 &#x1f95e;1.Nacosdi地址 &#x1f32d;2.GitHub下载 &#x1f37f;3.目录结构 &#x1f953;4.启动nacos &#x1f9c2;5.客户端登陆 &#x1f9c8…

利用docker的LNMP

服务器环境 容器 操作系统 IP地址 主要软件 nginx CentOS 7 172.20.0.10 Docker-Nginx mysql CentOS 7 172.20.0.20 Docker-Mysql php CentOS 7 172.20.0.30 Docker-php 任务需求 使用 Docker 构建 LNMP 环境并运行 Wordpress 网站平台…

ES-极客学习第二部分ES 入门

基本概念 索引、文档、节点、分片和API json 文档 文档的元数据 需要通过Kibana导入Sample Data的电商数据。具体参考“2.2节-Kibana的安装与界面快速浏览” 索引 kibana 管理ES索引 在系统中找到kibana配置文件&#xff08;我这里是etc/kibana/kibana.yml&#xff09; vim /…

LabVIEW编码器自动校准系统

简介 在工作中&#xff0c;精确的角度测量和校准对于保持设备精度至关重要。开发了一套自动化角度编码器校准系统&#xff0c;利用了LabVIEW的强大功能。该系统以全圆连续角度标准装置为基础&#xff0c;配合二维导轨装夹系统&#xff0c;实现了空心轴角度编码器的高效自动校…

[易语言]使用易语言部署工业级人脸检测模型

【框架地址】 https://github.com/ShiqiYu/libfacedetection 【算法介绍】 Libfacedetection是一个开源的计算机视觉库&#xff0c;主要用于实时的人脸检测。它利用深度学习技术&#xff0c;特别是卷积神经网络&#xff08;CNN&#xff09;&#xff0c;实现了高精度的脸部定位…

Excel学习

文章目录 学习链接Excel1. Excel的两种形式2. 常见excel操作工具3.POI1. POI的概述2. POI的应用场景3. 使用1.使用POI创建excel2.创建单元格写入内容3.单元格样式处理4.插入图片5.读取excel并解析图解POI 4. 基于模板输出POI报表5. 自定义POI导出工具类ExcelAttributeExcelExpo…

RibbonGroup添加QCheckBox

RibbonGroup添加 QCheckBox&#xff1a; QCheckBox* pCheck new QCheckBox(tr("Check")); pCheck->setToolTip(tr("Check")); groupClipboard->addWidget(pCheck); connect(pCheck, SIGNAL(stateChanged(int)), this, SLOT(checkClick(int))); …

章鱼网络 2023 年全回顾|暨12月进展报告

2023年&#xff0c;章鱼网络轻装上阵&#xff0c;身处加密行业的低谷中砥砺前行。 12月17日&#xff0c;经过整整1年时间的开发和打磨&#xff0c;章鱼网络在重磅上线 Octopus 2.0&#xff0c;即 $NEAR Restaking 和 NEAR-IBC&#xff0c;获得了社区和市场的一致认可&#xff…

供排水管网管理信息化的必要性

供排水管网是城市供水系统的大动脉&#xff0c;它负担者将优质水源输送到最终用户的重要职责&#xff0c;对供水系统有着极其重要的作用。城市供排水管网埋设在地下&#xff0c;规模庞大&#xff0c;仅靠人工难以管理。同时&#xff0c;由于城市的发展&#xff0c;管网连接结构…

Camtasia2024屏幕录像和视频编辑软件

做网络教学视频&#xff0c;开发微课程&#xff0c;用得最多的就是录屏视频编辑&#xff0c;而在这类软件中我只推荐Camtasia Studio。随着Camtasia Studio的更新&#xff0c;其功能越来越完善&#xff0c;用户界面越来越友好&#xff0c;除了安装更加简单&#xff0c;汉化只需…

设置了uni.chooseLocation,小程序中打不开

设置了uni.chooseLocation&#xff0c;在小程序打不开&#xff0c;点击没反应&#xff0c;地图显现不出来&#xff1b; 解决方案&#xff1a; 1.Hbuilder——微信开发者工具路径没有配置 打开工具——>设置 2.微信小程序服务端口没有开 解决方法&#xff1a;打开微信开发…

苹果手机怎么还原删除的照片?这3个方法教你快速还原!

苹果手机用户在误删照片后&#xff0c;可能会感到非常焦虑。并且手机照片丢失对我们生活和工作都可能带来诸多不便。 但是&#xff0c;大家不必过于担心&#xff0c;仍有一些方法可以帮助我们找回这些误删的照片。苹果手机怎么还原删除的照片&#xff1f;本文将为大家介绍3种简…

九州金榜|临近春节,孩子要做什么更有意义?

元旦刚过&#xff0c;奔向除夕的脚步便越走越快了&#xff0c;转眼间&#xff0c;又来到了一年的末尾。 孩子们也都开始了新一轮的寒假&#xff0c;但是大街小巷中还是冷冷清清。 在和朋友们聊天时&#xff0c;他们也纷纷感叹&#xff1a;现在的孩子&#xff0c;不像我们这一…

python 计数器

这个Python脚本定义了一个名为new_counter()的函数&#xff0c;它读取系统时间并将其与存储在文件中的时间进行比较。然后根据比较结果更新存储在另一个文件中的计数器值。如果系统时间与存储的时间匹配&#xff0c;则计数器值增加1。如果系统时间与存储的时间不匹配&#xff0…

QMenuBar和QACtion的使用

1. 主界面&#xff1a;QMainWindow 包含了菜单栏、工具栏、状态栏以及工作区等功能 菜单栏&#xff1a;使用QMenuBar类管理&#xff0c;管理菜单栏中的菜单或者执行动作 执行动作&#xff1a;QAction类管理 工具栏&#xff1a;使用QToolBar类管理 状态栏&#xff1a;使用QStatu…

电脑扩容升级硬盘选1T还是2T

SSD固态有必要升级2TB吗&#xff1f;----------吴中函 某大二学生用的一台笔记本电脑&#xff0c;512GB的硬盘空间已经严重不够用了&#xff0c;想给笔记本扩容升级一下硬盘&#xff1b; 这位学生是学设计专业的、平时也喜欢摄影、电脑里面也装了一些游戏&#xff0c;经常整理、…