数字滚动效果

您所在的位置:网站首页 js滚动数字 数字滚动效果

数字滚动效果

2024-07-15 14:25| 来源: 网络整理| 查看: 265

在需求中我需要实现一个倒计时的效果,这个倒计时效果类似滚轮的效果 分析效果:

实现一个类似滚轮的效果,容器向上滚动 可以实现多个滚轮的联动 无缝滚动

容器中列举了所有的可能的值,实现上述效果,就是匀速更改容器的偏移值 这种方案类似于无缝轮播的方案,下面来介绍一下这种方案 在倒计时中,元素值从0到9一共十个值,下面是具体的代码

{ Array.from({length: 10}).map((_, index) => ( {index} )) } const [percent, setPercent] = useState(0); useInterval(() => { setPercent(prev => (prev + 1) % 10); }, 1000) .slider { height: 36px; width: 20px; overflow: hidden; position: relative; } .pager_tape { display: flex; flex-direction: column; position: absolute; top: 0; transition: transform 500ms; } .ele { font-size: 26px; line-height: 36px; }

在上面代码中,我们通过设置容器的偏移位置来控制显示的数字(其中useInterval的代码可参考这篇文章定时器在hooks的使用和分装)。 上述代码存在一个问题,当我们从9到0的时候,容器偏移从-90%直接到了0%。 但是由于设定了固定的过度动画时间,就可以看到下面这种情况: 解决这个问题,可以参考无缝滚动的思路,在9后面复制一份0,当容器滚动到9的时候,继续滚动到复制的0,这个时候直接把容器的偏移位置设置为0%,并且控制容器的过度动画transition-time为0。 具体代码如下:

{ Array.from({length: 10}).map((_, index) => ( {index} )) } 0 export function useInterval(callback, delay) { const savedCallback = useRef(() => {}); useEffect(() => { savedCallback.current = callback; }); useEffect(() => { if (delay !== null) { const interval = setInterval(() => savedCallback.current(), delay || 0); return () => clearInterval(interval); } return undefined; }, [delay]); } const [percent, setPercent] = useState(0); const [playing, setPlaying] = useState(true); useInterval(() => { let num = (percent + 1) % 11; let status = true; setPercent(num); setPlaying(status) }, 1000) const endPlay = () => { if (percent+1 === 11) { setPercent(0); setPlaying(false); } };

上述代码中,复制了一份0到9的后面,此外过度动画时间从js来控制,而不是使用写固定的css。

声明变量playing来控制是否有过渡动画 监听容器的transitionEnd事件 判断当前是否滚动到9后面的0,如果是,则调用endPlay方法 endPlay主要作用用于把偏移位置重置到0,并且设置为playing为false 以上面这种方式,对于用户来说,就没有先前的跳变的过程,滚动效果非常平滑。 利用两个元素实现

事实上我们并不需要这么多子节点,仔细看动图的效果。 事实上在在视口只有两个元素,一个值为当前的值,另外一个元素的值为(current + 1) % 11的值。 下面是调整后的DOM结构:

{[prev, cur].map((item, index) => ( {item} ))}

prev表示之前的值,cur表示当前的值。下面将其封装成一个组件

const { value } = props; const [prev, setPrev] = useState(''); const [cur, setCur] = useState(''); const [playing, setPlaying] = useState(false); const play = (prev, current) => { setPrev(prev); setCur(current); setPlaying(false); setTimeout(() => { setPlaying(true); }, 16); }; useEffect(() => { if (isEffective(value)) { play(cur, value); } else { setPrev(value); setCur(value); } }, [value]);

监听useEffect监听value值的变化,只有当传入值有效的时候才会播放动画,下面是具体的css代码:

.slider { display: flex; flex-direction: column; overflow: hidden; height: 36px; } .slider-text { font-size: 26px; line-height: 36px; height: 100%; transform: translateY(0%); } .slider-ani { transform: translateY(-100%); transition: transform 500ms ease; }

描述一下这种方案的思路:

声明两个变量,存放当前的值,prev: 之前的值;cur: 表示变化后的值 监听传入值的变化 首次传值:设置prev和cur为当前传入的值 第二次更改值:调用play方法 把prev的值设置为没有变化前的cur值,cur值更改为传入的值 设置playing为false,然后16ms后设置为true 这里有个问题就是为什么需要在16ms后设置playing为true,拆解一下这个过程你就明白了 上次移动后,playing为true,此时容器的偏移位置为translateY(-100%) 当新值传入时,我们需要更改元素的值,并且把容器位置重新置为translateY(0),需要注意的是设置这个过程的时候是不能有动画效果的 16ms,这个表示屏幕的刷新每一帧画面需要的时间

如果要实现文章开头的效果,只需要多个组件挨着就可以实现了。

上面就是所有关于滚动效果的内容,欢迎关注我的公众号: 前端好好学



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3