Skip to content

Realtime Merge Cells

Use the areaSelection feature to select multiple cells, then right-click to open a context menu for merging or splitting cells in realtime.

Implementation Approach

  1. Enable the areaSelection feature and listen to the onareaselectionchange event to get selection ranges
  2. Listen to the onrowmenu event (right-click) and show a context menu with ja-contextmenu
  3. On "Merge Cells" click, convert the selection range into rowspan/colspan info stored in a Map
  4. The mergeCells callback in column config reads merge info from the Map
  5. On "Split Cells" click, remove merge info within the selection range
loading

Core Logic

typescript
// 合并状态存储 key: `${rowId}__${colIndex}` value: { rowspan, colspan }
const mergeMap = new Map<string, { rowspan: number; colspan: number }>();

// 列配置中的 mergeCells 回调
function mergeCells({ row, col }) {
  const colIndex = columns.findIndex(c => c.dataIndex === col.dataIndex);
  return mergeMap.get(`${row.id}__${colIndex}`);
}

// 合并选中的单元格
function mergeSelectedCells() {
  const range = selectionRanges().at(-1);
  const { minRow, maxRow, minCol, maxCol } = normalizeRange(range);
  const startRow = dataSource()[minRow];

  // 清除范围内已有的合并信息,避免冲突
  for (let r = minRow; r <= maxRow; r++)
    for (let c = minCol; c <= maxCol; c++)
      mergeMap.delete(`${dataSource()[r].id}__${c}`);

  // 在左上角单元格设置合并信息
  mergeMap.set(`${startRow.id}__${minCol}`, {
    rowspan: maxRow - minRow + 1,
    colspan: maxCol - minCol + 1,
  });

  // 强制表格重新渲染
  setDataSource(ds => ds.slice());
}

// 拆分选中的单元格
function splitSelectedCells() {
  for (const range of selectionRanges()) {
    const { minRow, maxRow, minCol, maxCol } = normalizeRange(range);
    for (let r = minRow; r <= maxRow; r++)
      for (let c = minCol; c <= maxCol; c++)
        mergeMap.delete(`${dataSource()[r].id}__${c}`);
  }
  setDataSource(ds => ds.slice());
}

Notes

  1. After merging, only the top-left cell content is displayed. Covered cell data remains in the data source and will be restored after splitting
  2. A new merge operation automatically clears existing merge info within the selection range to avoid conflicts
  3. This approach also works with virtual scrolling mode

Released under the MIT License