React项目中如何让滑块根据选中项索引移动到对应列表项位置
React列表滑块跟随选中项移动解决方案
核心实现逻辑
- 给所有列表项绑定ref集合,用于实时获取每个元素的实际位置
- 用state单独保存滑块的纵向偏移量,不要在渲染时动态计算初始值
- 监听选中下标的变化,每次选中项更新时,获取当前选中项距离父容器顶部的
offsetTop值,同步给滑块偏移量的state - 给滑块添加CSS过渡属性,实现平滑移动效果
核心代码示例
JSX部分
import { useState, useRef, useEffect } from 'react'; const listOptions = ['选项1', '选项2', '选项3', '选项4', '选项5']; export default function App() { // 保存当前选中下标 const [activeIndex, setActiveIndex] = useState(0); // 保存滑块纵向偏移量 const [sliderY, setSliderY] = useState(0); // 存储所有列表项的ref const itemRefs = useRef([]); // 选中项变化时更新滑块位置 useEffect(() => { const currentItem = itemRefs.current[activeIndex]; if (currentItem) { setSliderY(currentItem.offsetTop); } }, [activeIndex]); return ( <div className="list-wrapper"> {/* 左侧滑块 */} <div className="left-slider" style={{ transform: `translateY(${sliderY}px)` }} /> {/* 选项列表 */} {listOptions.map((text, idx) => ( <div key={idx} ref={el => itemRefs.current[idx] = el} className={`list-item ${activeIndex === idx ? 'active' : ''}`} onClick={() => setActiveIndex(idx)} > {text} </div> ))} </div> ); }
CSS部分
.list-wrapper { position: relative; width: 220px; padding: 8px 0; } .left-slider { position: absolute; left: 0; top: 8px; /* 和父容器的上padding对齐 */ width: 3px; height: 28px; background-color: #1890ff; border-radius: 2px; transition: transform 0.25s cubic-bezier(0.3, 0, 0.7, 1); } .list-item { height: 28px; line-height: 28px; padding-left: 12px; cursor: pointer; } .list-item.active { color: #1890ff; font-weight: 500; }
原有问题原因
之前的实现之所以滑块每次都从第一项位置开始移动,是因为没有用独立的state存储滑块的当前偏移量,每次渲染都基于初始位置计算过渡,导致过渡的起点始终是初始的第一项位置。
内容的提问来源于stack exchange,提问作者DSteman
相关产品推荐
相关产品推荐

