
本文详解如何使用 react 与 css 实现平滑、无限循环的垂直向上文字轮播,确保新条目入场时旧条目仍部分可见并自然移出,避免突兀跳变,适用于动态长度的 cms 文本列表。
本文详解如何使用 react 与 css 实现平滑、无限循环的垂直向上文字轮播,确保新条目入场时旧条目仍部分可见并自然移出,避免突兀跳变,适用于动态长度的 cms 文本列表。
要打造如参考视频中所示的“上滑式无缝轮播”效果——即当前项完全进入视图的同时,前一项尚未完全消失(仍轻微可见),随后淡出并上移隐去——关键不在于单纯控制 transform: translateY(),而在于精准管理三个状态的视觉层叠与过渡:隐藏态(translateY(100%))、激活态(translateY(0))和退出态(translateY(-100%)),并辅以同步的 opacity 过渡。
以下为完整实现方案,已优化可维护性与边界逻辑:
✅ 核心思路:三态 CSS 类 + 模运算索引映射
-
.slider-item:默认隐藏在视图下方(translateY(100%)),透明度为 0; -
.slider-item.active:当前显示项,位于视图中心(translateY(0)),opacity: 1; -
.slider-item.prev-active:上一轮显示项,需向上滑出视图(translateY(-100%)),同时渐隐(opacity: 0);
⚠️ 注意:直接用 index === currentIndex - 1 判断前一项会在循环首尾失效(如 currentIndex = 0 时 -1 越界)。正确做法是利用模运算映射逻辑前驱:
(index + 1) % texts.length === currentIndex
该表达式确保当 currentIndex = 0 时,唯一满足条件的是 index = texts.length - 1(即最后一个元素),完美闭环。
✅ 完整代码实现(React + CSS)
JSX 部分(TextSlider.js):
import React, { useState, useEffect } from 'react';
const TextSlider = ({ texts }) => {
const [currentIndex, setCurrentIndex] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCurrentIndex(prev => (prev + 1) % texts.length);
}, 2700);
return () => clearInterval(interval);
}, [texts.length]);
return (
<div classname="text-slider">
{texts.map((text, index) => (
<div key="{index}" classname="{`" slider-item currentindex : texts.length="==">
<h1 style="{{" fontsize: margin:>{text}</h1>
@@##@@
</div>
))}
</div>
);
};
export default TextSlider;
CSS 部分(styles.css):
.text-slider {
height: 120px; /* 建议略高于单个 item 高度,留出过渡余量 */
overflow: hidden;
position: relative;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.slider-item {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 0.8rem;
opacity: 0;
transform: translateY(100%);
transition: transform 0.5s cubic-bezier(0.33, 1, 0.68, 1),
opacity 0.5s ease;
pointer-events: none; /* 避免非 active 元素干扰交互 */
}
.slider-item.active {
opacity: 1;
transform: translateY(0);
pointer-events: auto;
}
.slider-item.prev-active {
opacity: 0;
transform: translateY(-100%);
}
⚠️ 关键注意事项
-
高度适配:
.text-slider的height应大于单个.slider-item的实际渲染高度(含文字、图片、间距),否则可能裁剪过渡过程。建议通过浏览器调试工具测量后微调。 -
缓动函数优化:CSS 中使用
cubic-bezier(0.33, 1, 0.68, 1)替代ease,可让入场更轻快、退场更舒缓,增强“漂浮感”。 -
无障碍友好:为
<h1></h1>添加语义化aria-live="polite"可提升屏幕阅读器体验(若需):<h1 aria-live="polite" style="{{" fontsize: margin:>{text}</h1> -
CMS 动态适配:该方案天然支持
texts数组长度变化——useEffect依赖[texts.length]确保轮播节奏自动适应新增/删减项。
✅ 效果总结
此实现达成:
- ✅ 无限循环、无跳变重启;
- ✅ 新项上滑入场时,旧项同步上滑淡出,中间存在短暂双项共存(半透明重叠);
- ✅ 完全响应式,适配任意长度文本列表;
- ✅ 逻辑清晰,CSS 与 JS 职责分离,易于定制动画时长、颜色、尺寸等。
只需将 texts 替换为 CMS API 返回的数据数组,即可开箱即用。











