文字的无限滚动
无限滚动效果
为了实现无限滚动的视觉效果,需要准备两段相同的文本,并让第二段文本的头部衔接在第一段文本的尾部;同时,为两段文本设置相同的滚动动画。
当第一段文本滚动到尾部时,如果能让第一段文本的位置瞬间移动回头部,并将第一段文本的头部内容替换为第二段的头部内容,同时动画也回到开始位置,这样,用户从视觉效果上看是感受不到变化的。
Marquee
组件及其样式的实现代码如下:
// Marquee.tsx
export default function Marquee(props) {
const { children } = props;
return (
<div className={styles.marquee}>
<div className={styles.ctx}>{children}</div>
<div className={styles.ctx}>{children}</div>
</div>
);
}
// App.tsx
export default function App() {
return (
<Marquee>只期待 後來的你 能快樂 那就是 後來的我 最想的</Marquee>
);
}
// Marquee.module.scss
.marquee {
width: 40px;
overflow: hidden;
position: relative;
.ctx {
animation: scroll 4s infinite linear; // 设置滚动动画
}
}
@keyframes scroll {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-100%);
}
}
悬停效果
实现鼠标悬停效果,通常有两种方法:
1)声明 isHovered
变量,通过监听 onMouseEnter
和 onMouseLeave
事件来动态修改 isHovered
的值,从而实现悬停效果。
2)使用 :hover
伪类,通过设置 animation-play-state
属性控制动画执行,从而实现悬停效果。
本文使用第二种方法,为整个外层容器设置 :hover
样式。当鼠标悬浮在整个容器上时,让内部元素的动画暂停。在 Marquee.module.scss
中添加如下样式:
// Marquee.module.scss
.marquee:hover {
.ctx {
animation-play-state: paused;
}
}
到此,基本功能已经实现,接下来开始实现表格组件的无限滚动。
表格的无限滚动
首先,实现根据配置动态生成表格的功能。
本文从传入的对象数组中提取所有的键,作为表头内容。
说明:本文实现的表头提取函数考虑了传入可选参数的情况,因此会遍历所有列表项并提取所有存在的键。如果表头属性完全固定,可以使用更简便的方法提取。
成功提取表头后,就可以遍历对象数组中的每一项,并根据对应的键将属性值填入相应的单元格中,逐步构建表格内容。
基于上述分析,表格组件的初步实现如下:
// DataTable.tsx
export default function DataTable<T extends object>({ dataSource }: { dataSource: Array<T> }) {
if (!Array.isArray(dataSource) || dataSource.length === 0) {
return null; // 数据源不是数组或数组为空,停止操作
}
const labelList = dataSource.reduce((acc: any, cur: any) => {
const keys = Object.keys(cur);
for (const key of keys) {
if (!acc.includes(key)) {
acc.push(key);
}
}
return acc;
}, []); // 提取表头
return (
<table>
<thead>
<tr>
{labelList.map((key, index) => (
<th key={index}>{key}</th>
))}
</tr>
</thead>
<tbody>
{dataSource.map((data, rowIndex) => (
<tr key={rowIndex}>
{labelList.map((key, columnIndex) => (
<!-- 如果是可选属性,赋予默认值 -->
<td key={columnIndex}>{data[key] ?? '-'}</td>
))}
</tr>
))}
</tbody>
</table>
);
}
在 App.tsx
中引入 DataTable
组件并传入 data
数组,就可以看到动态生成的表格。
// App.tsx
import DataTable from '@/components/DataTable';
export default function App() {
const data = [
{ name: 'Alice', city: 'New York' },
{ name: 'Bob', age: 30, city: 'San Francisco' },
{ name: 'Charlie', age: 35, city: 'Chicago' },
{ name: 'David', age: 40, city: 'Los Angeles', num: 0 },
];
return (
<DataTable dataSource={data} />
);
}
接下来,就是加上无限滚动的效果。
通常来说,可滚动表格只需要一个表头,也就是只需要一个 thead
部分,并且需要固定在顶部。按照上述文字滚动的实现思路,只要在一个 table
中实现两个相同的 tbody
内容,并给它们设置相同的动画即可。
同时,为了限制整体容器的高度,以防用户在表格位置滚动时感知到突变,造成不好的视觉体验,还需要给 table
加一层外部容器。
DataTable
组件的整体实现如下:
// DataTable.tsx
export default function DataTable<T extends object>({ dataSource }: { dataSource: Array<T> }) {
if (!Array.isArray(dataSource) || dataSource.length === 0) {
return null; // 数据源不是数组或数组为空,停止操作
}
const labelList = dataSource.reduce((acc: any, cur: any) => {
const keys = Object.keys(cur);
for (const key of keys) {
if (!acc.includes(key)) {
acc.push(key);
}
}
return acc;
}, []); // 提取表头
return (
<div className={styles.container}>
<table className={styles.table}>
<thead>
<tr>
{labelList.map((key, index) => (
<th key={index}>{key}</th>
))}
</tr>
</thead>
<tbody className={styles.tbody}>
{dataSource.map((data, rowIndex) => (
<tr key={rowIndex}>
{labelList.map((key, columnIndex) => (
<td key={columnIndex}>{data[key] ?? '-'}</td>
))}
</tr>
))}
</tbody>
<tbody className={styles.tbody}>
{dataSource.map((data, rowIndex) => (
<tr key={rowIndex}>
{labelList.map((key, columnIndex) => (
<td key={columnIndex}>{data[key] ?? '-'}</td>
))}
</tr>
))}
</tbody>
</table>
</div>
);
}
// DataTable.module.scss
@keyframes scroll {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-100%);
}
}
.container {
height: 160px;
overflow: hidden;
.table {
height: 100%;
overflow: hidden;
position: relative;
background-color: #e6e6e6;
.tbody {
animation: scroll 4s infinite linear;
}
}
}
table {
width: max-content;
border-spacing: 0;
thead {
height: 30px;
z-index: 99;
background-color: #adbcaa;
position: sticky;
top: 0;
tr {
color: #fff;
font-weight: bold;
}
}
th,
td {
width: max-content;
padding: 0 8px;
line-height: 30px;
text-align: center;
}
}
刷新页面,就可以看到表格的无限滚动效果已经成功实现了。
最后
前端新手一枚,欢迎大家提出问题或建议,一起进步。