js实现⼀个逐步递增的数字动画
⽬录
背景
实现类似滚轮的效果,容器固定,数字向上滚动
利⽤两个元素实现滚动
利⽤H5的requestAnimationFrame()API实现数字逐步递增的动画效果
计时器对⽐
requestAnimationFrame实现滚动动画思路
成果展⽰
背景
可视化⼤屏项⽬使⽤最多的组件就是数字组件,展⽰数据的⼀个变化,为了提⾼视觉效果,需要给数字增加⼀个滚动效果,实现⼀个数字到另⼀个数字逐步递增的滚动动画。
先上⼀个思维导图:
实现类似滚轮的效果,容器固定,数字向上滚动
先列举所有的可能的值形成⼀个纵向的列表,然后固定⼀个容器,匀速更改数字的偏移值。
下⾯来介绍⼀下这种⽅案的实现,元素值从0到9⼀共⼗个值,每个数字占纵向列表的10%,所以纵向偏移值依次为为0% —> -90%
实现:
<ul>
<li>
<span>0123456789</span>
</li>
</ul>
ul{
margin-top: 200px;
}
ul li{
margin:0 auto;
width: 20px;
height: 30px;
text-align: center;
border:2px solid rgba(221,221,221,1);
border-radius:4px;
}
ul li span{
position: absolute;
color: #fff;
top: 30%;
left: 50%;
transform: translate(-50%,0);
transition: transform 500ms ease-in-out;
writing-mode: vertical-rl;
text-orientation: upright;
letter-spacing: 17px;
}
let spanDom = document.querySelector('span')
let start = 0
setInterval(() =>{
start++
if(start>9){
start = 0
}
ansform = `translate(-50%,-${start*10}%)`
}, 1000)
上述代码存在⼀个问题,当我们从9到0的时候,容器偏移从-90%直接到了0%。但是由于设定了固定的过渡动画时间,就会出现⼀个向反⽅向滚动的情况,为了解决这个问题,可以参考⽆缝滚动的思路
在9后⾯复制⼀份0,
当纵向列表滚动到9的时候,继续滚动到复制的0
滚动到复制的0的时候,把列表的偏移位置改为0,并且控制动画时间为0
<ul>
<li>
<span>01234567890</span>
</li>
</ul>
let spanDom = document.querySelector('span')
let start = 0
var timer = setInterval(fn, 1000);
function fn() {
start++
clearInterval(timer)
timer = setInterval(fn,start >10 ? 0 : 1000);
if(start>10){
ansition = `none`
start = 0
}else{
ansition = `transform 500ms ease-in-out`
}
ansform = `translate(-50%,-${start/11*100}%)`
}
利⽤两个元素实现滚动
仔细看动图的效果,事实上在在视⼝只有两个元素,⼀个值之前的值,⼀个为当前的值,滚动偏移值只需设置translateY(-100%)
具体思路:
声明两个变量,分别存放之前的值prev,以及变化后的值cur;声明⼀个变量play作为这两个值的滚动动画的开关
使⽤useEffect监听监听传⼊的值:如果是有效的数字,那么把没有变化前的值赋值给prev,把当前传⼊的值赋值给cur,并且设置paly为true开启滚动动画
下⾯是调整后的代码结构:
<div className={styles.slider}>
{[prev, cur].map((item, index) => (
<span key={index} className={`${styles['slider-text']} ${playing && styles['slider-ani']} ${(prev === 0 && cur === 0 && index ===0) && styles['slider-hide']}`}> {item}
</span>
))}
</div>
const { value} = props
const [prev, setPrev] = useState(0)
const [cur, setCur] = useState(0)
const [playing, setPlaying] = useState(false)
const play = (pre, current) => {
setPrev(pre)
setCur(current)
setPlaying(false)
setTimeout(() => {
setPlaying(true)
}, 20)
}
useEffect(() => {
if (!Number.isNaN(value)) {
play(cur, value)
} else {
setPrev(value)
setCur(value)
}
}, [value])
.
slider {
display: flex;
flex-direction: column;
height: 36px;
margin-top: 24%;
overflow: hidden;
text-align: left;代码运行js特效
}
.slider-text {
display: block;
height: 100%;
transform: translateY(0%);
}
.slider-ani {
transform: translateY(-100%);
transition: transform 1s ease;
}
.slider-hide {
opacity: 0;
}
实现多个滚轮的向上滚动的数字组件
利⽤H5的requestAnimationFrame()API实现数字逐步递增的动画效果
实现⼀个数字的逐渐递增的滚动动画,并且要在指定时间内完成。要看到流畅的动画效果,就需要在更新元素状态时以⼀定的频率进⾏,JS动画都是通过在很短的时间内不停的渲染/绘制元素做到的,所以计时器⼀直都是Javascript动画的核⼼技术,关键就是刷新的间隔时间,刷新时间需要尽量短,这样动画效果才能显得更加流畅,不卡顿;同时刷新间隔⼜不能太短,需要确保浏览器有能⼒渲染动画。
⼤多数电脑显⽰器的刷新频率是 60Hz,即每秒重绘 60次。因此平滑动画的最佳循环间隔是通常是 1000ms/60,约等于16.6ms
计时器对⽐
与 setTimeout 和 setInterval 不同,requestAnimationFrame 不需要程序员⾃⼰设置时间间隔。setTimeout 和 setInterval 的问题是精确度低。它们的内在运⾏机制决定了时间间隔参数实际上只是指定了把动画代码添加到浏览器 UI 线程队列中以等待执⾏的时间。如果队列前⾯已经加⼊了其他任务,那动画代码就要等前⾯的任务完成后再执⾏。
requestAnimationFrame 采⽤系统时间间隔,它会要求浏览器根据⾃⼰的频率进⾏⼀次重绘,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使⽤动画卡顿不流畅,让各种⽹页动画效果能够有⼀个统⼀的刷新机制,从⽽节省系统资源,提⾼系统性能,改善视觉效果。
requestAnimationFrame 会把每⼀帧中的所有 DOM 操作集中起来,在⼀次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率。
requestAnimationFrame 对于隐藏或不可见元素,将不会进⾏重绘或回流,就意味着使⽤更少的 CPU、GPU 和内存使⽤量。
requestAnimationFrame 是由浏览器专门为动画提供的API,在运⾏时浏览器会⾃动优化⽅法的调⽤,并且如果页⾯不是激活状态下的话,动画会⾃动暂停,有效节省了CPU开销。
requestAnimationFrame实现滚动动画思路
动画开始,记录开始动画的时间 startTimeRef.current
const startTimeRef = w());
const [t, setT] = w());
之后每⼀帧动画,记录从开始动画经过了多长时间,计算出当前帧的所到达的数字应该是多少,即currentValue
useEffect(() => {
const rafFunc = () => {
const now = w();
const t = now - startTimeRef.current;
if (t >= period) {
setT(period);
} else {
setT(t);
requestAnimationFrame(rafFunc);
}
};
let raf;
if (autoScroll) {
raf = requestAnimationFrame(rafFunc);
startTimeRef.current = w();
} else {
raf && cancelAnimationFrame(raf);
}
return () => raf && cancelAnimationFrame(raf);
}, [period, autoScroll]);
const currentValue = useMemo(() => ((to - from) / period) * t + from, [t, period, from, to]);
针对当前每个数字位上的数字进⾏⽐较,如果有变化,进⾏偏移量的变化,偏移量体现在当前数字位上的数字与下⼀位数字之间的
差值,这个变化每⼀帧都串起来形成了滚动动画
成果展⽰
到此这篇关于js实现⼀个逐步递增的数字动画的⽂章就介绍到这了,更多相关js 逐步递增数字动画内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论