前端实现动画

7 篇文章 0 订阅

JS setInterval + left/right 或 setInterval + transform

其主要思想是通过setInterval或setTimeout方法的回调函数来持续调用改变某个元素的CSS样式以达到元素样式变化的效果。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <style type="text/css">
        #rect {
            width: 200px;
            height: 200px;
            background: #ccc;
        }
    </style>
</head>
<body>
    <div id="rect"></div>
    <script>
        let elem = document.getElementById('rect');
        let left = 0;
        let timer = setInterval(function(){
            if(left<window.innerWidth-200){
                elem.style.marginLeft = left+'px';
                left ++;
            }else {
                clearInterval(timer);
            }
        },16);
    </script>
</body>
</html>

javascript 实现动画通常会导致页面频繁性重排重绘消耗性能,一般应该在桌面端浏览器。在移动端上使用会有明显的卡顿。

上面例子中,我们设置的setInterval时间间隔是16ms。一般认为人眼能辨识的流畅动画为每秒60帧,这里16ms比(1000ms/60=16.666667)帧略小一些,但是一般可仍为该动画是流畅的。
在很多移动端动画性能优化时,一般使用16ms来进行节流处理连续触发的浏览器事件。例如对touchmove、scroll事件进行节流等。通过这种方式减少持续事件的触发频率,可以大大提升动画的流畅性。

  • setTimeout 的执行时间并不是确定的。在 Javascript 中, setTimeout 任务被放进了异步队列中,只有当主线程上的任务执行完以后,才会去检查该队列里的任务是否需要开始执行,因此 setTimeout 的实际执行时间一般要比其设定的时间晚一些
  • 刷新频率受屏幕分辨率和屏幕尺寸的影响,因此不同设备的屏幕刷新频率可能会不同,而 setTimeout 只能设置一个固定的时间间隔,这个时间不一定和屏幕的刷新时间相同。

以上两种情况都会导致 setTimeout 的执行步调和屏幕的刷新步调不一致,从而引起丢帧现象。

JS requestAnimationFrame

requestAnimationFrame是另一种Web API,原理与setTimeout和setInterval类似,都是通过JavaScript持续循环的方法调用来触发动画动作。

requestAnimationFrame 与 setTimeout/setInterval 最大的区别是由系统自己的刷新机制来决定什么时候调用动画函数,开发者只需要定义好动画函数,这个函数会在浏览器重绘之前调用。

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style type="text/css">
        * {
            margin:0;
            padding:0;
        }
        div {
            width: 200px;
            height: 200px;
            background-color: #ccc;
        }
    </style>
</head>
<body>
    <div id="rect"></div>
    <script type="text/javascript">
    window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
    window.msRequestAnimationFrame;

    let elem = document.getElementById("rect");
    let left = 0;
    // 第一帧渲染
    requestAnimationFrame(step);
    // 回调函数
    function step() {
        if(left<window.innerWidth-200){
            left+=1;
            elem.style.marginLeft = left+"px";
            // 在动画没有结束前,递归渲染
            requestAnimationFrame(step);
        }
    }
    </script>
</body>
</html>

requestAnimationFrame只是将回调的方法传入到自身的参数中执行,而不是通过setInterval调用。

CSS3 transition(transform+transition)

transition是过度动画。但是transition并不能实现独立的动画,只能在某个标签元素样式或状态改变时进行平滑的动画效果过渡,而不是马上改变。
此种方式比较小众,不易控制

CSS3 animation(animation属性 + @keyframes)

通过对关键帧和循环次数的控制,页面标签元素会根据设定好的样式改变进行平滑过渡。而且关键帧状态的控制是通过百分比来控制的。
CSS3最大的优势是摆脱了js的控制,并且能利用硬件加速以及实现复杂动画效果。

<html>
	<head>
	<meta charset="utf-8"> 
	<style> 
		div
		{
			width:100px;
			height:100px;
			background:red;
			animation:myfirst 5s;
		}
		
		@keyframes myfirst
		{
			0%   {background:red;}
			25%  {background:yellow;}
			50%  {background:blue;}
			100% {background:green;}
		}		
	</style>
	</head>
	<body>
		<div></div>
	</body>
</html>

在动画中使用 transform 比 left/top 性能更好,能减少浏览器 repaint。

HTML5 Canvas动画(setInterval+canvas)

借助Web API来实现动画的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
    *{
        margin:0;
        padding:0;
        
    }
    </style>
</head>
<body>
    <canvas id="canvas" width="700" height="550"></canvas>
    <script type="text/javascript">
        let canvas = document.getElementById("canvas");
        let ctx = canvas.getContext("2d");
        let left = 0;
        let timer = setInterval(function(){
            ctx.clearRect(0,0,700,550);	 // 清除图形,700, 550表示清除整个canvas中的图形
            ctx.beginPath();			 // 开始一条路径
            ctx.fillStyle = "#ccc";		 // 设置图形颜色
            ctx.fillRect(left,0,100,100);	// 绘制图形
            ctx.stroke();					// 绘制已定义的路径
            if(left>700){
                clearInterval(timer);
            }
            left += 1;
        },16);
    </script>
</body>
</html>

通过getContext()获取元素的绘制对象,通过clearRect不断清空画布并在新的位置上使用fillStyle绘制新矩形内容实现页面动画效果。

Canvas主要优势是可以应对页面中多个动画元素渲染较慢的情况,完全通过javascript来渲染控制动画的执行。可用于实现较复杂动画

SVG(svg标签+animate标签)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
    *{
        margin:0;
        padding:0;
    }
    </style>
</head>
<body>
    <svg id="box" width="800" height="400" xmlns="http://www.w3.org/2000/svg" version="1.1">
        <rect x="" y="" width="100" height="100" fill="rgb(255,0,0);" stroke="" stroke-width="">
            <set attributeName="x" attributeType="XML" to="100" begin="4s"/>
            <animate attributeName="x" attributeType="XML" begin="0s" dur="4s" from="0" to="300"/>
            <animate attributeName="y" attributeType="XML" begin="0s" dur="4s" from="0" to="0"/>
            <animateTransform attributeName="transform" begin="0s" dur="4s" type="scale" from="1" to="2" repeatCount="1" />
            <animateMotion path="M10,80 q100,120 120,20 q140,-50 160,0" begin="0s" dur="4s" repeatCount="1" />

        </rect>     
    </svg>  

</body>
</html>

SVG的一大优势是含有较为丰富的动画功能,原生绘制各种图形、滤镜和动画,并且能被js调用。html是对dom的渲染,那么svg就是对图形的渲染。
但是,另一方面元素较多且复杂的动画使用svg渲染会比较慢,而且SVG格式的动画绘制方式必须让内容嵌入到HTML中使用。CSS3的出现让svg的应用变得相对少了。

总结

复杂的动画是通过一个个简单的动画组合实现的。基于兼容性问题,通常在项目中,一般在
桌面端浏览器推荐使用javascript直接实现动画或SVG方式
移动端可以考虑使用CSS3 transition、CSS3
animation
CanvasrequestAnimationFrame方式。

参考

前端实现动画的6种方式详解
005-【前端动画】实现动画的6种方式
CSS3动画那么强,requestAnimationFrame还有毛线用?

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值