181 lines
4.9 KiB
JavaScript
181 lines
4.9 KiB
JavaScript
import React, { useImperativeHandle, useRef, useEffect, useCallback, useState, useMemo } from 'react'
|
|
|
|
const itemSize = 40;
|
|
|
|
const Table = React.forwardRef((props, ref) => {
|
|
const {columns = [], mainKey = 'id', autoNext = true, pageFinished, dataSource} = props;
|
|
|
|
const sizeRef = useRef();
|
|
const tableRef = useRef();
|
|
|
|
const [pageSize, setPageSize] = useState(0);
|
|
const [page, setPage] = useState(1);
|
|
|
|
const [data, setData] = useState([])
|
|
|
|
const totalPage = useMemo(
|
|
() => Math.ceil(data.length / pageSize),
|
|
[data, pageSize]
|
|
);
|
|
|
|
const currentData = useMemo(
|
|
() => data.slice(pageSize * (page - 1), pageSize * page),
|
|
[data, pageSize, page]
|
|
)
|
|
|
|
const tableSetting = useCallback(() => {
|
|
let { offsetHeight, scrollHeight, offsetWidth, scrollWidth } = tableRef.current;
|
|
let pageSize = Math.floor(offsetHeight / itemSize) - 1;
|
|
setPageSize(pageSize);
|
|
}, [])
|
|
|
|
const nextPage = useCallback(() => {
|
|
if(page + 1 > totalPage){
|
|
if(autoNext){
|
|
setPage(1);
|
|
}else{
|
|
pageFinished && pageFinished();
|
|
}
|
|
}else{
|
|
setPage(page + 1);
|
|
}
|
|
}, [totalPage, page])
|
|
|
|
useEffect(() => {
|
|
let innerWindow = sizeRef.current.contentDocument.defaultView;
|
|
innerWindow.addEventListener("resize", tableSetting);
|
|
tableSetting();
|
|
return () => {
|
|
innerWindow.removeEventListener("resize", tableSetting);
|
|
}
|
|
}, [tableSetting])
|
|
|
|
useEffect(() => {
|
|
if (dataSource) {
|
|
setData(dataSource);
|
|
setPage(1);
|
|
}
|
|
}, [dataSource]);
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
nextPage,
|
|
setData: data => {
|
|
setData(data);
|
|
setPage(1);
|
|
},
|
|
addData: addData => {
|
|
setData(data.concat(...addData))
|
|
},
|
|
updateData: updateData => {
|
|
setData(data.map(item => {
|
|
let mainValue = item[mainKey];
|
|
let update = updateData.find(i => i[mainKey] === mainValue);
|
|
if(update) item = update;
|
|
return item;
|
|
}))
|
|
},
|
|
deleteData: deleteData => {
|
|
setData(data.filter(item => {
|
|
let mainValue = item[mainKey];
|
|
return !deleteData.find(i => i[mainKey] === mainValue);
|
|
}))
|
|
},
|
|
}), [data, nextPage, mainKey])
|
|
|
|
return (
|
|
<div className="screen-table" ref={tableRef}>
|
|
<object
|
|
ref={sizeRef}
|
|
tabIndex="-1"
|
|
type="text/html"
|
|
aria-hidden="true"
|
|
data="about:blank"
|
|
style={{
|
|
display: "block",
|
|
position: "absolute",
|
|
top: 0,
|
|
left: 0,
|
|
width: "100%",
|
|
height: "100%",
|
|
border: "none",
|
|
padding: 0,
|
|
margin: 0,
|
|
opacity: 0,
|
|
zIndex: -1000,
|
|
pointerEvents: "none",
|
|
}}>
|
|
</object>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
{columns.map(({title, width}) => {
|
|
let thProps = {key: title};
|
|
if(width !== undefined) thProps.style = {width: width + 'px'}
|
|
return <th {...thProps}>{title}</th>
|
|
})}
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{currentData.map((item, index) => (
|
|
<tr key={item[mainKey]} className={index % 2 === 1 ? `delay-${index} stripe`: `delay-${index}`}>
|
|
{columns.map(config => {
|
|
let {title,code, render} = config;
|
|
if(render) return <td key={title}>{render(item[code], config, item)}</td>;
|
|
return <td key={title}>{item[code]}</td>
|
|
})}
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
<style jsx>{`
|
|
.screen-table{
|
|
height: 100%;
|
|
overflow: hidden;
|
|
text-align: center;
|
|
position: relative;
|
|
}
|
|
.screen-table > table{
|
|
width: 100%;
|
|
}
|
|
.screen-table th,
|
|
.screen-table td{
|
|
height: ${itemSize}px;
|
|
word-break: break-all;
|
|
color: rgba(255, 255, 255, 0.85);
|
|
font-weight: 400;
|
|
}
|
|
.screen-table th{
|
|
background: rgba(40, 163, 255, 0.25);
|
|
}
|
|
.screen-table .stripe td{
|
|
background: rgba(40, 163, 255, 0.1);
|
|
}
|
|
.screen-table tbody tr{
|
|
animation-name: show;
|
|
animation-duration: 0.3s;
|
|
animation-iteration-count: 1;
|
|
opacity: 0;
|
|
animation-fill-mode: forwards;
|
|
}
|
|
@keyframes show {
|
|
from {opacity: 0;}
|
|
to {opacity: 1;}
|
|
}
|
|
`}</style>
|
|
<style jsx global>{`
|
|
.delay-0{ animation-delay: 0s; }
|
|
.delay-1{ animation-delay: 0.2s; }
|
|
.delay-2{ animation-delay: 0.4s; }
|
|
.delay-3{ animation-delay: 0.6s; }
|
|
.delay-4{ animation-delay: 0.8s; }
|
|
.delay-5{ animation-delay: 1s; }
|
|
.delay-6{ animation-delay: 1.2s; }
|
|
.delay-7{ animation-delay: 1.4s; }
|
|
.delay-8{ animation-delay: 1.6s; }
|
|
.delay-9{ animation-delay: 1.8s; }
|
|
`}</style>
|
|
</div>
|
|
);
|
|
})
|
|
|
|
export default Table; |