树状表格子节点移动 - 在Vue.js中实现上下移动子节点的表格功能

news2024/11/24 10:34:27

目录

功能介绍

示例

代码

视图部分

逻辑部分

完整代码


功能介绍

        本文介绍了如何在Vue.js框架下实现一个树状表格,其中支持选择子节点行的上下移动。通过这个功能,用户可以方便地改变子节点的顺序。代码示例和详细的实现步骤将展示如何使用Vue.js的相关特性和组件实现这个功能。通过本文的介绍,您可以轻松了解如何在您的Vue.js项目中应用这个功能,以满足您的特定需求。     

示例

代码

视图部分

        实现父节点选择的代码

        在上次选中父节点的代码基础上加上操作行,生成上下移动的按钮: 

      <el-table-column align="center">
        <template slot-scope="scope" v-if="!scope.row.children">
          <el-button v-show="!validateOperate(scope.row, 'up')" size="mini" icon="el-icon-top" plain
            @click="handleSort(scope.row, 'up')">
          </el-button>
          <el-button v-show="!validateOperate(scope.row, 'down')" size="mini" icon="el-icon-bottom" plain
            @click="handleSort(scope.row, 'down')"></el-button>
        </template>
      </el-table-column>

        新增列定义,用于显示上移和下移按钮。<template> 标签中定义了使用 slot-scope 来访问作用域插槽,在这个作用域下,使用了两个 <el-button> 元素来展示上移和下移按钮。为了使第一行与最后一行只有下移或上移,这里通过绑定 v-show 来控制按钮的显示与隐藏,根据 validateOperate() 方法的返回值确定按钮是否可见。@click 侦听器则会触发 handleSort() 方法来完成所在行的移动。

逻辑部分

组件数据和选中父节点的代码相同,获取tableData后,如果没有index,则自己遍历加上该属性。

   

methods对象新增方法:

  • getParent(id) 方法用于获取拥有指定子行 id 的父级行,它通过遍历 this.tableData 数组来寻找子行所属的父行。
    getParent(id) {
      let result = [];
      this.tableData.some(item => {
        item.children.some(d => {
          if (d.id == id) result = item;
        })
      });
      return result;
    }
  • validateOperate(row, type) 方法用于根据指定的操作类型(上移或下移)检查当前行是否可进行该操作。首先判断是否最内层的子树,对于上移操作,当前行的索引为0时返回true,隐藏上移按钮;对于下移操作,当前行的索引等于自身所处children数组的长度减1时返回true,隐藏下移按钮。
    validateOperate(row, type) {
      if (!row.children) {
        if (type == 'up' && row.index == 0) {
          return true;
        }
        else if (type == 'down') {
          return this.getParent(row.id).children.length - 1 == row.index;
        }
        else {
          return false;
        }
      }
    }
  • handleSort(row, type) 方法用于处理行的上移和下移操作。它首先获取该行的父级行和父级行的 ID,并定义一个标志变量 downFlag。然后通过遍历 parent.children 数组来查找需要进行上移或下移操作的行,并进行相应的移动和调整索引的操作。最后,更新父级行的子行列表和相关数据。
    handleSort(row, type) {
      let parent = this.getParent(row.id);
      let parentId;
      let downFlag = true;

      this.tableData.forEach(item => {
        if (item.children === parent) parentId = item.id;
      });

      console.log(parent);
      parent.children.some(item => {
        if (type == 'up') {
          if (item.index == row.index - 1) {
            parent.children.splice(row.index, 1);
            parent.children.splice(item.index, 0, row);
            parent.children.forEach((child, index) => child.index = index);
            this.tableData.forEach(data => {
              if (data.id === parentId) data.children = parent.children;
            });
          }
        } else if (type == 'down' && downFlag) {
          if (item.index == row.index + 1) {
            parent.children.splice(row.index, 1);
            parent.children.splice(item.index, 0, row);
            parent.children.forEach((child, index) => child.index = index);
            this.tableData.forEach(data => {
              if (data.id === parentId) data.children = parent.children;
            });
            downFlag = false;
          }
        }
      })
    }

完整代码

<template>
  <div>
    <el-table v-loading="loading" :data="tableData" style="width: 100%;margin: 20px;" row-key="id" border
      default-expand-all :tree-props="{ children: 'children' }">
      <el-table-column width="60" align="center">
        <template slot="header" slot-scope="scope">
          <el-checkbox :indeterminate="isIndeterminate" v-model="isFullChecked" @change="checkAllChange">
          </el-checkbox>
        </template>
        <template slot-scope="{row}" v-if="row.children">
          <el-checkbox :indeterminate="row.isIndeterminate" :value="row.checked" @change="checkRowChange(row)">
          </el-checkbox>
        </template>
      </el-table-column>

      <el-table-column prop="series" label="系列" align="center"></el-table-column>
      <el-table-column prop="num" label="编号" align="center"></el-table-column>
      <el-table-column prop="name" label="名字" align="center"></el-table-column>
      <el-table-column align="center">
        <template slot-scope="scope" v-if="!scope.row.children">
          <el-button v-show="!validateOperate(scope.row, 'up')" size="mini" icon="el-icon-top" plain
            @click="handleSort(scope.row, 'up')">
          </el-button>
          <el-button v-show="!validateOperate(scope.row, 'down')" size="mini" icon="el-icon-bottom" plain
            @click="handleSort(scope.row, 'down')"></el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isFullChecked: false,
      isIndeterminate: false,
      loading: true,
      tableData: []
    }
  },
  mounted() {
    this.getList()
  },
  watch: {
    tableData() {
      this.isFullChecked = false;
      this.isIndeterminate = false;
    }
  },
  methods: {
    getList() {
      const tableData = [
        {
          id: 1,
          series: 'DDLC',
          children: [
            {
              id: 11,
              num: '1',
              name: 'monika',
              index: 0,
            },
            {
              id: 12,
              num: '2',
              name: 'nasuki',
              index: 1,
            },
            {
              id: 13,
              num: '3',
              name: 'sayori',
              index: 2,
            },
            {
              id: 14,
              num: '4',
              name: 'yuri',
              index: 3,
            }
          ]
        },
        {
          id: 2,
          series: 'Bloom Into You',
          children: [
            {
              id: 21,
              num: '11',
              name: 'nanami',
              index: 0,
            },
            {
              id: 22,
              num: '12',
              name: 'yuu',
              index: 1,
            }
          ]
        },
      ];
      tableData.forEach(item => {
        item.checked = false;
        item.isIndeterminate = false;
      })
      this.tableData = tableData;
      this.total = this.tableData.length;
      this.loading = false;
    },

    checkAllChange() {
      const recursionSetChecked = (item, checked) => {
        item.checked = checked;
        item.isIndeterminate = false;
      }
      this.isIndeterminate = false;
      this.tableData.forEach(item => recursionSetChecked(item, this.isFullChecked));
    },

    checkRowChange(data) {
      data.checked = !data.checked;
      const recursion = node => {
        if (node.children && node.children.length > 0)
          node.isIndeterminate = false;
        return node;
      };
      this.tableData.forEach(item => recursion(item));

      if (this.tableData.every(item => item.checked)) {
        this.isFullChecked = true;
      }
      else if (this.tableData.every(item => !item.checked)) {
        this.isFullChecked = false;
      }

      this.isIndeterminate = this.tableData.some(item => item.isIndeterminate)
        ? true
        : this.tableData.some(item => !item.checked) && this.tableData.some(item => item.checked);
    },

    getParent(id) {
      let result = [];
      this.tableData.some(item => {
        item.children.some(d => {
          if (d.id == id) result = item;
        })
      });
      return result;
    },

    validateOperate(row, type) {
      if (!row.children) {
        if (type == 'up' && row.index == 0) {
          return true;
        }
        else if (type == 'down') {
          return this.getParent(row.id).children.length - 1 == row.index;
        }
        else {
          return false;
        }
      }
    },

    handleSort(row, type) {
      let parent = this.getParent(row.id);
      let parentId;
      let downFlag = true;

      this.tableData.forEach(item => {
        if (item.children === parent) parentId = item.id;
      });

      console.log(parent);
      parent.children.some(item => {
        if (type == 'up') {
          if (item.index == row.index - 1) {
            parent.children.splice(row.index, 1);
            parent.children.splice(item.index, 0, row);
            parent.children.forEach((child, index) => child.index = index);
            this.tableData.forEach(data => {
              if (data.id === parentId) data.children = parent.children;
            });
          }
        } else if (type == 'down' && downFlag) {
          if (item.index == row.index + 1) {
            parent.children.splice(row.index, 1);
            parent.children.splice(item.index, 0, row);
            parent.children.forEach((child, index) => child.index = index);
            this.tableData.forEach(data => {
              if (data.id === parentId) data.children = parent.children;
            });
            downFlag = false;
          }
        }
      })
    }
  }
}
</script>

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

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

相关文章

OJ题库:俩个有序序列(数组)合并

前言&#xff1a;在部分大厂笔试时经常会使用OJ题目&#xff0c;这里对《有序序列合并》进行思路分析和讲解&#xff0c;在这里主要使用俩种方法进行讲解&#xff0c;希望对各位读者有所帮助。 题目来自牛客网&#xff0c;欢迎各位积极挑战&#xff1a;有序序列合并_牛客题霸_牛…

汽车电子笔记之:基于AUTOSAR的多核监控机制

目录 1、概述 2、系统监控的目标 2.1、任务的状态机 2.2、任务服务函数 2.3、任务周期性事件 2.4、时间监控的指标 2.5、时间监控的原理 2.6、CPU负载率监控原理 2.6.1、设计思路 2.6.2、监控方法的评价 3、基于WDGM模块热舞时序监控方法 3.1、活跃监督 3.2、截至时…

Mongodb启动失败相关问题解决最全

一、mongod突然启动失败&#xff0c;存在mongod.lock文件 查找文件 find / -name mongod.lock -d删除该文件 rm -rf mongod.lock重新启动 /data/mongodb/bin/mongod --config /data/mongodb/bin/mongodb.conf --replSet cloud通过修改的方式启动 /data/mongodb/bin/mongod --r…

与信创国产化高度适配的低代码开发框架

信创产业是中国经济发展的基础&#xff0c;也是重要驱动力。坚持基础软件自主创新&#xff0c;是国产软件正版化应用和推广的源头。行业预测&#xff0c;2023年信创产业市场规模预计为18710.59亿元&#xff0c;预计到2025年将会接近3.5万亿元。 信创产业的主要目标是实现信息技…

屏蔽百度右侧热搜和首页新闻

先看效果 这样就没有垃圾新闻影响我们的注意力了 设置其实很简单&#xff0c;首先需要安装一下 Adblock Plus&#xff0c;安装的方式很多&#xff0c;这里我使用一个网站直接添加即可&#xff1a; Download Adblock Plus 3.18.1 CRX File for Chrome - Crx4Chrome 然后就能在…

Django(8)-静态资源引用CSS和图片

除了服务端生成的 HTML 以外&#xff0c;网络应用通常需要一些额外的文件——比如图片&#xff0c;脚本和样式表——来帮助渲染网络页面。在 Django 中&#xff0c;我们把这些文件统称为“静态文件”。 我们使用static文件来存放静态资源&#xff0c;django会在每个 INSTALLED…

【已解决】pycharm突然双击无法打开,重启电脑也不管用

1.问题&#xff1a; pycharm突然双击无法打开&#xff0c;重启电脑也不管用 2.解决 2.1 方法一&#xff08;修改Roaming&#xff09; 1.找到C盘对应路径下的pycharm版本 2. 用记事本打开文件类型为VMOPTIONS文件 3. 修改或删除最后一行的映射路径 4.保存退出 2.2 方法二…

无涯教程-Python机器学习 - Analysis of Silhouette Score函数

剪影得分的范围是[-1,1]。其分析如下- 1分数-接近1 剪影分数表示样本距离其邻近簇很远。 0分数-0 剪影分数表示样本在将两个相邻聚类分隔开的决策边界上或非常接近。 -1分数-1 剪影分数表示样本已分配给错误的聚类。 Silhouette得分的计算可以使用以下公式完成 $$剪影得…

FAB厂逃离指南—转行IC之经验分享!

一、为什么转行&#xff1f; 毕业后&#xff0c;我在成都一家国企做面板半导体工艺&#xff0c;说是工艺但是去了得先学习了解进口的设备半年左右&#xff0c;还得上夜班。&#xff08;这里给各位一个小小的建议&#xff1a;如果毕业找FAB厂类工作要慎重&#xff0c;非纯研发岗…

《机器学习在车险定价中的应用》实验报告

目录 一、实验题目 机器学习在车险定价中的应用 二、实验设置 1. 操作系统&#xff1a; 2. IDE&#xff1a; 3. python&#xff1a; 4. 库&#xff1a; 三、实验内容 实验前的猜想&#xff1a; 四、实验结果 1. 数据预处理及数据划分 独热编码处理结果&#xff08;以…

【QT】ComboBox的使用(14)

ComboBox这个控件我常用于多文本的储存、调用&#xff0c;正如他的中文意思为&#xff1a;下拉列表框。 下拉列表框&#xff1a;字面意思就是一个多文本的列表框&#xff0c;今天来看下如何使用ComboBox这个控件。 一.环境配置 1.python 3.7.8 可直接进入官网下载安装&…

恒运资本:“鹰派”讲话吓坏市场?美股大跳水后反弹!

鲍威尔表示&#xff0c;“如果适宜&#xff0c;美联储准备继续加息”。 北京时间8月25日晚间&#xff0c;美联储主席鲍威尔在杰克逊霍尔全球央行年会上发表讲话。 鲍威尔在讲话过程中&#xff0c;警告通胀“依旧过高”&#xff0c;以及“如果适宜&#xff0c;美联储准备继续加…

会话跟踪技术 【CookieSession】

会话技术 1 会话跟踪技术的概述2 Cookie2.1 Cookie的基本使用2.1.1 概念2.1.2 Cookie的工作流程2.1.3 Cookie的基本使用2.1.3.1 发送Cookie2.1.3.2 获取Cookie 2.2 Cookie的原理分析2.3 Cookie的使用细节2.3.1 Cookie的存活时间2.3.2 Cookie存储中文 3 Session3.1 Session的基本…

多线程学习之生产者和消费者与阻塞队列的关系

生产者和消费者 概述&#xff1a; 生产者消费者问题&#xff0c;实际上主要是包含了两类线程&#xff1a; 生产者线程用于生产数据消费者线程用于消费数据 生产者和消费者之间通常会采用一个共享的数据区域&#xff0c;这样就可以将生产者和消费者进行解耦&#xff0c; 两…

1.MIMO信号检测

目录 最优信号检测算法 次最优信号检测算法 分层信号检测算法 线性信号检测算法 迫零线性信号检测算法 最小均方误差线性信号检测算法 非线性信号检测算法 在MIMO-OFDM系统中&#xff0c;信号检测算法可以通过将MIMO系统的信号检测算法应用于各个并行的子信道进行信号…

java八股文面试[JVM]——类初始化过程

回顾类加载过程&#xff1a; 知识来源&#xff1a; 【2023年面试】Class初始化过程是什么_哔哩哔哩_bilibili

哪种类型耳机不伤耳朵,对耳朵伤害最小的耳机类型

在骨传导耳机的普及浪潮下&#xff0c;人们越来越意识到长期使用传统耳机对耳道造成的伤害。许多朋友纷纷转向相对更加护听的骨传导耳机&#xff0c;但仍有一部分人对这项技术不太了解&#xff0c;甚至被误导认为骨传导耳机会对听力和大脑造成伤害。因此&#xff0c;我将给大家…

【应用层】网络基础 -- HTTPS协议

HTTPS 协议原理加密为什么要加密常见的加密方式对称加密非对称加密 数据摘要&&数据指纹 HTTPS 的工作过程探究方案1-只使用对称加密方案2-只使用非对称加密方案3-双方都使用非对称加密方案4-非对称加密对称加密中间人攻击-针对上面的场景 CA认证理解数据签名方案5-非对…

Redis限流实践:实现用户消息推送每天最多通知2次的功能

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…

log4net 输出中文乱码

如上图 在appender属性内加入 <param name"Encoding" value"utf-8" /> 问题解决!