vue目录树组件(树状结构列表)

2023-11-06

一般数据类展示内容,大多采用树状结构展示内容。类似效果如下:

关注微信公众号,查看效果

在这里插入图片描述

左侧是导航分类,可以进行新建,对单项导航分享和删除。单击导航,在右侧查询出当前导航下所有目录结构,可以新建目录。新增类型分为三种,目录可以无限嵌套,当然也可以设置层级。

页面整体布局

页面分为左右两个部分。左侧列表,通过路由跳转显示右侧内容。左侧列表分为上下两块,顶部是添加按钮,下面是导航列表。

less样式。

import "../../theme/variables.less";
.main {    position: relative;    height: 100%;    overflow: hidden;    .content {        border: 1px solid #dcdcdc;        position: relative;        height: 100%;        background: #f1f2f7;        display: flex;        border-radius: @borderRadius;        .left {            width: 240px;            background: #fff;            border-right: 1px solid rgba(220, 220, 220, 1);            padding: 15px 10px;            display: flex;            flex-direction: column;            overflow: auto;            .header {                width: 100%;                margin-bottom: 20px;                display: flex;                justify-content: center;                align-items: center;                .btn {                    width: 136px;                    margin: 0 6px;                    :global {                        .icon {                            margin-right: 14px;                        }                        .customIcon {                            display: inline-block;                            transform: rotate(45deg);                        }                    }                }            }            .treeLayout {                flex: 1;                .item {                    width: 100%;                    height: 32px;                    line-height: 32px;                    margin-bottom: 11px;                    position: relative;                    .link {                        display: flex;                        align-items: center;                        font-size: 14px;                        font-family: Microsoft YaHei;                        font-weight: 400;                        color: rgba(51, 51, 51, 1);                        padding-left: 21px;                        cursor: pointer;                        .catalogIcon {                            font-size: 12px;                        }                        .text {                            display: inline-block;                            flex: 1;                            margin-left: 12px;                        }                        .opBtn {                            width: 46px;                            display: flex;                            align-items: center;                            justify-content: space-between;                        }                        .operateIcon {                            display: none;                        }                        &:hover {                            color: #00a4ff;                            .opBtn {                                color: rgba(51, 51, 51, 1);                            }                            .operateIcon {                                display: block;                            }                        }                    }                    .iconBtns {                        position: absolute;                        top: 28px;                        right: 24px;                        width: 112px;                        background: rgba(255, 255, 255, 1);                        box-shadow: 0px 0px 6px 0px rgba(0, 0, 0, 0.13);                        border-radius: 4px;                        z-index: 10;                        .icon {                            width: 100%;                            height: 40px;                            border-radius: 2px;                            display: flex;                            align-items: center;                            justify-content: center;                            font-size: 12px;                            font-family: Microsoft YaHei;                            font-weight: 400;                            color: rgba(51, 51, 51, 1);                            cursor: pointer;                            .iconName {                                margin-left: 18px;                            }                            &:hover {                                background: #e7e8e9;                            }                        }                    }                }                .itemActive {                    .link {                        color: #00a4ff;                        .opBtn {                            color: rgba(51, 51, 51, 1);                        }                        .operateIcon {                            display: block;                        }                    }                }            }        }        .right {            flex: 1;            width: 100%;            overflow: hidden;        }    }}

这里的导航列表,新增导航,和删除都是调用相关接口。

目录树组件

页面右侧就是树状结构列表,通过路由跳转携带catalogId参数,接口查询出列表数据,后端返回的数据就是有层级的树状结构。

我认为的写一个组件,单指这里的目录树组件,组件中只需要构造出页面布局,任何的交互逻辑都不涉及,只将相关事件抛出即可。这就需要先明确好数据结构,来写样式布局了。

数据结构,有id,name,父级id,子节点数组,类型catalogType:1是目录,2是场景,3是外链场景 ... 如下:

树状结构会涉及到递归,这里为了处理方便,组件中分为两层。组件目录结构如下:

index就是对外暴露的窗口,主要目录树的布局样式是在DomNode中。先明确一下布局,目录树中单个一行,需要一个展开收起的图标,当前行类型的图标,这里业务上分三种类型,就需要以此判断显示不同图标。每项最后还会有四个操作按钮。

这里把事件简化了,只分了两个事件,一个是展开收起,一个是一系列编辑操作,传个type参数作为区分。

tabNode(node: ITree) {    this.$emit("tabNode", node);},
// 操作doNode(node: ITree, type: string, index: number) {    this.$emit("doNode", node, type, index);},

index文件中引用DomNode,相关的接收的参数和抛出去的事件,和DomNode一致。

// index布局<div class="treeLayout">    <DomNode        v-for="(item, index) in trees"        :key="index"        :node="item"        @tabNode="tabNode"        @doNode="doNode"        :index="index"    ></DomNode></div>
// 接收的参数props: {    trees: {        type: Array as () => ITree[],        default: [],    },    activeId: {        type: String,        default: "",    },},

页面右侧实现

引用catalogTree组件。

<catalog-tree  :trees="treeList"  @tabNode="tabNode"  @doNode="doNode"></catalog-tree>

前文已经提过,目录数据是后端返回的,那么treeList就是后端返回值res.data。但操作tabNode和doNode这两个方法,需要将treeList数组转换成map对象。

因为需要自定义添加一些字段,这些字段只作为前端交互操作逻辑使用,所以后端返回值中不会携带。

需要给每一项数据添加isOpen字段,用来判断展开收起状态。level字段,用来实现上移下移操作。

先来构造这个catalogMap,定义个方法setCatalogMap,需要的参数有存放结果的treeMap,原数据treeList数组。

setCatalogMap,很简单的一个递归。

拿到map对象,就可以实现tabNode和doNode这两个方法。

// 切换状态tabNode(node: ITree) {    if (node.isOpen) {        this.treeMap[node.catalogId].isOpen = false;    } else {        this.treeMap[node.catalogId].isOpen = true;    }},
// 编辑等一系列操作,按照类型区分doNode(node: ITree, type: string, index: number) {    switch (type) {        case "up":            // 上移            this.doUp(node, index);            break;        case "down":            // 下移            this.doDown(node, index);            break;        case "edit":            // 编辑            this.doEdit(node.catalogId);            break;        case "delete":            // 删除            this.doDelete(node);            break;    }},

有认真看的话,会发现,并没有在哪里定义isOpen属性,怎么就在tabNode方法中使用了。

因为我还没有写。

拿到map对象,循环做个判断,用来保持isOpen状态。

Object.keys(treeMap).forEach((key) => {    const item = treeMap[key];    if (this.treeMap[key]) {        item.isOpen = this.treeMap[key].isOpen;    } else {        item.isOpen = true;    }});

doNode中的四个方法,编辑和删除就是调个接口,主要是上移下移操作,前端实现数据的排序,最后将最新的数据返回给后端保存,doSaveSort方法调接口保存。

上代码,好好琢磨琢磨。

doUp(node: ICatalogModel, index: number) {    if (index === 0) {        return;    }    const parentId: string = node.catalogParent as string;    const parentItem: ICatalogModel = this.treeMap[parentId];
    let dataList: ICatalogModel[] = [];    // 如果为空则是顶级    if (parentItem) {        if (parentItem.catalogTreeVoList) {            dataList = parentItem.catalogTreeVoList;        }    } else {        dataList = this.treeList;    }    const item = dataList[index];    dataList.splice(index, 1);    dataList.splice(index - 1, 0, item);    this.doSaveSort(dataList);},
doDown(node: ICatalogModel, index: number) {    const parentId: string = node.catalogParent as string;    const parentItem: ICatalogModel = this.treeMap[parentId];    // 如果为空则是顶级    let dataList: ICatalogModel[] = [];    if (parentItem) {        if (parentItem.catalogTreeVoList) {            // 最后一个不能下移            if (parentItem.catalogTreeVoList.length === (index + 1)) {                return;            } else {                dataList = parentItem.catalogTreeVoList;            }        }    } else {        // 一级最后一个不能下移        if ( this.treeList.length === (index + 1)) {            return;        }        dataList = this.treeList;    }    const item = dataList[index];    dataList.splice(index, 1);    dataList.splice(index + 1, 0, item);    this.doSaveSort(dataList);},

总结

树状结构列表,首先需要明确数据结构,必备的字段id,name,父级id,children数组,根据数据结构,使用递归构建布局。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue目录树组件(树状结构列表) 的相关文章

随机推荐

  • qt中复制文件的功能

    1 利用qt来复制文件 首先新建个工程文件 拖入按钮 复制文件 2 需要引入的头文件如下 include
  • 六月学习记录

    六月学习记录 6 1 Android消息传递之Handler消息机制 four articles http www cnblogs com whoislcj p 5590615 html 6 2 代码审查工具phabricator 6 4
  • 7 Linux 内核移植

    一 编译 ST 的 Linux 系统 1 压缩源码 首先先下载 ST 官方源码 之前章节已经下载过了 直接输入以下命令 cd linux atk mpl stm32mp1 openstlinux 5 4 dunfell mp1 20 06
  • pycharm 2023.1.2 去掉版本控制

    pycharm 2023 1 2 去掉版本控制
  • 优秀程序员应该具备的12种能力

    1 编程语言能力 不用多说 作为合格的计算机程序员 精通一门语言是必须的 这种精通 不是说看了一本编程宝典 抄了几个程序就能说精通的 要靠长时间的积累 2 编码能力 我曾经看很多程序员写的代码 在同一个jsp或者java源文件里 出现了三种
  • WinForm控件Chart的图表类型

    将就看 后期再加目录导航2020 10 23 折线图 折线图通常使用一条线来连接一系列不同的数据点 这样的直线是直线 样条曲线或阶梯 折线图更简单 因此还可以使您可视化多个系列而不会像条形图那样重叠 以下是折线图的不同类型 折线图 折线图使
  • C\C++各种变量存放区域(代码、数据、堆、栈)

    C C 各种变量存放区域 代码 数据 堆 栈 文章目录 C C 各种变量存放区域 代码 数据 堆 栈 变量 数据 变量 数据存放区域 练习 请说明下面的指针分别指向什么位置 BSS Block Started by Symbol 区 为什么
  • numpy实现卷积两种方法

    暂时针对二维卷积 方法1 按定义计算 def numpy conv inputs myfilter h ori w ori inputs shape h k w k myfilter shape h new w new h ori h k
  • 如何控制小程序的tabBar的显示和隐藏

    1 使用wx hideTabBar 方法隐藏tabBar 2 使用wx showTabBar 方法显示tabBar 参考文档
  • 适配器模式代码示例

    package com example shipeiqi public interface ThreeElectricOutlet 用来刻画三相插座 public abstract void connectElectricCurrent p
  • maven-metadata.xml使用

    最近在开发过程中 发现工程中的一些包有问题 主要分为以下两种 1 最新包 版本号未变 只是被更新了 少了一个方法 2 jar包被更新了 但是无法更新最新的包下来 首先先确定一下更新包会导致更新哪些文件 下面都以a 1 0 1 snapsho
  • 学习笔记:机器学习之支持向量机(一、最大间隔算法)

    活动地址 CSDN21天学习挑战赛 1 简介 支持向量机也是一种二分类模型 它是通过在特征空间中建立间隔最大的分类器 这是有别于感知机模型的一点 支持向量机可分为线性可分支持向量机 线性支持向量机 非线性支持向量机 2 函数间隔 几何间隔
  • node后台快速开发框架

    任何可以用 JavaScript 来写的应用 最终都将用 JavaScript 来写 node js是用JS语言编写的 JaveScript已经是世界上最流行的语言之一 用它可以实现任何功能需求 无论是后台开发 前端 App 桌面应用程序
  • 华为OD机试 C++ 最佳植树距离

    题目 小明得到了一项任务 在一个沙地里种树 不过 有些地方不能种树 只能选特定的位置来种 为了让树之间的空间尽可能大 从而更好地防沙 你要帮小明决定每棵树应该种在哪里 举个例子 如果合适的种树地点是1 3 5 6 7 10 13 你有3棵树
  • CountDownLatch理解一:与join的区别

    首先 我们来看一个应用场景1 假设一条流水线上有三个工作者 worker0 worker1 worker2 有一个任务的完成需要他们三者协作完成 worker2可以开始这个任务的前提是worker0和worker1完成了他们的工作 而wor
  • zabbix-server无法启动

    故障现象 监控界面无数据 1 netstat lntup 先查看zabbix server进程是否正常 2 tail f var log zabbix zabbix server log 查看后台日志 表示一个子进程死掉 是一个zabbix
  • 平凯星辰合伙人余梦杰:全球化和云计算趋势下的开源生态构建

    开源是技术发展的大趋势 其开放的全球生态 敏捷的技术创新以及快速的产品迭代 都有助于企业的发展 而云的蓬勃发展则加速了企业数字化的进程 开源和云两者交融 必然会迸发更多势能 2022年7月27日 在2022开放原子全球开源峰会数据库论坛上
  • 在 IDEA 中连接数据库实现增删改查,使用dao封装数据库操作+bean封装实体类+util封装数据库连接与释放(含源码下载)

    在 IDEA 中连接数据库实现增删改查 使用dao封装数据库操作 bean封装实体类 util封装数据库连接与释放 主要内容 利用SQLyog图形化工具建立数据库 具体代码搭建 bean目录下的 用户实体类User util中对数据库的连接
  • ARM汇编指令集——跳转指令、内存传输指令、软中断产生指令、协处理器指令、伪指令、伪操作(如何从底层直接操纵CPU)

    一 跳转指令 完成程序跳转 实质就是对PC操作 赋值 b bl跳转是短跳转 跳转范围 32MB start mov r0 1 mov r1 2 mov r3 3 b func b跳转 不带返回值 mov r4 4 func mov r5 5
  • vue目录树组件(树状结构列表)

    一般数据类展示内容 大多采用树状结构展示内容 类似效果如下 关注微信公众号 查看效果 左侧是导航分类 可以进行新建 对单项导航分享和删除 单击导航 在右侧查询出当前导航下所有目录结构 可以新建目录 新增类型分为三种 目录可以无限嵌套 当然也