vxe-table 同时实现合并单元格与任意列展开行

news2025/7/19 12:50:10

 前一段时间有一个需求,要求既要合并单元格,又要实现树状图的效果,但是展开节点tree-node 可以放在非第一列的任意位置,Vxe-table可以实现如下是效果图:

大家可以一起交流学习!

~重点注意事项:

1. 树状结构会用到rowField,不配置的话默认是id,必须是不能为空,且是唯一的;如果配置了如下tree-config, PrdId必须不能为空,且是唯一。 (新增时尤其要注意赋值

:tree-config="{
        transform: true,
        rowField: 'PrdId',
        parentField: 'ParentERP'
      }"

~效果图

~Template

<template>
  <div>
    <p>
      <vxe-button @click="toggleExpandEvent">切换第一个</vxe-button>
      <vxe-button @click="setExpandEvent">展开第三个</vxe-button>
      <vxe-button @click="expandAllEvent">展开所有</vxe-button>
      <vxe-button @click="claseExpandEvent">关闭所有</vxe-button>
    </p>

    <vxe-table
      border
      show-overflow
      ref="tableRef"
      :column-config="{ resizable: true }"
      :tree-config="{ transform: true }"
      :edit-config="{ trigger: 'click', mode: 'cell' }"
      :data="tableData"
      :span-method="objectSpanMethod"
      header-row-class-name="headerRowClass"
    >
      <vxe-column
        field="userName"
        title="用户名"
        :edit-render="{ autofocus: ' .vxe-input--inner' }"
      >
        <template #edit="{ row }">
          <vxe-input v-model="row.userName" />
        </template>
      </vxe-column>
      <vxe-column
        field="targetNum"
        title="数量"
        :edit-render="{ autofocus: ' .vxe-input--inner' }"
      >
        <template #edit="{ row }">
          <vxe-input v-model="row.targetNum" mode="text" type="number" />
        </template>
      </vxe-column>
      <vxe-column
        field="dilieverSite"
        title="项目交付地"
        :edit-render="{ autofocus: ' .vxe-input--inner' }"
      >
        <template #edit="{ row }">
          <vxe-input v-model="row.dilieverSite" mode="text" />
        </template>
      </vxe-column>
      <vxe-column
        field="name"
        title="名字"
        :edit-render="{ autofocus: ' .vxe-input--inner' }"
        tree-node
      >
        <template #edit="{ row }">
          <vxe-input v-model="row.name" transfer />
        </template>
      </vxe-column>
      <vxe-column
        field="type"
        title="类型"
        :edit-render="{ autofocus: ' .vxe-input--inner' }"
      >
        <template #edit="{ row }">
          <vxe-input v-model="row.type" transfer />
        </template>
      </vxe-column>
      <vxe-column
        field="size"
        title="尺寸"
        :edit-render="{ autofocus: ' .vxe-input--inner' }"
      >
        <template #edit="{ row }">
          <vxe-input v-model="row.size" transfer />
        </template>
      </vxe-column>
      <vxe-column title="删除小条目" width="80">
        <template #default="{ row }">
          <el-icon
            @click="handleERPDelete(row)"
            class="el-icon-delete"
            color="#F56C6C"
            ><Delete
          /></el-icon>
        </template>
      </vxe-column>
      <vxe-column field="oper" title="操作" width="100">
        <template #default="{ row }">
          <el-button @click="handleAdd(row)" link size="small" type="primary"
            >新增</el-button
          >
          <el-button @click="handleDelete(row)" link size="small" type="danger"
            >删除</el-button
          >
        </template>
      </vxe-column>
    </vxe-table>
  </div>
</template>

~script

<script lang="ts" setup>
import { ref, onMounted } from "vue";
import { ElMessageBox } from "element-plus";
import type {
  VxeTablePropTypes,
  VxeTableEvents,
  VxeTableInstance
} from "vxe-table";
interface RowVO {
  id: number;
  userName: string;
  dilieverSite: string;
  targetNum: number;
  parentId: number | null;
  name: string;
  type: string;
  size: number;
  date: string;
  oper?: string;
}

const tableData = ref<RowVO[]>([
  {
    id: 10000,
    parentId: null,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "test abc1",
    type: "mp3",
    size: 1024,
    date: "2020-08-01"
  },
  {
    id: 10050,
    parentId: null,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test2",
    type: "mp4",
    size: 0,
    date: "2021-04-01"
  },
  {
    id: 24300,
    parentId: 10050,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test3",
    type: "avi",
    size: 1024,
    date: "2020-03-01"
  },
  {
    id: 20045,
    parentId: 24300,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "test abc4",
    type: "html",
    size: 600,
    date: "2021-04-01"
  },
  {
    id: 10053,
    parentId: 24300,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "test abc96",
    type: "avi",
    size: 0,
    date: "2021-04-01"
  },
  {
    id: 24330,
    parentId: 10053,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "test abc5",
    type: "txt",
    size: 25,
    date: "2021-10-01"
  },
  {
    id: 21011,
    parentId: 10053,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test6",
    type: "pdf",
    size: 512,
    date: "2020-01-01"
  },
  {
    id: 22200,
    parentId: 10053,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 23666,
    parentId: null,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test8",
    type: "xlsx",
    size: 2048,
    date: "2020-11-01"
  },
  {
    id: 23677,
    parentId: 23666,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 23671,
    parentId: 23677,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 23672,
    parentId: 23677,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 23688,
    parentId: 23666,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 23681,
    parentId: 23688,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 23682,
    parentId: 23688,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 24555,
    parentId: null,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "test abc9",
    type: "avi",
    size: 224,
    date: "2020-10-01"
  },
  {
    id: 24566,
    parentId: 24555,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 24577,
    parentId: 24555,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  }
]);

const setTabelRowSpan = (tableData: any, fieldArr: any, effectMerge = {}) => {
  let lastItem = {};
  fieldArr.forEach((field: any, index: any) => {
    let judgeArr = fieldArr.slice(0, index + 1);
    if (effectMerge[field]) {
      judgeArr = [...effectMerge[field], field];
    }
    tableData.forEach((item: any) => {
      item.mergeCell = fieldArr;
      const rowSpan = `rowspan_${field}`;
      if (
        judgeArr.every((e: any) => lastItem[e] === item[e] && item[e] !== "")
      ) {
        item[rowSpan] = 0;
        lastItem[rowSpan] += 1;
      } else {
        item[rowSpan] = 1;
        lastItem = item;
      }
    });
  });
};
const executeMerge = (data: any) => {
  // let effectRows = [0];
  // let fieldArr = ["userName"]; //全部字段
  let RowfieldArr = ["userName", "dilieverSite", "targetNum"];
  //setTableColumnSpan(data, fieldArr, effectRows); // (表格数据,表格字段,合并列
  setTabelRowSpan(data, RowfieldArr); // (表格数据,表格字段,合并的条件)
  //如果要用到合并条件:参考如下
  // const effectMerge = {
  //      dilieverSite: ['userName'],//参照userName字段合并
  //      targetNum: ['userName']//
  //  }
};

onMounted(() => {
  executeMerge(tableData.value);
});

const tableRef = ref<VxeTableInstance<RowVO>>();

const colspanMethod: VxeTablePropTypes.SpanMethod<RowVO> = ({
  row,
  _rowIndex,
  column,
  columnIndex
}) => {
  if (columnIndex === 1) {
    console.log("row", row);
  }
};

const toggleExpandEvent = () => {
  const $table = tableRef.value;
  if ($table) {
    $table.toggleTreeExpand(tableData.value[1]);
  }
};

const setExpandEvent = () => {
  const $table = tableRef.value;
  if ($table) {
    $table.setTreeExpand(tableData.value[8], true);
  }
};

const expandAllEvent = () => {
  const $table = tableRef.value;
  if ($table) {
    $table.setAllTreeExpand(true);
  }
};

const claseExpandEvent = () => {
  const $table = tableRef.value;
  if ($table) {
    $table.clearTreeExpand();
  }
};

const objectSpanMethod: VxeTablePropTypes.SpanMethod<any> = ({
  row,
  column,
  rowIndex,
  columnIndex
}) => {
  // if (effectRows.includes(rowIndex)) {
  //   const colspan = row[`colspan_${column.property}`];
  //   if (colspan) {
  //     return { rowspan: 1, colspan: colspan };
  //   } else {
  //     return { rowspan: 0, colspan: 0 };
  //   }
  // }
  if (row.mergeCell.includes(column.property)) {
    const rowspan = row[`rowspan_${column.property}`];
    if (rowspan) {
      return { rowspan: rowspan, colspan: 1 };
    } else {
      return { rowspan: 0, colspan: 0 };
    }
  } else if (column.property === "oper") {
    const rowspan = row[`rowspan_userName`];
    if (rowspan) {
      return { rowspan: rowspan, colspan: 1 };
    } else {
      return { rowspan: 0, colspan: 0 };
    }
  }
};

const handleAdd = row => {
  console.log(row);
};

const handleDelete = row => {
  console.log(row);
};

const handleERPDelete = row => {
  ElMessageBox.confirm("确定要删除吗?", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning"
  }).then(() => {
    console.log(row);
  });
};
</script>

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

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

相关文章

ArcGIS Desktop使用入门(二)常用工具条——图形

系列文章目录 ArcGIS Desktop使用入门&#xff08;一&#xff09;软件初认识 ArcGIS Desktop使用入门&#xff08;二&#xff09;常用工具条——标准工具 ArcGIS Desktop使用入门&#xff08;二&#xff09;常用工具条——编辑器 ArcGIS Desktop使用入门&#xff08;二&#x…

神经网络语言模型(前馈神经网络语言模型)

神经网络语言模型 什么是神经网络&#xff1f;神经网络的基本结构是什么&#xff1f;输入层隐藏层输出层 神经网络为什么能解决问题&#xff1f;通用近似定理为什么需要权重和偏置&#xff1f;为什么需要激活函数&#xff1f;权重是如何确定的&#xff1f;1. 穷举2. 反向传播主…

CUDA编程——性能优化基本技巧

本文主要介绍下面三种技巧&#xff1a; 使用 __restrict__ 让编译器放心地优化指针访存想办法让同一个 Warp 中的线程的访存 Pattern 尽可能连续&#xff0c;以利用 Memory coalescing使用 Shared memory 0. 弄清Kernael函数是Compute-bound 还是 Memory-bound 先摆出一个知…

道通EVO MAX系列无人机-支持二次开发

道通EVO MAX系列无人机-支持二次开发 EVO Max 系列采用Autel Autonomy自主飞行技术&#xff0c;实现复杂环境下的全局路径规划、3D场景重建、自主绕障和返航&#xff1b;高精度视觉导航能力&#xff0c;使其在信号干扰强、信号遮挡、信号弱等复杂环境下&#xff0c;依然获得高精…

计算机网络-MPLS LDP基础实验配置

前面我们学习了LDP的会话建立、标签发布与交换、LDP的工作原理&#xff0c;今天通过一个基础实验来加深记忆。 一、LDP基础实验 实验拓扑&#xff1a; 1、IGP使用OSPF进行通告&#xff0c;使用Lookback接口作为LSR ID&#xff0c;LDP ID自动生成。 2、实验目的&#xff1a;使…

HPE ProLiant DL360 Gen11 服务器,配置 RAID 5 教程!

今天的任务&#xff0c;是帮客户的一台HPE ProLiant DL360 Gen11 服务器&#xff0c;配置RAID 5。依然是按照我的个人传统习惯&#xff0c;顺便做一个教程&#xff0c;分享给有需要的粉丝们。如果你在实际操作中&#xff0c;遇到了什么问题&#xff0c;欢迎在评论区留言&#x…

SARIMA-LSTM融合模型对太阳黑子数量预测分析|附智能体数据代码

全文智能体链接&#xff1a;https://tecdat.cn/?p41969 分析师&#xff1a;Peng Fan 本研究以太阳黑子活动数据为研究对象&#xff0c;旨在帮助客户探索其未来走势并提供预测分析。首先&#xff0c;通过对数据的清洗和处理&#xff0c;包括离群值的识别与处理以及时间序列的建…

C# WinForm DataGridView 非常频繁地更新或重新绘制慢问题及解决

非常频繁地更新 DataGridView问题描述&#xff1a; 在 C# 中无法在合理的时间内刷新我的 DataGridView &#xff0c;我每秒通过网络发送 20 个数据包&#xff0c;获取数据。我想解析这些数据并将其放入 DataGridView 中。我还想调整 DataGridView 的更新间隔&#xff0c;从 0.1…

【数据结构】红黑树(C++)

目录 一、红黑树的概念 二、红黑树的性质 三、红黑树结点定义 四、红黑树的操作 1. 插入操作 1.1 插入过程 1.2 调整过程 1.2.1 叔叔节点存在且为红色 1.2.2 叔叔节点存在且为黑色 1.2.3 叔叔节点不存在 2. 查找操作 2.1 查找逻辑 2.2 算法流程图 2.3 使用示例 …

Android Framework学习五:APP启动过程原理及速度优化

文章目录 APP启动优化概述APP启动流程点击图片启动APP的过程启动触发Zygote 与应用进程创建Zygote进程的创建应用进程初始化 ApplicationActivity 启动与显示 优化启动时黑白屏现象可优化的阶段Application阶段相关优化 Activity阶段数据加载阶段 Framework学习系列文章 APP启动…

Meta的AIGC视频生成模型——Emu Video

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍Meta的视频生成模型Emu Video&#xff0c;作为Meta发布的第二款视频生成模型&#xff0c;在视频生成领域发挥关键作用。 &#x1f33a;优质专栏回顾&am…

Axure难点解决分享:统计分析页面引入Echarts示例动态效果

亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! Axure产品经理精品视频课已登录CSDN可点击学习https://edu.csdn.net/course/detail/40420 课程主题:统计分析页面引入Echarts示例动态效果 主要内容:echart示例引入、大小调整、数据导入 应用场景:统计分析页面…

Docker 常见问题及其解决方案

一、安装与启动问题 1.1 安装失败 在不同操作系统上安装 Docker 时&#xff0c;可能会出现安装失败的情况。例如&#xff0c;在 Ubuntu 系统中&#xff0c;执行安装命令后提示依赖缺失。这通常是因为软件源配置不正确或系统缺少必要的依赖包。 解决方案&#xff1a; 确保系统…

IC解析之TPS92682-Q1(汽车LED灯控制IC)

目录 1 IC特性介绍2 主要参数3 接口定义4 工作原理分析TPS92682-Q1架构工作模式典型应用通讯协议 控制帧应答帧协议5 总结 1 IC特性介绍 TPS92682 - Q1 是德州仪器&#xff08;TI&#xff09;推出的一款双通道恒压横流控制器&#xff0c;同时还具有各种电器故障保护&#xff0c…

6.01 Python中打开usb相机并进行显示

本案例介绍如何打开USB相机并每隔100ms进行刷新的代码,效果如下: 一、主要思路: 1. 打开视频流、读取帧 self.cam_cap = cv2.VideoCapture(0) #打开 视频流 cam_ret, cam_frame = self.cam_cap.read() //读取帧。 2.使用定时器,每隔100ms读取帧 3.显示到Qt的QLabel…

2023华为od统一考试B卷【二叉树中序遍历】

前言 博主刷的华为机考题&#xff0c;代码仅供参考&#xff0c;因为没有后台数据&#xff0c;可能有没考虑到的情况 如果感觉对你有帮助&#xff0c;请点点关注点点赞吧&#xff0c;谢谢你&#xff01; 题目描述 思路 0.用Character数组存储树&#xff0c;index下标的左右…

在Spark搭建YARN

&#xff08;一&#xff09;什么是SparkONYarn模式 Spark on YARN&#xff08;Yet Another Resource Negotiator&#xff09;是 Spark 框架在 Hadoop 集群中运行的一种部署模式&#xff0c;它借助 Hadoop YARN 来管理资源和调度任务。 架构组成 ResourceManager&#xff1a;作…

LeetCode_sql刷题(3482.分析组织层级)

题目描述&#xff1a;3482. 分析组织层级 - 力扣&#xff08;LeetCode&#xff09; 表&#xff1a;Employees ------------------------- | Column Name | Type | ------------------------- | employee_id | int | | employee_name | varchar | | manager_id …

不用服务器转码,Web端如何播放RTSP视频流?

在物联网、智慧城市、工业互联网等新兴技术浪潮下&#xff0c;实时视频流&#xff08;如RTSP协议&#xff09;作为安防监控、生产巡检、远程协作等场景的核心数据载体&#xff0c;其价值愈发凸显。然而&#xff0c;一个长期困扰行业的痛点始终存在——‌如何在Web浏览器中直接播…

如何开发一款 Chrome 浏览器插件

Chrome是由谷歌开发的网页浏览器&#xff0c;基于开源软件&#xff08;包括WebKit和Mozilla&#xff09;开发&#xff0c;任何人都可以根据自己需要使用、修改或增强它的功能。Chrome凭借着其优秀的性能、出色的兼容性以及丰富的扩展程序&#xff0c;赢得了广大用户的信任。市场…