Table cell merge

最近做项目,需要根据条件对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;
        }
      }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值