天天看點

前端實作動畫

通常在前端中,實作動畫的方案主要有6種:

  • CSS3 transition;
  • CSS3 animation;
  • javascript直接實作;
  • .jQuery的animate()API;
  • requestAnimationFrame;
  • SVG(可伸縮矢量圖形);
  • Canvas動畫;

首先,我們來搭一個基本結構架構:

<style>
  div {
    position: relative;
    background: #999;
    width: 50px;
    height: 50px;
  }
 
    .animat{
 
    }
 
</style>
 
<body>
  <div class="animat"></div>
</body>      

CSS3 transition

transition是過度動畫。但是transition隻能在某個标簽元素樣式或狀态改變時進行平滑的動畫效果過渡,而不是馬上改變。

 transition是漸變的意思,就是某個屬性 從一個值逐漸變成另一個值,比如width:從50px,到200px

 基本表達式 transition: transition-property  transition-duration transition-timing-function transition-delay

  • transition-property :需要做緩動的屬性,預設值為all,就表示所有可以緩動的屬性都做緩動動畫
  • transition-duration : 整個緩動動畫的持續時間,比如1s 就是1秒
  • transition-timing-function : 緩動動畫的呈現速度方式,預設值為ease,即 先慢再快再慢,還有linear(勻速)等其他方式
  • transition-delay : 延遲執行動畫時間

示例

.animat{
           transition:width 2s;
           -moz-transition:width 2s; /* Firefox 4 */
           -webkit-transition:width 2s; /* Safari and Chrome */
           -o-transition:width 2s; /* Opera */
       }

       .animat:hover{
        width:300px;
    }      

完整代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
        div
        {
            width:100px;
            height:100px;
            background:red;
            position:absolute;
}

        }
        .animat{
           transition:width 2s;
           -moz-transition:width 2s; /* Firefox 4 */
           -webkit-transition:width 2s; /* Safari and Chrome */
           -o-transition:width 2s; /* Opera */
       }

       .animat:hover{
        width:300px;
    }
</style>
</head>
<body>
   <div class=\'animat\'></div>
</body>
</html>      

這個動畫呈現效果是:當滑鼠移動到div上的時候,執行width 改變動畫。

很多其他的一些屬性也可以,比如left,opacity 等等,這裡不做贅述。

CSS3 animation

文法:

animation: name duration timing-function delay iteration-count direction;

name:keyframe的名稱,也就是定義了關鍵幀的動畫的名稱,這個名稱用來差別不同的動畫。
duration:完成動畫所需要的時間(2s 或者 2000ms)
timing-function:完成動畫的速度曲線
delay:動畫開始之前的延遲
iteration-count:動畫播放次數
direction:是否輪流反向播放動畫(normal:正常順序播放,alternate下一次反向播放)如果把動畫設定為隻播放一次,則該屬性沒有效果。

使用animation屬性制作動畫可以更加靈活的設定動畫幀,通過不同keyframe(動畫幀)的設定,實作很多優雅的效果,keyframe中的百分數是動畫完成總時間的比例。
animation是設定總的動畫效果,而keyframe中設定上相應的動畫名字,然後在keyframe中設定具體的動畫效果。當然由于是css3的屬性,仍然需要注意它的相容性,加上必須的字首。      

keyframes

包含兩部分,第一個是使用animation屬性,第二部分是:用@keyframes定義動畫

示例

.animat{
          animation: testAni 2s infinite alternate;
      }
      /*infinite表示動畫一直循環播放*/
      /*alternate表示動畫下一次反向播放*/

      @keyframes testAni {
        0% {
            width:100px;
        }
        
        30% {
         width:200px;
     } 
     
     100% {
          width: 500px;
    }
}         

0% 表示最開始,30%,表示整個動畫時間的30%,  100% 表示結束, 

中括号裡面就是需要呈現動畫的屬性。

注:動畫優化:1)因為動畫改變的太頻繁,是以我們最好用position:absolute或fixed的方式把元素脫離文檔流,避免頻繁重繪;

                2) 如果是定位屬性:比如left,top等等,可以用transform:translate()的方式來替代,這樣性能更好.

注:transition适合于一次性的呈現動畫,animation适合多次 或者需要控制中間過程的動畫.

javascript 直接實作動畫

其主要思想是通過setInterval或setTimeout方法的回調函數來持續調用改變某個元素的CSS樣式以達到元素樣式變化的效果。

示例

<body>
    <div id="animat"></div>
    <script>
        let elem = document.getElementById(\'animat\');
        let left = 1;
        //擷取某個元素的寬度:obj.offsetWidth;
        console.log(elem.offsetWidth); 
        let timer = setInterval(function(){
            let elemWidth=elem.offsetWidth;
            if(elemWidth<500){
                 //設定某個元素的寬度:obj.style.width;
                 elem.style.width=elemWidth+left+\'px\';
                 left ++; 
             }else 
             {
                clearInterval(timer); 
            } },16); 
     </script> 
</body>      

Jquery的animate()方法就是這種方式實作的。

存在的問題

javascript 實作動畫通常會導緻頁面頻繁性重排重繪,消耗性能,一般應該在桌面端浏覽器。在移動端上使用會有明顯的卡頓。

Jquery的animate()

jQuery animate() 方法用于建立自定義動畫。

文法:

$(selector).animate({params},speed,callback);      

示例

<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>

<script> 
$(document).ready(function(){
  $("button").click(function(){
    var div=$("div");
    div.animate({height:\'300px\',opacity:\'0.4\'},"slow");
    div.animate({width:\'300px\',opacity:\'0.8\'},"slow");
    div.animate({height:\'100px\',opacity:\'0.4\'},"slow");
    div.animate({width:\'100px\',opacity:\'0.8\'},"slow");
  });
});
</script> 
</head>
 
<body>

<button>開始動畫</button>
<div style="background:#98bf21;height:100px;width:100px;position:absolute;">
</div>

</body>
</html>      

requestAnimationFrame

requestAnimationFrame是另一種Web API,原理與setTimeout和setInterval類似,都是通過javascript持續循環的方法調用來觸發動畫動作。但是requestAnimationFrame是浏覽器針對動畫專門優化形成的APi,在性能上比另兩者要好。

通常,我們将執行動畫的每一步傳到requestAnimationFrame中,在每次執行完後進行異步回調來連續觸發動畫效果。

示例

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

    let elem = document.getElementById("animat");
    let left = 0;
    //自動執行持續性回調
    requestAnimationFrame(step);
    //持續該改變元素位置
    function step() {
         let elemWidth=elem.offsetWidth;
            if(elemWidth<500){
                 //設定某個元素的寬度:obj.style.width;
                 elem.style.width=elemWidth+left+\'px\';
                 left ++; 
                 requestAnimationFrame(step);
             }
    }
    </script>
</body>
</html>      

我們注意到,requestAnimationFrame隻是将回調的方法傳入到自身的參數中執行,而不是通過setInterval調用。

什麼是SVG? 

SVG 指可伸縮矢量圖形 (Scalable Vector Graphics)

SVG 用來定義用于網絡的基于矢量的圖形

SVG 使用 XML 格式定義圖形

SVG 圖像在放大或改變尺寸的情況下其圖形品質不會有所損失

SVG 是網際網路聯盟的标準

SVG 與諸如 DOM 和 XSL 之類的 W3C 标準是一個整體

(SVG是HTML下的一個分支)

Canvas動畫

canvas作為H5新增元素,是借助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");
        //getContext()擷取元素的繪制對象
        let ctx = canvas.getContext("2d");
        let width = 100;
        let timer = setInterval(function(){
            //clearRect不斷清空畫布并在新的位置上使用fillStyle繪制新矩形内容實作頁面動畫效果。
            ctx.clearRect(0,0,700,550);
            ctx.beginPath();
            ctx.fillStyle = red;
            ctx.fillRect(0,0,width,200);
            ctx.stroke();
            if(width>700){
                clearInterval(timer);
            }
            width += 5;
        },16);
    </script>
</body>
</html>      

總結

複雜的動畫是通過一個個簡單的動畫組合實作的。基于相容性問題,通常在項目中,一般在

      • 桌面端浏覽器推薦使用javascript直接實作動畫或SVG方式;
      • 移動端可以考慮使用CSS3 transition、CSS3 

        animation、Canvas或requestAnimationFrame方式**。