用React实现了一个自动滚动的内容区域,先上图图:
1.用处:
用于实现列表的自动滚动,鼠标进入可停止滚动
2.实现原理:
创建一个dom为ul,赋值为列表,然后拷贝这个dom赋值给第二个ul,然后判断屏幕高度跟滚动高度对比,利用requestAnimationFrame动画实现滚动
3.注意事项:
可在render里传需要渲染的表格,比如状态这一栏文字前面加个小圆圈等等,可以在render中传入,如果需要传任意内容,可修改ul里的内容,改为children由父组件传入
代码:
import React, { ReactNode } from 'react';
import style from './style/index.less';
interface ViewState {}
interface ViewProps {
height: number;
dataSource: Record<string, any>[];
columns: TableColumn[];
headerHeight?: number;
rowHeight?: number;
onRowClick?: (l: Record<string, any>) => void;
rowKey?: string;
scroll?: boolean;
}
export interface TableColumn {
key: string;
title: string;
width: number;
render?: (index: number, data: Record<string, any>, text: any) => string | ReactNode;
onClick?: (data: Record<string, any>) => void;
}
export default class ScrollTable extends React.Component<ViewProps, ViewState> {
private wrapperDom = React.createRef<any>();
private childDom1 = React.createRef<any>();
private childDom2 = React.createRef<any>();
private count = 0;
private reqAnimation: number;
public componentDidMount = () => {
this.reqAnimation = window.requestAnimationFrame(this.taskStart);
};
public componentWillUnmount = () => {
this.handleEnter();
};
public render() {
const { height, dataSource, columns, rowHeight = 27.5, headerHeight = 36, rowKey } = this.props;
return (
<div className={style.scrollContainer} style={{ height: `${height / 100}rem` }}>
<div className={style.scrollHead}>
{columns.map(l => (
<div key={l.key} style={{ width: `${l.width / 100}rem` }}>
{l.title}
</div>
))}
</div>
<div
className={style.scrollBody}
ref={this.wrapperDom}
style={{ height: `${(height - headerHeight) / 100}rem` }}
>
<ul ref={this.childDom1} onMouseOver={this.handleEnter} onMouseLeave={this.handleLeave}>
{dataSource.map((l, i) => (
<li
data-key={rowKey ? l[rowKey] : `list${i}`}
key={rowKey ? l[rowKey] : `list${i}`}
style={{ height: `${rowHeight / 100}rem` }}
>
{columns.map((p, c) => {
let pStyle: Record<string, any> = { width: `${p.width / 100}rem` };
if (l.lineColor) {
pStyle['color'] = l.lineColor;
}
return (
<div
key={`p${c}`}
style={pStyle}
onClick={e => {
e.stopPropagation();
this.onCellClick(l, p);
this.props.onRowClick?.(l);
}}
>
{p?.render?.(i, l, l[p.key]) || l[p.key]}
</div>
);
})}
</li>
))}
</ul>
<ul ref={this.childDom2} />
</div>
</div>
);
}
private taskStart = () => {
if (
this.childDom1.current?.clientHeight >= this.wrapperDom.current?.clientHeight &&
this.childDom2.current?.clientHeight < 10
) {
this.childDom2.current.innerHTML = this.childDom1.current.innerHTML;
}
if (this.wrapperDom.current.scrollTop >= this.childDom1.current.scrollHeight) {
this.wrapperDom.current.scrollTop = 0;
this.count = 0;
} else {
this.count += 1;
this.wrapperDom.current.scrollTop = this.count;
}
if (this.props.scroll) {
this.reqAnimation = window.requestAnimationFrame(this.taskStart);
}
};
private handleEnter = () => {
window.cancelAnimationFrame(this.reqAnimation);
};
private handleLeave = () => {
this.reqAnimation = window.requestAnimationFrame(this.taskStart);
};
private onCellClick = (l: Record<string, any>, p: TableColumn) => {
p?.onClick?.(l);
};
}
样式文件:
.scrollContainer {
width: 100%;
div {
text-align: center;
display: inline-block;
margin: 0;
font-size: 14px;
font-weight: normal;
font-stretch: normal;
letter-spacing: 0;
opacity: 0.9;
}
.scrollHead {
display: flex;
height: 42px;
align-items: center;
background-color: rgba(0, 183, 185, 0.3);
div {
font-size: 14px;
font-stretch: normal;
letter-spacing: 0;
color: #07d8b5;
font-family: MicrosoftYaHei, sans-serif;
opacity: 1;
}
}
.scrollBody {
overflow-y: scroll;
width: 100%;
scrollbar-width: none;
-ms-overflow-style: none;
ul {
height: auto;
padding: 0;
margin: 0;
}
li {
list-style: none;
position: relative;
cursor: pointer;
display: flex;
height: 36px;
color: #fff;
align-items: center;
}
li div {
line-height: 36px;
color: #fff;
white-space: nowrap; /* 文本不换行 */
overflow: hidden; /* 溢出部分隐藏 */
text-overflow: ellipsis; /* 溢出部分用"..."代替 */
}
li:hover {
background: rgba(43, 143, 171, 0.52);
> div {
color: #fff;
}
}
&::-webkit-scrollbar {
display: none;
}
li:nth-child(even) {
background-color: rgba(43, 143, 171, 0.13);
}
li:nth-child(even):hover {
background: rgba(43, 143, 171, 0.52);
color: #fff;
}
}
}