最近做项目,需要根据条件对table cell 进行merge。于是做了一个小demo, 方便日后自己参考。先看效果图:
************************************************上代码******************************************************
step 1: 创建mock data
import { FC } from "react";
import TableOne from "./components/TableOne";
import TableTwo from "./components/TableTwo";
import TableThree from "./components/TableThree";
const tableData = {
data: [
{
category: "Fish",
name: "salmon",
yesterdayPrice: "¥23",
todayPrice: "¥23",
tomorrowPrice: "¥25"
},
{
category: "Fish",
name: "cod",
yesterdayPrice: "¥13",
todayPrice: "¥13.3",
tomorrowPrice: "¥15"
},
{
category: "Fish",
name: "plaice",
yesterdayPrice: "¥13",
todayPrice: "¥13.3",
tomorrowPrice: "¥15"
},
{
category: "Meat",
name: "beaf",
yesterdayPrice: "¥30",
todayPrice: "¥30",
tomorrowPrice: "¥25"
},
{
category: "Meat",
name: "mutton",
yesterdayPrice: "¥22",
todayPrice: "¥22.5",
tomorrowPrice: "¥25"
},
{
category: "Meat",
name: "chicken",
yesterdayPrice: "¥18",
todayPrice: "¥18",
tomorrowPrice: "¥20"
},
{
category: "Meat",
name: "pork",
yesterdayPrice: "¥18",
todayPrice: "¥22",
tomorrowPrice: "¥20"
},
]
}
export interface TableMergeExampleProps {
tableData: any;
}
const TableMergeExample: FC<TableMergeExampleProps> = ({ ...rest }) => {
return <>
<h3>Table One - Merge same neighbouring cell between rows </h3>
<TableOne tableData={tableData.data}/>
<h3>Table Two - Merge same neighbouring cell between columns</h3>
<TableTwo tableData={tableData.data} />
</>
}
export default TableMergeExample;
step 2: draw table One & table Two
import styled from "styled-components";
import { TableMergeExampleProps } from "../TableMergeExample";
import { FC, useEffect } from "react";
import { mergeTableRowCell } from "../../../utils/mergeTableRowCell";
const StyledTable = styled.table`
border-collapse: separate;
border: 1px solid cadetblue;
tr {
background-color: cadetblue;
}
tr, th {
padding: 10px 30px;
}
tr td:first-child {
font-weight: bold;
}
`;
const TableOne: FC<TableMergeExampleProps> = ({ tableData }) => {
useEffect(() => {
let table: HTMLTableElement= document.getElementById('tableOne') as HTMLTableElement
mergeTableRowCell(table);
}, [tableData]);
return <StyledTable id="tableOne">
<thead>
<tr>
<th></th>
<th>Category</th>
<th>Yesterday's Price</th>
<th>Today's Price</th>
</tr>
</thead>
{
tableData.map((item: any, index: number) => (
<tr key={`${item.category}-${index}`}>
<td>{item.category}</td>
<td>{item.name}</td>
<td>{item.yesterdayPrice}</td>
<td>{item.todayPrice}</td>
</tr>
))
}
</StyledTable>
};
export default TableOne;
import styled from "styled-components";
import { TableMergeExampleProps } from "../TableMergeExample";
import { FC, useEffect } from "react";
import { mergeTableColumnCell } from "../../../utils/mergeTableColumnCell";
const StyledTable = styled.table`
border-collapse: separate;
border: 1px solid darkkhaki;
tr {
background-color: darkkhaki;
}
tr, th {
padding: 10px 30px;
}
tr td:first-child {
font-weight: bold;
}
`;
const TableTwo: FC<TableMergeExampleProps> = ({ tableData }) => {
useEffect(() => {
const table: HTMLTableElement = document.getElementById('tableTwo') as HTMLTableElement;
mergeTableColumnCell(table)
}, [tableData]);
return <StyledTable id="tableTwo">
<thead>
<tr>
<th></th>
<th>Category</th>
<th>Yesterday's Price</th>
<th>Today's Price</th>
</tr>
</thead>
{
tableData.map((item: any, index: number) => (
<tr key={`${item.category}-${index}`}>
<td>{item.category}</td>
<td>{item.name}</td>
<td>{item.yesterdayPrice}</td>
<td>{item.todayPrice}</td>
</tr>
))
}
</StyledTable>
};
export default TableTwo;
step 3: 实现utility
如果相邻两列单元格内容相同,就merge成一个单元格
export function mergeTableColumnCell(table: HTMLTableElement) {
for(let rowIndex =0; rowIndex< table.rows.length; rowIndex++ ){
const row = table.rows[rowIndex];
let headerCells: HTMLTableCellElement[] = [];
headerCells[0] = row.cells[0];
for(let colIndex=1; colIndex < row.cells.length; colIndex++){
const cell = row.cells[colIndex];
if(cell.innerText === "") continue;
if (
headerCells[colIndex - 1] == null || headerCells[colIndex - 1].innerText !== cell.innerText
) {
headerCells[colIndex] = cell;
} else {
headerCells[colIndex - 1].colSpan++;
cell.remove();
colIndex--;
}
}
}
}
如果相邻两行单元格内容相同, 就merge成一个单元格
export function mergeTableRowCell(table: HTMLTableElement) {
let headerCells: HTMLTableCellElement[] = [];
for (let rowIndex = 1; rowIndex < table.rows.length; rowIndex++) {
const row = table.rows[rowIndex];
let removedCell = false;
let headerCellsIndex = 0;
for (let colIndex = 0; colIndex < row.cells.length; colIndex++) {
const cell = row.cells[colIndex];
// remove the style set for the first cell of the row
if(colIndex === 0 && removedCell) {
cell.style.fontWeight = "unset";
}
headerCellsIndex = !removedCell ? colIndex : headerCellsIndex + 1;
if (cell.innerText.trim() === '') continue;
if (headerCells[headerCellsIndex] === undefined || cell.innerText !== headerCells[headerCellsIndex].innerText) {
headerCells[headerCellsIndex] = cell;
} else {
headerCells[headerCellsIndex].rowSpan++;
cell.remove();
colIndex--;
removedCell = true;
}
}
}
}