簡単的なTable
Table
<table className={tableClass}>
<TableHeader columns={columns} />
<TableBody columns={columns} data={data} />
</table>
const columns = [
{ key: 'ア', title: 'ア', rowSpan: 3 },
{ key: 'イ', title: 'イ', rowSpan: 3 },
{ key: 'ウ', title: 'ウ', rowSpan: 3 },
{
key: 'エ', title: 'エ', colSpan: 2,
children: [ // 多次元データを一次元に変換し ITableColumn[][] => ITableColumn[]
{
key: 'エア', title: 'エア', colSpan: 2,
children: [
{ key: 'エアア', title: 'エアア' },
{ key: 'エアオ', title: 'エアオ' }
]
}
]
},
]
const data = [
{ key: 'ア', value: '1' },
{ key: 'イ', value: '2' },
{ key: 'ウ', value: '3' },
{ key: 'エ', value: '4' },
{ key: 'エア', value: '41' },
{ key: 'エアア', value: '4111' },
{ key: 'エアオ', value: '412' },
];
theader
特殊なデータ処理を行い、多次元データを一次元に変換し、表ヘッダーの作成を簡略化します。
TableHeader
export const setDataEntries = (columns: ITableColumn[], dataEntries: ITableColumn[][] = [], lv: number = 0) => {
dataEntries[lv] = dataEntries[lv] || [];
columns.forEach((item: ITableColumn) => {
dataEntries[lv].push(item);
if (item.children) {
return setDataEntries(item.children, dataEntries, lv + 1);
}
})
return dataEntries;
}
tbody
同じです。一次元のデータにより、順番にレンダリングする
TableBody
export const setDataEntries = (columns: ITableColumn[], dataEntries: string[] = []) => {
columns.forEach((item: ITableColumn) => {
if (item.children) {
return setDataEntries(item.children, dataEntries);
} else {
if (dataEntries.every(key => key !== item.key)) {
dataEntries.push(item.key)
}
}
})
return dataEntries;
}
pagination
実現
const createpPaginationItems = useCallback(() => {
const paginationItem = new Array(maxPage).fill(1).map((i, index: number) => {
const currentPage: number = index + 1;
return (
<div
key={index}
className={
paginationItemClass +
(page === currentPage ? ' ' + styles["pagination-item-active"] : '')
}
onClick={() => {
setPage(currentPage);
onPaginationChange?.(currentPage);
}}
>{index + 1}</div>
)
});
if (maxPage === 1) {
return paginationItem;
}
const showCount: number = 5;
if (page < showCount) {
paginationItem.splice(
maxPage - showCount,
maxPage - showCount - 1,
<EllispsePaginationItem
paginationItemClass={paginationItemClass}
keyName='rightEllispse'
/>
);
} else if (page > maxPage - showCount + 1) {
paginationItem.splice(
1,
maxPage - showCount - 1,
<EllispsePaginationItem
paginationItemClass={paginationItemClass}
keyName='leftEllispse'
/>
);
} else {
const half = Math.floor(showCount / 2);
paginationItem.splice(
page + half,
maxPage - page - half - 1,
<EllispsePaginationItem
paginationItemClass={paginationItemClass}
keyName='rightEllispse'
/>
);
paginationItem.splice(
1,
page - half - 1,
<EllispsePaginationItem
paginationItemClass={paginationItemClass}
keyName='leftEllispse'
/>
);
}
return paginationItem;
}, [maxPage, page]);
データやコンテンツを複数のページにわたって
const [dataKey, setDataKey] = useState<string[]>([]);
const [showData, setShowData] = useState<ITableDataItem[][]>([]);
useEffect(() => {
setDataKey(setDataEntries(columns));
}, [columns]);
useEffect(() => {
if (data.length > pageSize) {
setShowData(data.slice((page - 1) * pageSize, page * pageSize));
}else{
setShowData(data);
}
}, [data, pageSize, page]);
tfooter
tfooter
renderTFooter={(data, columns) => {
return (
<tr>
<td>会計:</td>
<td colSpan={4}>
{
data.reduce((a, c) => {
return a + c.reduce((f, g) => f + g.value, 0);
}, 0)
}
</td>
</tr>
)
}}
trとtdに自動的にclassNameを増加
addElementClass
const addElementClass = useCallback((ele: ReactElement): ReactElement => {
const { className: preClassName = '', children: preChildren = [] } = ele.props || {};
let children: ReactElement[] | null = [];
let className: string | null = '';
if (preChildren) {
const len = preChildren.length;
if (len) {
for (let i = 0; i < len; i++) {
const node = preChildren[i]?.props?.children;
if (typeof node !== 'object') {
children?.push(preChildren[i]);
} else {
children?.push(addElementClass(preChildren[i]));
}
}
} else {
children?.push(preChildren);
}
}
if (ele.type == 'tr') {
className = preClassName + ` ${trClass}`;
}
if (ele.type == 'td') {
className = preClassName + ` ${tdClass}`;
}
const newElement = React.createElement(ele.type, {
...ele.props,
className,
children,
});
return newElement;
}, []);
renderTFooter={(data, columns) => {
return (
<>
<tr className='abc' onClick={console.log}>
<td>会計:</td>
<td colSpan={4}>
{
data.reduce((a, c) => {
return a + c.reduce((f, g) => f + g.value, 0);
}, 0)
}
</td>
</tr>
<tr>
<td colSpan={1}>製表日:</td>
<td colSpan={4}>
令和6年1月23日
</td>
</tr>
</>
)
}}