Open shuangmianxiaoQ opened 3 years ago
看似简单的需求,但也踩了不少坑,一步一步来总能解决问题!
import React, { useEffect, useRef, useState } from 'react'; import cx from 'classnames'; import { requestInterval, clearRequestInterval } from '@essentials/request-interval'; import { px2vw } from '@/utils/helper'; import styles from './index.module.scss'; const list = [ { id: 1, picUrl: 'https://imagev2.xmcdn.com/group44/M02/69/AB/wKgKkVsRFeHSZ9NvAABqVg24cIc530.jpg', desc: '用户xxx获得专辑《德云社》', }, { id: 2, picUrl: 'https://imagev2.xmcdn.com/group44/M02/69/AB/wKgKkVsRFeHSZ9NvAABqVg24cIc530.jpg', desc: '用户xxx获得专辑《三体全集》', }, { id: 3, picUrl: 'https://imagev2.xmcdn.com/group44/M02/69/AB/wKgKkVsRFeHSZ9NvAABqVg24cIc530.jpg', desc: '用户xxx获得专辑《德云社》', }, { id: 4, picUrl: 'https://imagev2.xmcdn.com/group44/M02/69/AB/wKgKkVsRFeHSZ9NvAABqVg24cIc530.jpg', desc: '用户xxx获得专辑《三体全集》', }, ]; const Footer = () => { const [winnerList, setWinnerList] = useState<any[]>([]); const [animate, setAnimate] = useState(false); const listRef = useRef<any[]>([]); const rafInterval = useRef<any>(null); useEffect(() => { setWinnerList(list); listRef.current = list; if (list.length >= 3) { rafInterval.current = requestInterval(scrollUp, 1500); } return () => { clearRequestInterval(rafInterval.current); }; }, []); const scrollUp = () => { listRef.current.push(listRef.current[0]); setWinnerList(listRef.current); setAnimate(true); setTimeout(() => { listRef.current.shift(); setWinnerList(listRef.current); setAnimate(false); }, 1200); }; return ( <div className={styles.listWrapper}> <div className={cx(styles.list, { [styles.animate]: animate })} style={{ transform: animate ? `translateY(-${px2vw(55)}vw)` : 'none' }} > {winnerList.map(({ picUrl, desc }, index) => ( <div className={styles.item} key={index}> <img src={picUrl} alt="" className={styles.avatar} /> <div className={styles.desc}>{desc}</div> </div> ))} </div> </div> ); };
.listWrapper { height: 150px; overflow: hidden; } .animate { transition: all 0.3s linear; }
transform
translateY
marginTop
setInterval
setTimeout
requestAnimationFrame
onTransitionEnd
transition
实现原理
核心代码
遇到的问题及解决方法
transform
的translateY
替换marginTop
:防止重绘导致动画不流畅setInterval
的时间间隔要稍大于setTimeout
,防止还未删除又加入新的数据导致重复setInterval
依然有数据错乱的问题,排查后发现是切换Tab时出现,原来是浏览器离开当前窗口失焦时setInterval
并不能如愿的继续定时执行任务,时间误差导致了数据增多而错乱。针对该问题一开始使用setTimeout
代替setInterval
,但并不能解决问题。然后使用requestAnimationFrame
替换setInterval
,问题得到了解决onTransitionEnd
回调中删除数据,发现在移动端息屏后不滚动了,排查后发现数组中数据没被删除,自然是transition
未执行导致的,换回setTimeout
则完美解决问题