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="width: 1000px;">
    <el-table-column v-for="(item, i) of tableHeader" :key="i" :label="item" :prop="item" align="center"></el-table-column>
</el-table>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM