• table表格动态合并


    最终效果图:

    一、JQ插件

    参考链接:http://www.jq22.com/jquery-info9377

    插件封装:

    (function ($) {
      $.fn.tablesMergeCell = function (options) {
        let defaults = {
          data: {}, // 后台数据
          automatic: true, // 是否自动合并
          cols: null, // 用数组表示列的索引,从0开始,然后根据指定列来处理(合并)相同内容单元格
          rows: null, // [[3, 4, 5], [6, 7]]自定义合并的行范围
        };
        let opts = $.extend(defaults, options);
    
        // 数据初始化
        let init = () => {
          let title = document.createElement('tr');
          for (let item of opts.data.title) {
            let th = document.createElement('th');
            th.innerHTML = item;
            title.append(th);
          }
          $(this).append(title);
    
          for (let rows of opts.data.content) {
            let tr = document.createElement('tr');
            for (let item of rows) {
              let td = document.createElement('td');
              td.innerHTML = item;
              tr.append(td);
            }
            $(this).append(tr);
          }
        };
    
        // 如果对javascript的closure和scope概念比较清楚, 这是个插件内部使用的private方法
        let tablesMergeRows = ($table, colIndex, rowIndex) => {
          $table.data('col-content', ''); // 存放单元格内容
          $table.data('col-rowspan', 1); // 存放计算的rowspan值 默认为1
          $table.data('col-td', $()); // 存放发现的第一个与前一行比较结果不同td(jQuery封装过的), 默认一个"空"的jquery对象
          $table.data('trNum', $('tbody tr', $table).length); // 要处理表格的总行数, 用于最后一行做特殊处理时进行判断之用
    
          // 我们对每一行数据进行"扫描"处理 关键是定位col-td, 和其对应的rowspan
          $('tbody tr', $table).each(function (index) {
            let $tr = $(this);
            // td:eq中的colIndex即列索引
            let $td = $('td:eq(' + colIndex + ')', $tr);
            let currentContent = $td.html();
            if (opts.automatic) {
              // 内容
              // 第一次时走此分支
              // console.log($table.data('col-content'));
              if ($table.data('col-content') === '') {
                $table.data('col-content', currentContent);
                $table.data('col-td', $td);
              } else {
                // 上一行与当前行内容相同
                if ($table.data('col-content') == currentContent) {
                  addRowspan(); // 上一行与当前行内容相同则col-rowspan累加, 保存新值
                } else {
                  newRowspan(); // 上一行与当前行内容不同
                }
              }
            } else {
              // 指定
              if (opts.rows.length > 0) {
                if (opts.rows[0].length == undefined) {
                  for (let i = 0; i < opts.rows.length; i++) {
                    customRowspan(opts.rows[i], opts.rows.length);
                  }
                } else {
                  for (let i = 0; i < opts.rows[rowIndex].length; i++) {
                    customRowspan(opts.rows[rowIndex][i], opts.rows[rowIndex].length);
                  }
                }
              }
            }
            function customRowspan(val, len) {
              if (index == val) {
                if ($table.data('col-content') == '') {
                  if (currentContent == '') {
                    currentContent = true;
                  }
                  $table.data('col-content', currentContent);
                  $td.attr('rowspan', len);
                } else {
                  $td.hide();
                }
              }
            }
            function addRowspan() {
              let rowspan = $table.data('col-rowspan') + 1;
              $table.data('col-rowspan', rowspan);
              // 值得注意的是 如果用了$td.remove()就会对其他列的处理造成影响
              $td.hide();
              // 最后一行的情况比较特殊一点
              // 比如最后2行 td中的内容是一样的, 那么到最后一行就应该把此时的col-td里保存的td设置rowspan
              if (++index == $table.data('trNum')) {
                $table.data('col-td').attr('rowspan', $table.data('col-rowspan'));
              }
            }
            function newRowspan() {
              // col-rowspan默认为1, 如果统计出的col-rowspan没有变化, 不处理
              if ($table.data('col-rowspan') !== 1) {
                $table.data('col-td').attr('rowspan', $table.data('col-rowspan'));
              }
              // 保存第一次出现不同内容的td, 和其内容, 重置col-rowspan
              $table.data('col-td', $td);
              $table.data('col-content', $td.html());
              $table.data('col-rowspan', 1);
            }
          });
        };
    
        // 合并列
        let tablesMergeCols = ($table, cols) => {
          $table.data('col-content', ''); // 存放单元格内容
          $table.data('col-colspan', 1); // 存放计算的cols值 默认为1
          $table.data('col-td', $()); // 存放发现的第一个与前一行比较结果不同td(jQuery封装过的), 默认一个"空"的jquery对象
          $table.data('trNum', $('tbody tr', $table).length); // 要处理表格的总行数, 用于最后一行做特殊处理时进行判断之用
          $('tbody tr', $table).each(function (index, item) {
            for (let j = 0; j < cols.length; j++) {
              let $td = $('td:eq(' + cols[j] + ')', item);
              let currentContent = $td.html();
              if (opts.automatic) {
                // 内容
                // 第一次时走此分支
                if ($table.data('col-content') === '') {
                  $table.data('col-content', currentContent);
                  $table.data('col-td', $td);
                } else {
                  // 上一列与当前行内容相同
                  if ($table.data('col-content') == currentContent) {
                    // 上一列与当前列内容相同则col-rowspan累加, 保存新值
                    addColspan();
                  } else {
                    // 上一列与当前列内容不同
                    newColspan();
                  }
                }
              }
    
              function addColspan() {
                let colspan = $table.data('col-colspan') + 1;
                $table.data('col-colspan', colspan);
                // 值得注意的是 如果用了$td.remove()就会对其他列的处理造成影响
                $td.hide();
                // 比如最后1行 连续多列td中的内容是一样的, 那么到最后一行就应该把此时的col-td里保存的td设置colspan
                if (index++ == $table.data('trNum') && j === cols.length - 1) {
                  $table.data('col-td').attr('colspan', $table.data('col-colspan'));
                }
              }
    
              function newColspan() {
                if ($table.data('col-colspan') !== 1) {
                  $table.data('col-td').attr('colspan', $table.data('col-colspan'));
                }
                // 保存第一次出现不同内容的td, 和其内容, 重置col-rowspan
                $table.data('col-td', $td);
                $table.data('col-content', $td.html());
                $table.data('col-colspan', 1);
              }
            }
          });
        };
    
        // 同样是个private函数 清理内存之用
        let dispose = $table => {
          $table.removeData();
        };
    
        return this.each(() => {
          let cols = opts.cols,
            rows = opts.rows;
          init();
          if (rows === null) {
            for (let i = cols.length - 1; cols[i] != undefined; i--) {
              tablesMergeRows($(this), cols[i]);
            }
          } else {
            for (let i = cols.length - 1, k = opts.rows.length - 1; cols[i] !== undefined; i--, k--) {
              tablesMergeRows($(this), cols[i], k);
            }
          }
          if (cols !== null) {
            tablesMergeCols($(this), cols);
          }
          dispose($(this));
        });
      };
    })(jQuery);

    页面调用:

    $('#table').tablesMergeCell({
        data: data.data,
        // automatic: false,
        cols: [0, 1, 2, 3],
        // rows: [3, 4],
    });

    二、element-ui动态合并行列

    参考链接:https://www.jianshu.com/p/cd34129cbfce

    element-ui通过给table传入span-method方法可以实现合并行或列,方法的参数是一个对象,里面包含当前行row、当前列column、当前行号rowIndex、当前列号columnIndex四个属性。该函数可以返回一个包含两个元素的数组,第一个元素代表rowspan,第二个元素代表colspan。 也可以返回一个键名为rowspancolspan的对象。

    // data
    private tableHeader: string[] = [];
    private tableData: object[] = [];
    private mergeConfig: any = {
        position: 0,
        rowsArr: [],
        colsArr: [],
        colsRange: [0, 3],
    };
    created() {
        this.init();
    }
    activated() {
        //
    }
    mounted() {
        //
    }
    // 初始化函数
    init() {
        this.getData();
        // 挂载函数
        this.getRowsArr(this.tableData);
        this.getColsArr(this.tableData);
    }
    getData() {
        let title = ['系统', '楼层', '区域', '机组编号', '1号', '2号', '3号', '合计', ];
        this.tableHeader = title;
        let data = [
            ['系统1', '楼层1', '区域1', '设备1', 1, 2, 3, 4],
            ['系统1', '楼层1', '区域2', '设备2', 1, 2, 3, 4],
            ['系统1', '楼层1', '区域2', '设备3', 1, 2, 3, 4],
            ['系统1', '楼层2', '区域3', '设备4', 1, 2, 3, 4],
            ['系统1', '楼层2', '区域3', '设备5', 1, 2, 3, 4],
            ['系统1', '楼层2', '区域3', '设备6', 1, 2, 3, 4],
            ['系统1', '合计', '合计', '合计', 1, 2, 3, 4],
            ['系统2', '楼层A', '区域4', '设备7', 1, 2, 3, 4],
            ['系统2', '楼层B', '区域5', '设备8', 1, 2, 3, 4],
            ['系统2', '楼层B', '区域5', '设备9', 1, 2, 3, 4],
            ['系统2', '合计', '合计', '合计', 1, 2, 3, 4],
            ['系统3', '楼层C', '区域6', '设备10', 1, 2, 3, 4],
            ['系统3', '楼层C', '区域7', '设备11', 1, 2, 3, 4],
            ['系统3', '楼层C', '区域8', '设备12', 1, 2, 3, 4],
            ['系统3', '合计', '合计', '合计', 1, 2, 3, 4],
        ];
        let obj = new Object();
        data.forEach((item, index) = > {
            item.forEach((_item, _index) = > {
                obj[title[_index]] = _item;
            });
            this.tableData.push(obj);
            // 清空对象
            obj = new Object();
        });
    }
    // 处理纵向数据
    getRowsArr(data: any[]) {
        let spanArr: number[] = [];
        for (let prop in data[0]) {
            for (let i = 0; i < data.length; i++) {
                if (i === 0) {
                    spanArr.push(1);
                    this.mergeConfig.position = 0;
                } else {
                    if (data[i - 1][prop] === data[i][prop]) {
                        spanArr.push(0);
                        spanArr[this.mergeConfig.position] += 1;
                    } else {
                        spanArr.push(1);
                        this.mergeConfig.position = i;
                    }
                }
            }
            this.mergeConfig.rowsArr.push(spanArr);
            spanArr = [];
        }
    }
    // 处理横向数据
    getColsArr(data: any[]) {
        let spanArr: number[] = [];
        let keyArr = Object.keys(data[0]);
        for (let item of data) {
            for (let i = this.mergeConfig.colsRange[0]; i <= this.mergeConfig.colsRange[1]; i++) {
                if (i === 0) {
                    spanArr.push(1);
                    this.mergeConfig.position = 0;
                } else {
                    if (item[keyArr[i - 1]] === item[keyArr[i]]) {
                        spanArr.push(0);
                        spanArr[this.mergeConfig.position] += 1;
                    } else {
                        spanArr.push(1);
                        this.mergeConfig.position = i;
                    }
                }
            }
            this.mergeConfig.colsArr.push(spanArr);
            spanArr = [];
        }
    }
    // 返回合并数组
    spanMethod({
        row, column, rowIndex, columnIndex
    }) {
        if (this.mergeConfig.colsRange[0] <= columnIndex && columnIndex <= this.mergeConfig.colsRange[1]) {
            const _row = this.mergeConfig.rowsArr[columnIndex][rowIndex];
            const _col = this.mergeConfig.colsArr[rowIndex][columnIndex];
            return [_row, _col];
        }
    }

    页面调用:

    <el-table :data="tableData" :span-method="spanMethod" border style=" 1000px;">
        <el-table-column v-for="(item, i) of tableHeader" :key="i" :label="item" :prop="item" align="center"></el-table-column>
    </el-table>
  • 相关阅读:
    js学习总结----案例之拖拽
    面向对象-数据属性
    Apply和call方法-扩充函数赖以生存的作用域
    JS中的function
    JS数组
    JS需要注意的细节和一些基础知识
    策略模式+简单工厂模式
    多态
    MVC3学习 八 Action和result过滤器及日志处理
    MVC3学习 七 JQuery方式和微软自带的AJAX请求
  • 原文地址:https://www.cnblogs.com/ziyoublog/p/13557939.html
Copyright © 2020-2023  润新知