实现表格数据(无刷新)轮询展示功能

302 阅读2分钟

功能描述

在React中实现,当表格数据超出容器盒子时,实现数据的无刷新轮询展示,同时当鼠标划入时停止滚动,当鼠标移出后继续滚动的效果。

组件源码

import React, { Component } from 'react'
import styles from './index.less'

/**
 * UI组件
 */
// import { SafeBox } from '../Common'

/**
 * 工具类
 */
import classNames from 'classnames'

// import { domMouseScroll } from './utils'

/**
 * 配置文件
 */
import { tableAnimation } from '@/containers/SafeEvent/config/config.js'
export default class Index extends Component {
	constructor(props) {
		super(props)
		this.domTbody = React.createRef()
		this.domFixed = React.createRef()
		this.state = {
			tData: [1, 2, 3, 4, 5, 6, 7, 8, 9],
		}
	}

	componentDidMount() {
		this.runMarquee()
	}
	componentWillUnmount() {
		this.stopMarquee()
	}
	// 运动
	runMarquee = () => {
		// this.stopMarquee()
		this.newStartFun()
	}

	stopMarquee = () => {
		clearInterval(this.timerMarquee)
		clearInterval(this.timerNewFun)
	}

	// 滚动事件
	newStartFun = () => {
		this.timerNewFun = setInterval(() => {
			clearInterval(this.timerMarquee)
			clearInterval(this.timerNewFun)
			this.verticalMarquee(1)
			this.newStartFun()
		}, tableAnimation.interval) //停顿时间
	}
	//滚动事件
	verticalMarquee = (num) => {
		this.domFixed.scrollTop += num
		if (this.domFixed) {
			if (this.domFixed.scrollTop && this.domFixed.scrollTop % 42 === 0) {
				clearInterval(this.timerMarquee)
				return
			}

			this.domFixed.scrollTop >= this.domTbody.scrollHeight
				? (this.domFixed.scrollTop = 0)
				: this.domFixed.scrollTop++

			clearInterval(this.timerMarquee)
			this.timerMarquee = setInterval(() => {
				this.verticalMarquee(0)
			}, tableAnimation.frame) //动画帧率
		}
	}

	tHeaderFun = (fixed) => {
		let templateDom = (
			<thead>
				<tr>
					<th>事故时间</th>
					<th>事故地点</th>
					<th>伤亡人数</th>
					<th>经济损失</th>
					<th>数据来源</th>
					<th>受理时间</th>
					<th>事故内容</th>
				</tr>
			</thead>
		)
		return fixed ? (
			<table className={classNames(styles.fixedHead)}>
				{templateDom}
			</table>
		) : (
			templateDom
		)
	}

	bgColorFun = (numb, index) => {
		const { tData } = this.state

		const bgColor = 'rgba(255, 255, 255, 0.1)'

		if (numb === 2) {
			if (tData.length % 2 === 0) {
				if (index % 2 === 0) {
					return bgColor
				} else {
					return 'transparent'
				}
			} else {
				if (index % 2 === 0) {
					return 'transparent'
				} else {
					return bgColor
				}
			}
		} else {
			if (tData.length % 2 === 0) {
				if (index % 2 === 0) {
					return 'transparent'
				} else {
					return bgColor
				}
			} else {
				if (index % 2 === 0) {
					return bgColor
				} else {
					return 'transparent'
				}
			}
		}
	}

	render() {
		const { tData } = this.state
		return (
			<div className={styles.normal}>
				<div className={styles.titBox}>
					<span className={styles.tTit}>事件数量</span>
					<span className={styles.tValue}>500</span>
					<span className={styles.tUnit}></span>
				</div>
				{this.tHeaderFun(true)}
				<div
					ref={(elem) => {
						this.domFixed = elem
					}}
					className={classNames(styles.contentTable, 'tab-scroll')}
					onMouseOver={this.stopMarquee}
					onMouseOut={this.runMarquee}
				>
					<table>
						{this.tHeaderFun()}
						{[1, 2, 3].map((tElem, tIndex) => {
							return (
								<tbody
									ref={(elem) => {
										this.domTbody = elem
									}}
									key={tIndex}
								>
									{tData.map((elem, index) => {
										return (
											<tr
												key={index}
												style={{
													background: this.bgColorFun(
														tElem,
														index + 1
													),
												}}
											>
												<td>2021-05</td>
												<td>天水</td>
												<td>{elem * 110}</td>
												<td>{elem * 1000}</td>
												<td>新闻</td>
												<td>2021-05</td>
												<td>......</td>
											</tr>
										)
									})}
								</tbody>
							)
						})}
					</table>
				</div>
			</div>
		)
	}
}

css样式

.normal {
	position: relative;
	height: 100%;

	.titBox {
		position: relative;
		width: 150px;
		height: 32px;
		background: url('./img/tit_bg.png') no-repeat;
		background-size: 100% auto;

		.tTit {
			margin-left: 8px;

			font-family: Noto Sans SC;
			font-style: normal;
			font-weight: normal;
			font-size: 14px;
			line-height: 32px;
			/* identical to box height, or 100% */

			color: #ffffff;
		}

		.tValue {
			position: absolute;
			right: 22px;
			height: 100%;
			font-family: Noto Sans SC;
			font-style: normal;
			font-weight: normal;
			font-size: 24px;
			line-height: 32px;
			background-image: -webkit-linear-gradient(top, #ffffff, #a3eefc);
			-webkit-background-clip: text;
			-webkit-text-fill-color: transparent;
		}

		.tUnit {
			position: absolute;
			right: 8px;
			height: 100%;
			font-family: Noto Sans SC;
			font-style: normal;
			font-weight: normal;
			font-size: 12px;
			line-height: 32px;
			/* identical to box height, or 100% */

			color: #2ea0f5;
		}
	}

	.contentTable {
		position: relative;
		float: left;
		margin-top: 25px;
		height: 340px;
		width: 100%;
		overflow: hidden;
		overflow-y: auto;

		/* 兼容chrome 和Safari*/
		&::-webkit-scrollbar {
			width: 0 !important;
			height: 0 !important;
		}
	}
	.fixedHead {
		position: absolute;
		top: 57px;
		z-index: 1;

		th {
			background: #114959;
		}
	}

	table {
		width: 100%;

		th,
		td {
			width: 92px;
			text-align: center;
			height: 42px;
		}

		tr {
			font-family: Noto Sans SC;
			font-style: normal;
			font-weight: normal;
			font-size: 14px;
			line-height: 14px;
			/* or 100% */

			text-align: center;

			color: #c8e8ef;

			// &:nth-child(odd) {
			// 	background: rgba(255, 255, 255, 0.1);
			// }
		}
		th {
			font-family: Noto Sans SC;
			font-style: normal;
			font-weight: normal;
			font-size: 14px;
			line-height: 14px;
			/* identical to box height, or 100% */

			color: #c8e8ef;
			background: rgba(0, 221, 138, 0.15);
		}
	}
}