15_通过指令实现table行合并

发布时间 2024-01-08 10:38:45作者: pleaseAnswer

实现效果

组件前提

iview 3.x版本的 table 组件并没有实现表格合并的功能;模拟4.x版本通过表格配置实现

本文通过指令实现 dom 操作

字段说明

  • ld:表格数据来源
    • columns:表头
    • showData:展示列表
  • spanMsg:对象数组
    • [{ 0: 5, 5: 3 }, { 0: 2, 2: 3}] 每一个对象代表一列
    • {0: 5, 5: 3} 表示从 第 0 行开始向下合并 5 行, 从第 5 行开始向下合并 3 行

组件实现

span-table-template.vue

<Table
   ref="table"
   border
   :columns="ld.columns"
   :data="ld.showData"
   :key="new Date().getTime()"
   v-dealSpan="spanMsg"
 ></Table>
props: {
  ld: Object,
  spanMsg: Array
}
directives: {
  dealSpan: {
    bind(el, binding, vnode) {
      // 表格上下文
      const __this = vnode.context;
      // 指令传参
      const spanMsg = binding.value;
      __this.$nextTick(() => {
        // 表格行
        const rows = el.querySelectorAll('tr.ivu-table-row');
        // 列从后往前处理
        for(let index = spanMsg.length - 1; index >= 0; index--) {
          let item = spanMsg[index]; // 处理某一列
          let rowIndex = 0;
          // 需使用 for..of 遍历节点
          for(let rowItem of rows) {
            let span = item[rowIndex]; // 某一列被合并的格数
            if(span) {
               // 给被合并到的单元格设置 rowspan 属性
              rowItem.querySelector(`td:nth-of-type(${index + 1})`).setAttribute('rowspan', span);
              // 记录 rowIndex < 列数 < span + rowIndex - 1 要移除第 index + 1 项
              let dealNum = span + rowIndex - 1;
              while(dealNum > rowIndex) {
                rows[dealNum].querySelector(`td:nth-of-type(${index + 1})`).remove();
                dealNum--;
              }
            }
            rowIndex++;
          }
        }
      });
    }
  }
}

应用

<SpanTableTemplate :ld="ld" :span-msg="[column1SpanMsg, column2SpanMsg]" />
async newSearch() {
  const { data: result } = await this.$axios.get(this.apix.list);
  this.ld.columns = this.setColumns(result.columns);
  this.dealTableData(result.data);
}
dealTableData(table) {
  const dataList = table.data_list;
  
  const showData = [];
  const column1SpanMsg = {};
  const column2SpanMsg = {};
    
  let lastTime = 0;
  let lastIndex = 0;
  let columnIndex = 0;
    
   /**
    * 思路:merge_time 下 json_cross.length
    * column2SpanMsg: [{ item.index: json_cross.length }]
    * column1SpanMsg: 若 item.merge_time 相同,则 [{ 0: add(json_cross.length) }]
    */
    dataList.map(item => {
      const { json_cross: cross, json_server: server, master_cross_id, merge_time: time } = item;
      column2SpanMsg[columnIndex] = cross.length;
      if (time === lastTime) {
        column1SpanMsg[lastIndex] = column1SpanMsg[lastIndex] + cross.length;
      } else {
        lastIndex = columnIndex;
        lastTime = time;
        column1SpanMsg[lastIndex] = cross.length;
      }
      cross.map(crossItem => {
        const { center_id, center_alias, wlevel, type } = crossItem;
        const obj = {
           merge_time: time,
           master_center_id: master_cross_id,
           slave_center_id: `${center_id}(${center_alias})`,
           wlevel,
           server_list: server[center_id]
             .map(serverItem => `${serverItem.server_name}(${serverItem.server_alias})`)
             .join(','),
           type
         };
         columnIndex++;
         showData.push(obj);
       });
    });
    this.ld.showData = showData;
    this.column1SpanMsg = column1SpanMsg;
    this.column2SpanMsg = column2SpanMsg;
}
# 接口返回的数据结构
data_list: {
  [{
    id: 2,
    json_cross: [
      { type: "master", center_id: 100007, center_alias: "cross_S100007", wlevel: 47 },
      { type: "slave", center_id: 100008, center_alias: "cross_S100008", wlevel: 45 }
    ],
    json_server: {
      100007: [
        { create_time: "2022-04-27 00:00:00", open_days: 582, server_alias: "test_S1001", server_id: 41, server_name: "更新服S1001" },
      100008: [
        { create_time: "2022-04-27 00:00:00", open_days: 582, server_alias: "test_S1002", server_id: 42, server_name: "更新服S1002" },
        { create_time: "2022-04-27 00:00:00", open_days: 582, server_alias: "test_S1003", server_id: 43, server_name: "更新服S1003" }
      ]
    },
    master_cross_id: 100007,
    merge_time: "2023-12-08 11:28:44",
    oper_admin: "刘清发",
    oper_time: "2023-11-29 11:29:02",
    platform: "test",
    remark: "",
    slave_cross_id: "100008"
  },
  {
    id: 1,
    json_cross: [
      { type: "master", center_id: 100004, center_alias: "cross_S100007", wlevel: 47 },
      { type: "slave", center_id: 100005, center_alias: "cross_S100008", wlevel: 45 }
      { type: "slave", center_id: 100006, center_alias: "cross_S100008", wlevel: 45 }
    ],
    json_server: {
      100004: [
        { create_time: "2022-04-27 00:00:00", open_days: 582, server_alias: "test_S1001", server_id: 41, server_name: "更新服S1001" },
      100005: [
        { create_time: "2022-04-27 00:00:00", open_days: 582, server_alias: "test_S1002", server_id: 42, server_name: "更新服S1002" },
        { create_time: "2022-04-27 00:00:00", open_days: 582, server_alias: "test_S1003", server_id: 43, server_name: "更新服S1003" }
      ],
      100006: [
        { create_time: "2022-04-27 00:00:00", open_days: 582, server_alias: "test_S1004", server_id: 44, server_name: "更新服S1004" },
        { create_time: "2022-04-27 00:00:00", open_days: 582, server_alias: "test_S1005", server_id: 45, server_name: "更新服S1005" }
      ]
    },
    master_cross_id: 100004,
    merge_time: "2023-12-08 11:28:44",
    oper_admin: "刘清发",
    oper_time: "2023-11-29 11:29:02",
    platform: "test",
    remark: "",
    slave_cross_id: "100005, 100006"
  }]
}