1. 程式人生 > >動態單元格合併---antd的table元件

動態單元格合併---antd的table元件

怎麼合併

antd提供了河邊單元格的功能,支援合併行和列。以合併行為例,將第一行的高度rowSpan設定為2,其下一行高度設定為0,這樣就實現了兩行單元格合併,多行和列colSpan合併同理,給一個單元格設定值為要合併的行數,其餘待合併為0,即可合併。

動態合併場景

以工作中的實際場景為例,使用者通過表格維護所有門店的外賣資訊,有的門店只有一個渠道,有的門店有兩個渠道,以後不排除多個渠道;表格要以門店的維度進行資料展示,使用者可以在渠道的維度進行資料操作,同時後端返回的資料以渠道的維度返回工作量相對較少,前後端資料結構的拼裝解析相對更容易些。在這種情況下,前端需要將相同門店(資料已排序,相同門店資料緊挨著)的門店名稱、編碼等資訊進行單元格合併展示。效果如下:

怎麼動態合併

資料後端返回時,已經做了排序,統一門店的資料緊挨著一起,前端不需要考慮排序的問題,當然,做起來也很容易。回到合併問題上來,資料是以陣列的形式返回,前端需要做的是對資料進行遍歷比較,拿到與當前值重複的個數,加一後設置當前列colSpan即可,重複的項colSpan設定為0,過程大致如下如下:

  1. 首先我需要一個變數temp,儲存當前重複的值,避免已經被判定重複的行在渲染時執行重複的對比方法,初始值為空。
  2. 第一條資料來了,判斷一下值與temp不相等,拿著當前值進行對比方法,並設定temp為當前值。
  3. 對比方法裡面在定義一個變數i,初始值為1,重複一項,i+1,判定不重複時結束方法,返回i。
  4. 設定當前行colSpan值為i。
  5. 第二條資料來了,判斷了值與temp相等,設定當前行colSpan為0。
  6. 接下來的資料重複步驟2或5,表格最終渲染完成。

怎麼實現

/**
 * dataList為後端返回的陣列
**/
let temp; // 當前重複的值
 
// 表格部分省略部分程式碼,直接從render方法開始寫
render: (text) => {
  const obj = {
    children: text,
    props: {},
  };

  if (text !== temp) {
    let i = 1;
    temp = text;
    dataList.
forEach(item => { if (item === temp) { i += 1; }; }; obj.props.rowSpan = i; } else { obj.props.rowSpan = 0; } return obj; },

單列實現了,為了方便,封裝成一個方法放到公用方法檔案內,就可以在任何一個需要的地方直接呼叫了。

// 引數解釋:【當前列欄位】【表格陣列】【存有重複值的全域性變數】
const mergeCells = (text, array, temp) => {
    const obj = {
    children: text,
    props: {},
  };

  if (text !== temp) {
    let i = 1;
    temp = text;
    array.forEach(item => {
      if (item === temp) {
        i += 1;  
      };
    };
    obj.props.rowSpan = i;
  } else {
     obj.props.rowSpan = 0;
  }
  return obj;
}

但是同時支援多列時就會有一個問題,我需要每一列都定義一個自己的全域性變數,所以,我們需要優化一下,使方法更具通用性。

我能想到的解決方案是在表格渲染前獲取到重複值和第一個重複值所在位置的物件[{value: xxx, index: 2}],存放一個數組中,以便我確定哪幾行需要進行合併,我需要一個方法拿到並返回這個陣列,改造一下mergeCells方法。

// 獲取到重複值和第一個重複值所在位置的物件[{value: xxx, index: 2}],並返回一個數組。引數解釋【當前列欄位名稱】【table資料來源】
const getMerge = (colnum, array) => {
  const mergeArray = [];
  let temp = ''; // 重複值
  array.forEach((item, index) => {
    if (item[colnum] !=== temp) {
        temp = item[colnum];
        mergeArray.push({{value: item[colnum], index }});
    }
  });
  return mergeArray; 
};

// 引數解釋:【當前列欄位值】【當前列欄位名稱】【當前列index】【表格陣列】【存有重複值的陣列】
const mergeCells = (text, colnum, index, array, mergeArray) => {
  const obj = {
    children: text,
    props: {},
  };
  const temp = _.findIndex(mergeArray, (o) => o.value === text); // 藉助lodash庫查詢當前欄位在重複值陣列內的位置,沒有則返回-1
  if ( temp > -1) { // 判斷當前行需要合併
    if (index === mergeArray[temp].index % 10 ) {
    // mergeArray[temp].index % 10 相容前端分頁時colnum的index與table陣列index的比較
      let i = 1;
      array.forEach(item => {
        if (item[colnum] === text) {
          i += 1;  
        };
      };
      obj.props.rowSpan = i;
      } else {
        obj.props.rowSpan = 0;
    }
  }
  return obj;
}