尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

handsontable实现新增删除行(双行)

handsontable实现新增删除行(双行)
📅 发布时间:2026/6/20 6:50:26
handsontable实现新增删除行(双行)

// 配置方法

const tableSettings = computed(() => {
   return {
      ...hotTableParams,
      nestedHeaders: false,
      filters: false,
      columnSorting: false,
      height: 358,
      rowHeaders: false,
      colHeaders: [
         '企业名称',
         '类型',
         '1月',
         '2月',
         '3月',
         '4月',
         '5月',
         '6月',
         '7月',
         '8月',
         '9月',
         '10月',
         '11月',
         '12月',
         '操作',
      ],
      columns: [
         {
            data: 'name',
            className: 'htCenter htMiddle',
            readOnly: false, // 企业名称固定只读
         },
         {
            data: 'type',
            className: 'htCenter htMiddle',
            readOnly: true, // 类型(电量/电价)固定只读
         },
         // 月份列(可编辑)
         { data: 'one', type: 'numeric', className: 'htRight' },
         { data: 'two', type: 'numeric', className: 'htRight' },
         { data: 'three', type: 'numeric', className: 'htRight' },
         { data: 'four', type: 'numeric', className: 'htRight' },
         { data: 'five', type: 'numeric', className: 'htRight' },
         { data: 'six', type: 'numeric', className: 'htRight' },
         { data: 'seven', type: 'numeric', className: 'htRight' },
         { data: 'eight', type: 'numeric', className: 'htRight' },
         { data: 'nine', type: 'numeric', className: 'htRight' },
         { data: 'ten', type: 'numeric', className: 'htRight' },
         { data: 'eleven', type: 'numeric', className: 'htRight' },
         { data: 'twelve', type: 'numeric', className: 'htRight' },
         // 操作列(自定义渲染+合并)
         {
            renderer: (instance, td, row) => {
               td.innerHTML = '';
               if(props.isEdit) return td;
               if(row === 0 || row === 1) return td;
               if(row % 2 === 0) {
                  const container = document.createElement('div');
                  container.style.width = '100%';
                  container.style.height = '100%';
                  container.style.display = 'flex';
                  container.style.alignItems = 'center';
                  container.style.justifyContent = 'center';
                  container.style.gap = '8px';

                  // 新增按钮
                  const addBtn = document.createElement('span');
                  addBtn.className = 'mdi mdi-plus';
                  addBtn.style.fontSize = '18px';
                  addBtn.style.width = '18px';
                  addBtn.style.height = '18px';
                  addBtn.style.cursor = 'pointer';
                  addBtn.style.display = 'flex';
                  addBtn.style.alignItems = 'center';
                  addBtn.style.justifyContent = 'center';

                  addBtn.onclick = (e) => {
                     e.stopPropagation();
                     const hot = instance;
                     const currentRow = row;

                     hot.alter('insert_row_below', currentRow + 1, 2);

                     hot.setDataAtCell(currentRow + 2, 0, '');
                     hot.setDataAtCell(currentRow + 2, 1, '电量');
                     hot.setDataAtCell(currentRow + 3, 0, '');
                     hot.setDataAtCell(currentRow + 3, 1, '电价');

                     const currentMergedCells = [
                        ...hot.getPlugin('mergeCells').mergedCellsCollection
                           .mergedCells,
                     ];
                     currentMergedCells.push(
                        { row: currentRow + 2, col: 0, rowspan: 2, colspan: 1 },
                        { row: currentRow + 2, col: 14, rowspan: 2, colspan: 1 },
                     );
                     hot.updateSettings({ mergeCells: currentMergedCells });
                  };

                  // 删除按钮
                  const delBtn = document.createElement('span');
                  delBtn.className = 'mdi mdi-trash-can-outline';
                  delBtn.style.fontSize = '18px';
                  delBtn.style.width = '18px';
                  delBtn.style.height = '18px';
                  delBtn.style.cursor = 'pointer';
                  delBtn.style.display = 'flex';
                  delBtn.style.alignItems = 'center';
                  delBtn.style.justifyContent = 'center';

                  delBtn.onclick = (e) => {
                     e.stopPropagation();
                     const hot = instance;
                     if(hot.countRows() <= 4) return;

                     const currentRow = row;
                     const rowsToRemove = 2;

                     // 1. 获取原始合并规则并深拷贝
                     const mergeCellsPlugin = hot.getPlugin('mergeCells');
                     const originalMerged = JSON.parse(
                        JSON.stringify(
                           mergeCellsPlugin.mergedCellsCollection.mergedCells,
                        ),
                     );

                     // 2. 删除2行
                     hot.alter('remove_row', currentRow, rowsToRemove);

                     // 3. 处理合并规则:过滤重复 + 位移行索引
                     const updatedMerged = originalMerged
                        .filter(
                           (cell) =>
                              !(
                                 cell.row >= currentRow &&
                                 cell.row < currentRow + rowsToRemove
                              ),
                        ) // 过滤已删除行的规则
                        .map((cell) => {
                           if(cell.row > currentRow) {
                              return { ...cell, row: cell.row - rowsToRemove }; // 后续规则行索引减2
                           }

                           return cell;
                        })
                        // 去重:确保每个(row, col)组合唯一
                        .filter((cell, index, self) => {
                           return (
                              self.findIndex(
                                 (c) => c.row === cell.row && c.col === cell.col,
                              ) === index
                           );
                        });

                     // 4. 重新设置合并规则
                     hot.updateSettings({ mergeCells: updatedMerged });
                  };

                  container.appendChild(addBtn);
                  container.appendChild(delBtn);
                  td.appendChild(container);
               }
               else {
                  td.style.visibility = 'visible';
                  td.style.pointerEvents = 'none';
               }

               return td;
            },
         },
      ],
      dropdownMenu: false,
      cells: (row, col) => {
         // 合计行(0、1行)所有单元格只读
         if(row === 0 || row === 1 || col === 14) {
            return { readOnly: true };
         }

         // 企业名称列(0列)和类型列(1列)只读
         if(
            ((col === 0 || col === 1) && (row === 0 || row === 1)) ||
            col === 1 ||
            col === 14
         ) {
            return { readOnly: true };
         }

         return { readOnly: props.isEdit };
      },
      mergeCells: true,
      async afterChange(changes) {
         if(!changes || changes.length === 0) return;

         const hot = this; // Handsontable实例
         const data = hot.getSourceData(); // 表格原始数据

         // 定义月份字段映射(与columns中“1月-12月”的data属性对应)
         const monthFields = [
            'one',
            'two',
            'three',
            'four',
            'five',
            'six',
            'seven',
            'eight',
            'nine',
            'ten',
            'eleven',
            'twelve',
         ];

         // 遍历每个月份,分别计算“电量合计”和“电价合计”
         monthFields.forEach((field) => {
            let elecSum = 0; // 电量合计
            let priceSum = 0; // 电价合计

            // 遍历所有企业行(跳过前2行“合计行”)
            for(let i = 2; i < data.length; i += 2) {
               // 电量行(类型为“电量”)
               const elecRow = data[i];
               elecSum += Number(elecRow[field] || 0); // 确保转为数字

               // 电价行(类型为“电价”)
               const priceRow = data[i + 1];
               priceSum += Number(priceRow[field] || 0); // 确保转为数字
            }

            // 更新“合计行”的对应月份值
            data[0][field] = elecSum; // 电量合计行(第0行)
            data[1][field] = priceSum; // 电价合计行(第1行)
         });

         let totalElecSum = 0; // 总电量合计(所有月份电量合计的总和)
         let weightedPriceSum = 0; // 加权电价合计

         // 1. 计算总电量(合计行的电量总和)
         monthFields.forEach((field) => {
            totalElecSum += Number(data[0]?.[field] || 0); // 用可选链操作符?.避免data[0]为undefined
         });

         // 2. 遍历所有企业行,计算加权电价
         for(let i = 2; i < data.length; i += 2) { // 企业行是“电量行+电价行”,每次跳2行
            monthFields.forEach((field) => {
               const enterpriseElec = Number(data[i]?.[field] || 0); // 企业当月电量(防undefined)
               const enterprisePrice = Number(data[i + 1]?.[field] || 0); // 企业当月电价(防undefined)

               if(totalElecSum > 0) {
                  const weight = enterpriseElec / totalElecSum; // 企业电量占总电量的权重
                  weightedPriceSum += enterprisePrice * weight; // 累加该企业的加权电价
               }
            });
         }

         // 更新总合计值
         totalElec.value = totalElecSum;
         totalPrice.value = weightedPriceSum.toFixed(2);

         // 重新渲染表格(确保合计值显示)
         hot.loadData(data);
      },
   };
});

相关新闻

  • 2025年国产角接触球轴承厂家推荐 一文了解轴承厂家选择标准
  • 前后端不分离的springboot应用,静态文件修改了不更新的问题
  • 2025 年铝卷厂家最新推荐榜,聚焦企业技术实力与市场口碑深度解析铝板铝卷/铝卷板/橘皮铝卷/压花铝卷/防锈铝卷/花纹铝卷公司推荐

最新新闻

  • 2026年6月宁波生成式引擎GEO优化服务商技术实力解析 - 起跑123
  • 2026 年南通市厨卫屋顶防水修缮三家对比测评 吉修匠 99.8 分稳居榜首 - 吉修匠
  • 表主必存!2026年宝玑官方售后中心实地体核验报告:全国网点最新地址、电话同步升级启用 - 亨得利中国服务中心
  • ApexSQL Log 2018:SQL Server事务日志可视化分析与精准回滚工具
  • 孤能子视角:涌现的本体论、动力学与认识论
  • Redis的数据结构

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号