天天看點

CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片

1.目标及知識點:

  1. css3 transition 使用
  2. css3 animation 使用
  3. css3 transform 使用
- 利用CSS3 transition 實作動畫 
  - transition 文法詳解
  - transition-delay
  - transition-duration
  - transition-property
  - transition-timing-function
    - 貝塞爾曲線運動 https://cubic-bezier.com/
  - transition 針對為渲染元素的問題 
  - transitionend 事件
- 利用CSS3 animation 動畫
  - keyframes
  - animation-name
  - animation-duration
  - animation-timing-function,
  - animation-delay
  - animation-iteration-count
  - animation-direction 
  - animation-fill-mode
  - animation 相關事件
    - animationstart
    - animationiteration 
    - animationend 
- CSS3 transform 詳解
  - transform 2D
    - 旋轉: rotate()
    - 縮放: scale()、scaleX()、scaleY()
    - 傾斜: skew()、skewX()、skewY()
    - 平移:translate()、translateX()、translateY()
    - transform 多函數書寫時的執行順序
    - transform-origin 源點設定
    - translate 和 源點關系
  - transform 3D 
    - 3D旋轉: rotateX()、rotateY()、rotateZ()
    - 3D位移:translateZ()
    - transform-style
    - perspective
    - perspective-origin
    - 搭建立方體
           
- CSS3 transform 詳解
  - transform 2D
    - 旋轉: rotate()
    - 縮放: scale()、scaleX()、scaleY()
    - 傾斜: skew()、skewX()、skewY()
    - 位移:translate()、translateX()、translateY()
    - transform 多函數書寫時的執行順序
    - transform-origin 源點設定
    - translate 和 源點關系
    - 執行個體:無縫滾動
    - 執行個體:水滴按鈕
    - 執行個體:時鐘實作
    - 擴充:JS 擷取 transform 的問題
      - matrix(a,b,c,d,e,f) 矩陣函數
	    - matrix(1,0,0,1,0,0);
      - 通過矩陣實作縮放
        - x軸縮放 a=x*a    c=x*c     e=x*e;
        - y軸縮放 b=y*b   d=y*d     f=y*f;
      - 通過矩陣實作位移
        - x軸位移: e=e+x
        - y軸位移: f=f+y
      - 通過矩陣實作傾斜
        - x軸傾斜: c=Math.tan(xDeg/180*Math.PI)
        - y軸傾斜: b=Math.tan(yDeg/180*Math.PI)
      - 通過矩陣實作旋轉
        - a=Math.cos(deg/180*Math.PI); 
        - b=Math.sin(deg/180*Math.PI);
        - c=-Math.sin(deg/180*Math.PI);
		    - d=Math.cos(deg/180*Math.PI);
  - transform 3D 
    - 3D旋轉: rotateX()、rotateY()、rotateZ()
    - 3D位移:translateZ()
    - transform-style
    - perspective
    - perspective-origin
    - 搭建立方體
           

2.transition

2.1 transition作用及樣式:

transition作用:

transition 在元素的樣式發生改變時,給元素添加一個過渡動畫。不是所有樣式都有效果,必須是寬高,背景色,距離,位置等數值類樣式才有效果。通過css和JS改變都會有動畫效果。

transition樣式:

  1. transition-delay:延遲時間,動畫延遲多長時間執行(s|ms),預設為0。可選
  2. transition-duration:動畫時長,動畫用多長時間完成(s|ms),預設為0,必填
  3. transition-property:要動畫的樣式。預設all。隻給某些加樣式如,transition:1s width;隻給寬加過渡動畫
  4. transition-timing-function:動畫形式

transition-timing-function動畫形式:

  • linear 勻速
  • ease 緩沖(預設值)
  • ease-in 加速
  • ease-out 減速
  • ease-in-out 先加速再減速
  • cubic-bezier()貝塞爾曲線

各個樣式之間不加逗号。除非給寬高分别加樣式:如,transition:1s width,.5s height;

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        div {
            width: 100px;
            height: 100px;
            background: red;
        }
        .hover {
            width: 400px;
            height: 200px;
            background: blue;
            /* transition: .5s;transition-delay動畫延遲多長時間執行 */
            /* transition: .5s 1s; transition-duration動畫用多長時間完成 */
            /* transition: .5s 1s width; transition-property:要動畫的樣式,預設all是給所有樣式加過渡效果*/
            /* transition: 1s .5s width ease-in-out;  */
            /*
            transition-timing-function:動畫形式:
                linear 勻速
                ease 緩沖(預設值)
                ease-in 加速
                ease-out 減速
                ease-in-out 先加速再減速
                cubic-bezier()貝塞爾曲線 https://cubic-bezier.com/
            */
            transition: 1s .5s width cubic-bezier(0,1.42,.83,.67);
        }
    </style>
</head>
<body>
    <div></div>
    <script>
        //設定滑鼠移入移出事件,然後加上transition效果
        var div = document.querySelector("div");
        div.onmouseover = function(){
            this.classList.add("hover");
        };
        div.onmouseout = function(){
            this.classList.remove("hover");
        };
    </script>
</body>
</html>
           

2.2 transition使用時注意點:

預設隐藏的元素,設定點選後再顯示時,過渡動畫會失效。

解決:定時器延時過渡動畫執行

需求:預設div隐藏,點選按鈕後再顯示并設定過渡後效果

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #box {
            width: 100px;
            height: 100px;
            background: red;
            display: none;
            transition: .5s;
        }
    </style>
</head>
<body>
    <div id="box"></div>
    <button>顯示</button>
    <script>
        //元素本身是隐藏的,點選時設定block,并改變其寬度,設定動畫過渡效果
        //延時最好不低于20:因為螢幕有渲染幀頻問題,1s渲染60次,16.7ms渲染一次。如果寫0可能卡在上一屏,動畫過渡效果就可能出不來
        var box = document.querySelector("#box");
        var btn = document.querySelector("button");
        btn.onclick = function(){
            box.style["display"] = "block";
            box.style["width"] = "400px";
            box.style["background"] = "blue";
            // setTimeout(function(){
            //     box.style["width"] = "400px";
            //     box.style["background"] = "blue";
            // },20);
        };
    </script>
</body>
</html>
           

問題:發現此時并沒有動畫過渡效果。

原因:元素本身設定display為none是不會渲染這個元素的,當display設定為block時,才開始渲染這個元素。而元素在頁面渲染完(display設定為block)之前,transition是不起效果的。即螢幕繪制(display設定為block)需要時間,當display設定為block時,這個元素渲染需要時間,而代碼之間執行的速度很快,是以會直接執行下面設定的寬高等樣式,而不會通過transition動畫去執行,是以,動畫效果沒有執行,螢幕已經渲染完了。

解決:需要在事件裡,給元素的改變加上定時器延時。時間至少20ms

setTimeout(function(){
                box.style["width"] = "400px";
                box.style["background"] = "blue";
            },20);
           

2.3 監聽transition執行結束的事件:

  • transitionend事件:監聽元素的transition動畫是否執行完畢
  • WebKitTransitionEnd:低版本WebKit核心需要寫成WebKitTransitionEnd

直接使用監聽事件ontransitionend會監聽不到transition執行結束:

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #box {
            width: 100px;
            height: 100px;
            background: red;
            display: none;
            
            transition: .5s;
        }
    </style>
</head>
<body>
    <div id="box"></div>
    <button>顯示</button>
    <script>
        var box = document.querySelector("#box");
        var btn = document.querySelector("button");

        //如果元素事先隐藏,會監聽到兩次
         btn.onclick = function(){
            box.style["display"] = "block";
            setTimeout(function(){
                box.style["width"] = "400px";
                box.style["background"] = "blue";
            },20);
        };
        //監聽事件ontransitionend方法沒有效果
        btn.ontransitionend = function(){
            console.log("ontransitionend執行完成");//不會進行列印(沒有監聽到)
        };
        //監聽transition執行結束事件transitionend
        box.addEventListener('transitionend',function(){
            console.log("addEventListener transitionend執行完成");
        });
    </script>
</body>
</html>
           

結果:ontransitionend沒有監聽并列印結果,通過事件監聽正确監聽到結果

CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片

注意:每個樣式都是獨立的過渡效果,而不是整體進行一次性進行過渡,是以設定了多個過渡效果,事件監聽也就會監聽到多少次,是以這裡列印了兩次。

CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片
CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片

2.4 取消監聽事件:

注意:

  • 如果要取消監聽事件,則添加監聽事件時不能使用匿名函數,而需要寫成有名函數
  • 取消監聽事件必須寫在有名函數函數體内
<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #box {
            width: 100px;
            height: 100px;
            background: red;
            
            transition: .5s;
        }
    </style>
</head>
<body>
    <div id="box"></div>
    <script>
        var box = document.querySelector("#box");
        //給box添加click監聽事件,并給box width+200,然後監聽結束後,取消監聽
        box.addEventListener('click',fn);
        boxWidth = parseInt(getComputedStyle(box)["width"]);
        
        function fn(){
            boxWidth += boxWidth;
            box.style["width"] = boxWidth + 'px';
            //監聽事件結束後,取消監聽事件(注意必須寫在監聽的函數中)
            box.removeEventListener('click',fn);
        }
    </script>
</body>
</html>
           

2.4 使用監聽事件好處

通過onXXX寫事件時,多個onXXX事件前一個事件處理會被覆寫。但是通過添加事件監聽方式,可以添加多個事件處理。

var box = document.querySelector("#box");
        //給box添加click監聽事件,并給box width+200,然後監聽結束後,取消監聽
        box.addEventListener('click',fn);
        box.addEventListener('click',function(){
            console.log("click事件2");
            
        });
        boxWidth = parseInt(getComputedStyle(box)["width"]);
        
        function fn(){
            boxWidth += boxWidth;
            box.style["width"] = boxWidth + 'px';
            //監聽事件結束後,取消監聽事件(注意必須寫在監聽的函數中)
            box.removeEventListener('click',fn);
        }
           
CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片

2.animation

2.1 transition作用及樣式

transition作用及樣式:

 transition隻能做一些簡單的動畫,如果要做一些複雜的動畫就得使用animation。而且如果希望元素一開始就有動畫,就要使用animation。animation使用時必須聲明關鍵幀@keyframes 名字

  • animation-name:動畫幀名稱 使用@keyframes 名字  進行定義 必選
  • animation-duration :動畫持續時間 必選
  • animation-timing-function : 動畫形式(參考transition)
  • animation-delay : 動畫開始前的延遲時間
  • animation-iteration-count 動畫執行次數 number | infinite(無限次)
  • animation-direction : 偶數次動畫執行過程 alternate(倒序執行) | normal (順序執行)
  • animation-fill-mode : backwards動畫開始前元素的樣式(保留在動畫幀0%);forwards動畫結束後,元素樣式保留在動畫幀0的100%的位置;both 動畫開始前和結束後樣式保留在動畫幀0%和100%的位置,即backwards+forwards
  • animation-play-state : 滑鼠移入後hover,動畫暫停(paused)| 繼續播放(running)

    #box:hover {

    animation-play-state:paused;

    }

animation使用注意點:

  • animation是基于關鍵幀@keyframes 名字實作;
  • 如果0%不寫就預設使用計算後樣式,可以對其進行重新定義;
  • 如果中間xx%不寫就沒有對應的過渡效果;
  • 如果100%不寫就預設使用計算後樣式,可以對其進行重新定義;
  • 動畫執行完後,又會回到計算後樣式;
  • 加animation-fill-mode就能改變動畫執行完前/後保留的樣式。而不是預設0%/100%
  • 如果使用from{} to{} to{}會自動計算百分比進行渲染;
  • 關鍵幀聲明好後,需要進行調用animation: move 1s;
  • 相容老版本Chrome,必須加字首-webkit-animation
  • animation-play-state必須用在滑鼠移入事件中,否則會導緻整個動畫暫停

簡單示例:

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        /* animation是基于動畫幀實作 */
        @keyframes move{
            /* 如果0%不寫就預設使用計算後樣式,可以對其進行重新定義 */
            0%{
                width: 0;
                height: 0;
            }
            25%{
                width: 100px;
                height: 150px;
            }
            50%{
                width: 150px;
                height: 300px;
            }
            75%{
                width: 300px;
                height: 100px;
            }
             /* 如果100%不寫就預設使用計算後樣式,可以對其進行重新定義,但是動畫執行完後,又會回到計算後樣式 */
            100%{
                width: 0;
                height: 0;
            }
            /* 如果使用from{}  to{} to{}會自動計算百分比進行渲染 */
        }

        #box {
            width: 100px;
            height: 100px;
            background: red;
            /* 動畫幀的調用 */
            /* animation: move 1s infinite; 執行無限次*/
            /* animation: move 1s 4; 執行指定次數 */
            /* animation: move 1s infinite alternate; 倒序執行(必須多次執行才有效) */
            /* animation: move 1s infinite normal; 順序執行 */
            animation: move 1s linear; 
            animation-fill-mode: both;/* 動畫開始和結束後,元素樣式保留在動畫幀的0%和100% */
        }
        #box:hover {
            animation-play-state:paused;
        }
    </style>
</head>
<body>
    <div id="box"></div>
</body>
</html>
           

from{} to{} to{} 實作動畫效果:

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        @keyframes move{
            from {
                width: 100px;
                height: 100px;
            }
            to {
                width: 100px;
                height: 100px;
            }
            to {
                width: 200px;
                height: 100px;
            }
            to {
                width: 300px;
                height: 100px;
            }
            to {
                width: 400px;
                height: 100px;
            }
        }

        #box {
            width: 100px;
            height: 100px;
            background: red;
            animation: move 2s 4;
            animation-fill-mode: both; 
        }
        #box:hover {
            animation-play-state:paused;
        }
    </style>
</head>
<body>
    <div id="box"></div>
</body>
</html>
           

2.2 animation三個事件監聽:

  • animationstart(動畫開始:第一次執行時監聽到)
  • animationend(動畫結束)
  • animationiteration(動畫多次執行時使用,監聽動畫再次執行)

必須使用事件監聽加這三個事件,而不能直接使用onXXX;

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        /* animation是基于動畫幀實作 */
        @keyframes move{
            0%{
                width: 0;
                height: 0;
            }
            25%{
                width: 150px;
                height: 100px;
            }
            50%{
                width: 300px;
                height: 100px;
            }
            75%{
                width: 150px;
                height: 100px;
            }
            100%{
                width: 0;
                height: 0;
            }
        }

        #box {
            width: 100px;
            height: 100px;
            background: red;
            animation: move 2s linear 6; 
            animation-fill-mode: both;
        }
        #box:hover {
            animation-play-state:paused;
        }
    </style>
</head>
<body>
    <div id="box"></div>
    <script>
        var box = document.querySelector("#box");
        box.addEventListener("animationstart",function(){
            console.log("動畫開始了");
        });
        box.addEventListener("animationend",function(){
            console.log("動畫結束了");
        });
        box.addEventListener("animationstart",function(){
            console.log("動畫又開始了");
        });
    </script>
</body>
</html>
           

結果:

CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片

 3.transform 2D

transform需要和transition或者animation一起使用才有過渡效果。

transform本身不脫離文檔流,進行任何改變對其他元素都沒有任何影響。

transform變換:

  1. 旋轉:rotate()  機關:deg(角度,可為正負)。也有弧度,旋轉幾圈等機關,但用得比較少。
  2. 斜切:三個方法skew(x,y) skewX() skewY()  機關:deg(角度)
  3. 縮放:三個方法scale(x,y) scaleX() scaleY()  本身沒有機關,隻有倍數
  4. 位移:三個方法translate(x,y) translateX() translateY(),機關像素或其他

transform為了友善我們使用,将其所有的功能已經封裝成對應的方法。

3.1 transform旋轉rotate(deg):

transition實作transform的旋轉:

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #wrap {
            width: 600px;
            height: 600px;
            border: 1px solid black;
            margin: 0 auto;
        }
        #box {
            width: 200px;
            height: 200px;
            background: red;
            margin: 200px auto;
            font: 140px/200px "宋體";
            text-align: center;
            color: white;
            transition: 3s;
        }
        #wrap:hover #box{
            /* 旋轉totate */
            transform: rotate(-360deg);
        }
    </style>
</head>
<body>
    <div id="wrap">
        <div id="box">上</div>
    </div>
</body>
</html>
           

animation實作旋轉:

如果要設定一直旋轉或其他操作就使用animation。把rotate()方法寫在關鍵幀中。

animation實作旋轉需要把transform旋轉寫在關鍵幀,再在對應元素樣式中調用animation。

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        /* animation實作旋轉就不能寫在hover樣式裡,就需要把transform旋轉寫在關鍵幀,在關鍵幀中寫旋轉方法,再在對應樣式中調用animation */
        @keyframes rotate{
            from {
                transform: rotate(180deg);
            }
            to {
                transform: rotate(360deg);
            }
        }
        #wrap {
            width: 600px;
            height: 600px;
            border: 1px solid black;
            margin: 0 auto;
        }
        #box {
            width: 200px;
            height: 200px;
            background: red;
            margin: 200px auto;
            font: 140px/200px "宋體";
            text-align: center;
            color: white;
            animation: 3s rotate infinite;
        }
    </style>
</head>
<body>
    <div id="wrap">
        <div id="box">上</div>
    </div>
</body>
</html>
           
CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片

3.2 transform斜切:

transform斜切有三個方法:

  1. skew(x,y) : X軸和Y軸都進行拉伸
  2. skewX() : 沿着X軸方向拉,使其與Y軸形成對應夾角。
  3. skewY() : 沿着Y軸方向拉,使其與X軸形成對應夾角。

shewX():  角度為正數,沿着X軸方向拉兩個對角(左上角和右下角),使其與Y軸形成對應角度的夾角;如果角度為負值,拉伸對角相反,沿着X軸方向拉兩個對角(右上角和左下角),使其與Y軸形成對應角度的夾角;

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #wrap {
            width: 600px;
            height: 600px;
            border: 1px solid black;
            margin: 0 auto;
        }
        #box {
            width: 200px;
            height: 200px;
            background: red;
            margin: 200px auto;
            font: 140px/200px "宋體";
            text-align: center;
            color: white;
            transition: 3s;
        }
        #wrap:hover #box{
            /* 斜切skewX() */
            transform: skewX(30deg);
        }
    </style>
</head>
<body>
    <div id="wrap">
        <div id="box">上</div>
    </div>
</body>
</html>
           
CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片
CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片

shewY():  角度為正數,沿着Y軸方向拉兩個對角(左上角和右下角),使其與X軸形成對應角度的夾角;如果角度為負值,拉伸對角相反,沿着Y軸方向拉兩個對角(右上角和左下角),使其與X軸形成對應角度的夾角;

/* 斜切skewY() */

transform: skewY(30deg);
           
CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片
CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片

skew(x,y) :X軸和Y軸都進行拉伸

/* 斜切skew() */

transform: skew(-40deg,-30deg);
           
CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片

注意:skew(0)和skew(180)位置不一樣。 skew(0)不會變化,skew(180)斜切180度。

3.3 transform 縮放:

transform縮放三個方法:transform縮放本身沒有機關,隻有倍數

  1. scale(x,y) : X,Y 軸都縮放
  2. scaleX() :X軸縮放
  3. scaleY()  :Y軸縮放

scale(x,y) :

/* scale(x,y)縮放X 和 Y軸 */
            transform: scale(.5); 
           

 scaleX():

/* scaleX()縮放X軸 */
            transform: scaleX(.5); 
           

 scaleY():

/* scaleY()縮放Y軸 */
            transform: scaleY(.5);
           

3.4 transform 位移:

translate位移三個方法,機關像素或其他

  1. translate(x,y):沿x和y軸定位方向位移
  2. translateX() :沿X軸方向位移
  3. translateY() :沿Y軸方向位移

translate(x,y):

/* translate(x,y)向X 和 Y軸坐标方向位移 */
            transform: translate(100px,200px); 
           

translateX():

/* translateX()X軸方向位移 */
            transform: translateX(200px);
           

translateY():

/* translateY()縮放Y軸方向位移 */
            transform: translateY(200px);
           

3.4 transform多函數書寫時的執行順序問題

transform中寫多個函數(縮放,斜切,位移,旋轉同時寫)時,後寫先計算。

原因:CSS本身的解讀順序有關,CSS本身解讀順序就是從右向左進行解讀。

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #wrap {
            width: 600px;
            height: 600px;
            border: 1px solid black;
            margin: 0 auto;
        }
        #box1 {
            width: 200px;
            height: 200px;
            background: red;
            margin: 50px auto;
            font: 140px/200px "宋體";
            text-align: center;
            color: white;
            transition: 1s;
        }
        #box2 {
            width: 200px;
            height: 200px;
            background: blue;
            margin: 0 auto;
            font: 140px/200px "宋體";
            text-align: center;
            color: white;
            transition: 1s;
        }
        #wrap:hover #box1{
            transform: translateX(200px) scale(0.5);
            /* transform: translateY(200px) scale(0.5);  */
        }
        #wrap:hover #box2{
            transform: scale(0.5) translateX(200px);
            /* transform: scale(0.5) translateY(200px); */
        }
    </style>
</head>
<body>
    <div id="wrap">
        <div id="box1">上</div>
        <div id="box2">下</div>
    </div>
</body>
</html>
           

解析: 都是進行transform: scale(0.5) translateX(200px);縮放和X軸位移,但是發現box2的X軸位置和box1不一樣,因為box1會先縮放0.5倍,再位移200px,而box2會先位移200px,再縮放0.5倍,是以整體box2比box1X軸方向少100px。

CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片
CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片

3.5 transform源點(錨點)transform-origin

transform源點:預設旋轉、縮放、斜切都是圍繞着元素的中心點進行變換。這是由于transform-origin變換基點的預設值決定。

transform-origin變換基點(旋轉、縮放、斜切 圍繞的哪個點進行操作):

  1. transform-origin預設值center center,即元素的正中心;
  2. 0,0點在元素的左上角;
  3. 其他自定義設定的點,在元素的具體對應位置。如transform-origin: 400px 400px;

位移本身圍繞自己設定的軸進行位移是以沒有源點的概念。

注意transform-origin: 400px 400px;設定在需要進行對應操作的元素上。

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #wrap {
            width: 600px;
            height: 600px;
            border: 1px solid black;
            margin: 0 auto;
        }
        #box {
            width: 200px;
            height: 200px;
            background: red;
            margin: 200px auto;
            font: 140px/200px "宋體";
            text-align: center;
            color: white;
            transition: 1s;
            transform-origin: 400px 400px;
        }
        #wrap:hover #box{
            transform: scale(.5) rotate(360deg);
        }
    </style>
</head>
<body>
    <div id="wrap">
        <div id="box">上</div>
    </div>
</body>
</html>
           

3.6 transform應用一(時鐘表盤)

純CSS實作,使用圖檔,使用canvas位圖三種實作方式,canvas位圖方式相對性能最高。

思路:這裡使用css實作

  1. 通過CSS畫出表盤的刻度樣式:li的源點為表盤的中心,沒隔5個樣式不一樣li:nth-of-type(5n+1);
  2. 通過JS生成60個li;
  3. 設定時分秒指針,并進行定位,設定變換基點圍繞底部進行旋轉,設定中心點(為美觀);
  4. 擷取時分秒的時間,一秒鐘秒鐘指針走一個li(6度),一分鐘分鐘指針也走一個li(6度),一小時小時指針走5個li即30度;
  5. 通過定時器,控制各個指針走動;
  6. 需要給時針和分針擷取到小數位的小時或分鐘,否則一小時會跳一整格;
<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>時鐘表盤</title>
    <style>
        ul,ul li {
            margin: 0;
            padding: 0;
            list-style: none;
        }
        #time {
            width: 200px;
            height: 200px;
            margin: 100px auto;
            border: 4px solid rgb(196, 13, 13);
            position: relative;
            border-radius: 50%;
        }
        #time li {
            width: 4px;
            height: 10px;
            background: rgba(255, 0, 0, 0.637);
            position: absolute;
            left: 98px;
            top: 0px;
            /* 源點:是以本元素為基點進行旋轉 */
            transform-origin: 2px 100px;
        }
        /* 指定了父級元素下是 5 的倍數的第一個 li 背景色 */
        #time li:nth-of-type(5n+1){
            background: rgba(160, 20, 20, 0.863);
            height: 12px;
        }
        /* 給li設定的旋轉樣式 */
        .time_rotate {
            transform: rotate(0deg);
        }
        /* 2.設定時分秒針樣式 */
        .hour {
            width: 6px;
            height: 50px;
            background: #000000;
            position: absolute;
            top: 50px;
            left: 97px;
            /* 設定上面兩個角圓角時針 */
            border-radius:10px 10px 0 0 /50px;
            /* 設定所有角圓角 */
            /* border-radius:10/50px; 
            border-top-left-radius:10px/50px;
            border-top-right-radius:10px/50px; */
            transform-origin: 3px 50px;
        }
        .minute {
            width: 4px;
            height: 60px;
            background: #d15f2a;
            position: absolute;
            top: 40px;
            left: 98px;
            border-radius:10px 10px 0 0 /50px;
            transform-origin: 2px 60px;
        }
        .second {
            width: 2px;
            height: 70px;
            background: #e0d20c;
            position: absolute;
            top: 30px;
            left: 99px;
            border-radius:10px 10px 0 0 /50px;
            transform-origin: 1px 70px;
        }
        .circle {
            width: 10px;
            height: 10px;
            background: #000000;
            position: absolute;
            top: 95px;
            left: 95px;
            border-radius: 50%;
        }
    </style>
</head>
<body>
<div id="time">
    <ul>
        <!-- <li style="transform: rotate(0deg);"></li>
        <li style="transform: rotate(6deg);"></li>
        <li style="transform: rotate(12deg);"></li>
        <li style="transform: rotate(18deg);"></li>
        <li style="transform: rotate(24deg);"></li> -->
    </ul>
    <div class="hour"></div>    
    <div class="minute"></div>    
    <div class="second"></div> 
    <div class="circle"></div>   
</div>
<script>
//1.使用JS生成表盤刻度 總共有360度,和60和刻度,是以每個刻度代表6度
var time = document.querySelector("#time");
var ul = time.querySelector("ul");
var hour = time.querySelector(".hour");
var minute = time.querySelector(".minute");
var second = time.querySelector(".second");

var len = 360/6;
var lis = '';
var timer = null;

for (var i = 0; i < len; i++) {
    lis +='<li style="transform: rotate('+ i*6 +'deg);"></li>';
}
ul.innerHTML = lis;

//3.通過定時器,讓時分秒中動起來
setTime();
//每次開啟定時器之前先關閉
clearInterval(timer);
timer = setInterval(setTime,1000);
function setTime(){
    var date = new Date();
    var seconds = date.getSeconds();
    var minutes = date.getMinutes() + seconds/60;
    var hours = date.getHours() + minutes/60;
    //4.時針和分針不能一次跳一大格,需要有小數點
    second.style.transform = 'rotate('+ seconds*6 +'deg)';
    minute.style.transform = 'rotate('+ minutes*6 +'deg)';
    //一個小時30度
    hour.style.transform = 'rotate('+ hours*30 +'deg)';
}
</script>    
</body>
</html>
           
CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片

3.7 transform應用二(水滴按鈕)

需求:滑鼠移入時,有動畫效果。

問題:使用hover實作時,發現滑鼠離開後,動畫就會停止了。

div:hover {
            animation: .5s move linear;
        }
           

解決: 要實作複雜的動畫就需要結合JS實作,且通過animationend監聽事件結束後,清除已有樣式,才會在滑鼠再次移入時有動畫效果

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>水滴按鈕</title>
    <style>
        @keyframes move {
            0% {
                transform: scaleX(1) scaleY(.75);
            }
            10% {
                transform: scaleY(.8) scaleX(.95);
            }
            20% {
                transform: scaleX(.9) scaleY(.85);
            }
            30% {
                transform: scaleY(.9) scaleX(.85);
            }
            40% {
                transform: scaleX(.8) scaleY(.95);
            }
            50% {
                transform: scaleY(1) scaleX(.75);
            }
            60% {
                transform: scaleX(.8) scaleY(.95);
            }
            70% {
                transform: scaleY(.85) scaleX(.9);
            }
            80% {
                transform: scaleX(.85) scaleY(.9);
            }
            90% {
                transform: scaleY(.8) scaleX(.95);
            }
            100% {
                transform: scaleX(1) scaleY(.75);
            }
        }
        div {
            width: 50px;
            height: 50px;
            margin: 100px auto;
            background: rgb(138, 137, 137);
            border-radius: 50%;
            font: 18px/50px "宋體";
            font-weight: bold;
            color: #ffffff;
            text-align: center;
        }
        /* div:hover {
            animation: .5s move linear;
        } */
        .btn_hover {
            animation: .4s move linear 2; 
        }
    </style>
</head>
<body>
    <div class="btn">More</div>
<script>
var btn = document.querySelector(".btn");
var water = document.querySelector(".water");
btn.addEventListener('mouseover',function(){
    btn.classList.add("btn_hover");
});
btn.addEventListener('animationend',function(){
    btn.classList.remove("btn_hover");
});
</script>
</body>
</html>
           
CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片

3.8 JS擷取transform (matrix)

transform可供操作的隻有一個值matrix,即矩陣。transform 2D 矩陣共有9位,預設三位不能操作,可供操作的隻有6位。transform 3D 矩陣共有16位,預設四位不能操作,可供操作的隻有12位。

而transform的旋轉,斜切,位移,縮放都是CSS封裝的操作matrix的各種方法。

matrix是不可逆的,即通過matrix是不能推出元素之前做過旋轉,斜切,位移,縮放哪些操作。是以transform的操作不能擷取。

- matrix(a,b,c,d,e,f) 矩陣函數 :預設值 matrix(1,0,0,1,0,0);

- 通過矩陣實作縮放

  1. x軸縮放 a=x*a   c=x*c   e=x*e;
  2. y軸縮放 b=y*b   d=y*d   f=y*f;

- 通過矩陣實作位移

  1. x軸位移: e=e+x
  2. y軸位移: f=f+y

- 通過矩陣實作傾斜

  1. x軸傾斜: c=Math.tan(xDeg/180*Math.PI)
  2. y軸傾斜: b=Math.tan(yDeg/180*Math.PI)

- 通過矩陣實作旋轉

  1. a=Math.cos(deg/180*Math.PI);
  2. b=Math.sin(deg/180*Math.PI);
  3. c=-Math.sin(deg/180*Math.PI);
  4. d=Math.cos(deg/180*Math.PI);

弧度轉角度:deg*180/Math.PI

角度轉弧度:deg/180*Math.PI

三角函數:

  1. tan正切:直角三角形中,對邊與鄰邊的比值
  2. sin正弦:直角三角形中,對邊與斜邊的比值
  3. cos餘弦:直角三角形中,鄰邊與斜邊的比值

需求:每次點選時,讓box在現有基礎上,繼續旋轉15度。

是以一開始需要擷取到box的旋轉角度,但是transform是擷取不到的,隻能操作其上面的matrix矩陣。

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #box {
            width: 100px;
            height: 100px;
            background: red;
            margin: 100px auto;
            font: 80px/100px "宋體";
            text-align: center;
        }
    </style>
</head>
<body>
    <div id="box">上</div>
    <script>
        (function(){
            // matrix(1,0,0,1,0,0);
            var a = 1;
            var b = 0;
            var c = 0;
            var d = 1;
            var e = 0;
            var f = 0;
            //matrix(a,b,c,d,e,f)
            var box = document.querySelector("#box");
            
            // 位移 x軸位移: e=e+x
            function translateX(x){
                e += x;
                box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';//matrix(a,b,c,d,e,f)
            }

            // 位移 y軸位移: f=f+y
            function translateY(y){
                f += y;
                box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';
            }
            //縮放 x軸縮放 a=x*a    c=x*c     e=x*e;
            function scaleX(x){
                a=x*a;
                c=x*c;
                e=x*e;
                box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';
            }
            //縮放 y軸縮放 b=y*b   d=y*d     f=y*f;
            function scaleY(y){
                b=y*b;
                d=y*d;
                f=y*f;
                box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';
            }
            // 通過矩陣實作傾斜 
            // x軸傾斜 c=Math.tan(xDeg/180*Math.PI)
            function skewX(xDeg){
                c=Math.tan(xDeg/180*Math.PI);
                box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';
            }
            // y軸傾斜: b=Math.tan(yDeg/180*Math.PI)
            function skewY(yDeg){
                b=Math.tan(yDeg/180*Math.PI);
                box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';
            }
            //通過矩陣實作旋轉
            function rotate(deg){
                a=Math.cos(deg/180*Math.PI); 
                b=Math.sin(deg/180*Math.PI);
                c=Math.sin(deg/180*Math.PI);
		        d=Math.cos(deg/180*Math.PI);
                box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';
            }

            box.onclick = function(){
                //x軸位移
                // translateX(10);

                //y軸位移
                // translateY(20);

                //x軸縮放
                // scaleX(.5);

                //y軸縮放
                // scaleY(.5);

                //x軸傾斜
                // skewX(40);

                //y軸傾斜
                // skewY(60);

                rotate(60);
            };
        })();
    </script>
</body>
</html>
           

4.transform 3D

4.1 transform 3D方法

- 3D旋轉:

  1. rotateX() 圍繞X軸旋轉(上下翻轉)
  2. rotateY() 圍繞Y軸旋轉(左右翻轉)
  3. rotateZ() 圍繞Z軸旋轉

- 3D位移:

  • translateZ()  Z軸位移,近大遠小。機關像素

- transform-style :3D空間。父級進行3D變換時,是否保留子元素的3D變換。預設值flat平面不保留子級3D變換;preserve-3d保留。

- perspective :景深,在3D變換中,模拟我們的視角,去看元素在Z軸的距離。一般在父級添加。

- perspective-origin:景深基點,在3D變換中,我們的視角點。一般在父級添加。

- backface-visibility: hidden;隐藏背面:加給 3d 每一個面 。背面:和父級角度相對面

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #wrap {
            width: 600px;
            height: 600px;
            border: 1px solid black;
            margin: 0 auto;
            /* 
                景深:在3D變換中,模拟我們的視角去看元素與Z軸的距離
            
             */
            perspective: 200px;
        }
        #box {
            width: 200px;
            height: 200px;
            background: red;
            margin: 200px auto;
            font: 140px/200px "宋體";
            text-align: center;
            color: white;
            transition: 3s;
            /* 3D空間,父級元素變換時,是否保留子元素的3D變換 preserve-3d保留,flat不保留*/
            transform-style: preserve-3d;
        }
        #wrap:hover span {
            display: block;
            width: 200px;
            height: 200px;
            background: yellow;
            transform: rotateX(45deg);
        }
        #wrap:hover #box{
            /* 3D變換,圍繞X軸旋轉 */
            transform: rotateY(360deg);
            /* 3D變換,圍繞Y軸旋轉 */
            /* transform: rotateY(180deg); */
            /* 3D變換,圍繞Y軸旋轉 */
            /* transform: rotateZ(180deg); */
            /* 3D變換,Z軸位移 */
            /* transform: translateZ(60px); */

        }
    </style>
</head>
<body>
    <div id="wrap">
        <div id="box">
            <span></span>
        </div>
    </div>
</body>
</html>
           

4.2 搭建立方體

思路:先寫好立方體的6個面,在旋轉每個面。

景深大小;各個面的絕對定位;各個面的旋轉基點transform-origin

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #wrap {
                width: 600px;
                height: 600px;
                border: 1px solid black;
                margin: 0 auto;
                perspective: 1000px;
                /* 景深基點 */
                perspective-origin: center center;
        }
        #box {
            width: 200px;
            height: 200px;
            position: relative;
            transform-style: preserve-3d;
            transition: 3s;
        }
        #wrap #box div{
            width: 200px;
            height: 200px;
            font: 140px/200px "宋體";
            text-align: center;
            position: absolute;
            opacity: .5;
        }
        #box div:nth-child(1) {
            background: rgb(255, 0, 0);
            top: 0;
            left: 200px;
            /* 隻圍繞底部,可隻寫bottom */
            transform-origin: bottom;
            transform: rotateX(90deg);
        }
        #box div:nth-child(2) {
            background: rgb(200, 255, 0);
            top: 200px;
            left: 0;
            transform-origin: right;
            transform: rotateY(-90deg);
        }
        #box div:nth-child(3) {
            background: rgb(0, 255, 115);
            top: 200px;
            left: 200px;
            /* transform-origin: 200px bottom;
            transform: rotateX(90deg); */
        }
        #box div:nth-child(4) {
            background: rgb(0, 153, 255);
            top: 200px;
            left: 400px;
            transform-origin: left;
            transform: rotateY(90deg);
        }
        #box div:nth-child(5) {
            background: rgb(132, 0, 255);
            top: 400px;
            left: 200px;
            transform-origin: top;
            transform: rotateX(-90deg);
        }
        #box div:nth-child(6) {
            background: rgb(255, 0, 200);
            top: 200px;
            left: 200px;
            /* 第6面是在Z軸方向 */
            transform: translateZ(-200px) rotateY(180deg);
        }
        #wrap:hover #box{ 
            transform-origin: 300px 300px;
            transform: rotateY(180deg);
        }
    </style>
</head>
<body>
    <div id="wrap">
        <div id="box">
            <div>1</div>
            <div>2</div>
            <div>3</div>
            <div>4</div>
            <div>5</div>
            <div>6</div>
        </div>
    </div>
</body>
</html>
           
CSS 動畫專題(transition,animation,transform)1.目标及知識點:2.transition2.animation2.2 animation三個事件監聽: 3.transform 2D4.transform 3D5.requestAnimationFarme動畫幀6.Tween 動畫公式7.動畫架構mTween的使用8.動畫架構mTween示例—無縫滾動幻燈片

5.requestAnimationFarme動畫幀

人眼每秒可識别24幀,超過24幀在人眼中,就會形成連續動畫的錯覺。是以使用JS制作動畫,不斷修改元素的值,就可以實作動畫效果。

能使用CSS實作的效果,盡量使用CSS實作,而不是使用JS實作。CSS本身性能會比JS好。另外,一般做動畫,能操作transform改變的,不要使用修改left,top等值實作,因為這些屬性在解析完成後,會導緻回流。

requestAnimationFarme動畫幀不是CSS中的動畫幀,而是JS中本身存在的,window下的方法。

requestAnimationFarme動畫幀與定時器相關差別:動畫流暢度和性能都比定時器好。使用定時器做動畫有可能丢幀(畫面忽然卡一下)。

  1. 計算機顯示器重新整理頻率一般是60Hz,相當于每秒重繪60次
  2. 螢幕每次渲染時就會調用目前次requestAnimationFarme(注意并不是重複調用),看目前次requestAnimationFarme有沒有執行新的東西
  3. 動畫幀采用的是系統時間間隔,它與計算機螢幕重繪頻率保持一緻(高性能,視覺佳)
  4. 定時器執行時間間隔(16.6666循環)不精确
  5. 相容性 IE9 以下不相容
  6. 與setTimeOut類似,隻會執行一次,如果希望執行動畫效果,連續執行,就需要使用遞歸進行重複調用
  7. 注意遞歸調用多次都需要存儲requestAnimationFrame動畫幀編号,便于取消requestAnimationFrame
  • 開啟動畫幀:index requestAnimationFrame(fn):參數為函數(隻有一個參數),傳回值為動畫幀對應編号
  • 關閉動畫幀:cancelAnimationFrame()

需求:使用JS實作跑停動畫

使用定時器實作:

使用間隔定時器,不斷改變div的transform的值

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #box {
            width: 100px;
            height: 100px;
            background: red;
            margin-bottom: 50px;
        }
    </style>
</head>
<body>
    <div id="box"></div>
    <button>跑</button>
    <button>停</button>
    <script>
        var box = document.querySelector("#box");
        var l = 0;
        var btns = document.querySelectorAll("button");
        var timer = null;
        btns[0].onclick = function(){
            clearInterval(timer);
            timer = setInterval(function(){
                l +=10;
                box.style.transform = 'translateX('+ l +'px)';
            },50);
        };
        btns[1].onclick = function(){
            clearInterval(timer);
        };
    </script>
</body>
</html>
           

問題:發現使用定時器實作的動畫,并不流暢。

解決:使用requestAnimationFrame實作

注意遞歸調用多次都需要存儲requestAnimationFrame動畫幀編号,便于取消requestAnimationFrame

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #box {
            width: 100px;
            height: 100px;
            background: red;
            margin-bottom: 50px;
        }
    </style>
</head>
<body>
    <div id="box"></div>
    <button>跑</button>
    <button>停</button>
    <script>
        var box = document.querySelector("#box");
        var l = 0;
        var btns = document.querySelectorAll("button");
        var runner = 0;
        btns[0].onclick = function(){
            cancelAnimationFrame(runner);
            runner = requestAnimationFrame(setTranslateX);
            function setTranslateX(){
                l +=1;
                box.style.transform = 'translateX('+ l +'px)';
                runner = requestAnimationFrame(setTranslateX);
            }
        };

        btns[1].onclick = function(){
            cancelAnimationFrame(runner);
        };
    </script>
</body>
</html>
           

6.Tween 動畫公式

- Tween 參數解析

  • - t: current time(目前時間-目前運動次數),動畫執行到第幾次(動畫已經消耗的時間)
  • - b: beginning value(動畫開始前的初始值)
  • - c: change in value(變化量:動畫初始值和目标點之間的內插補點)
  • - d: duration(持續時間-運動總次數:動畫執行總次數)

Tween動畫算法:

/*
    Tween 動畫算法
*/    
var Tween = {
	linear: function (t, b, c, d){  //勻速
		return c*t/d + b;
	},
	easeIn: function(t, b, c, d){  //加速曲線
		return c*(t/=d)*t + b;
	},
	easeOut: function(t, b, c, d){  //減速曲線
		return -c *(t/=d)*(t-2) + b;
	},
	easeBoth: function(t, b, c, d){  //加速減速曲線
		if ((t/=d/2) < 1) {
			return c/2*t*t + b;
		}
		return -c/2 * ((--t)*(t-2) - 1) + b;
	},
	easeInStrong: function(t, b, c, d){  //加加速曲線
		return c*(t/=d)*t*t*t + b;
	},
	easeOutStrong: function(t, b, c, d){  //減減速曲線
		return -c * ((t=t/d-1)*t*t*t - 1) + b;
	},
	easeBothStrong: function(t, b, c, d){  //加加速減減速曲線
		if ((t/=d/2) < 1) {
			return c/2*t*t*t*t + b;
		}
		return -c/2 * ((t-=2)*t*t*t - 2) + b;
	},
	elasticIn: function(t, b, c, d, a, p){  //正弦衰減曲線(彈動漸入)
		if (t === 0) { 
			return b; 
		}
		if ( (t /= d) == 1 ) {
			return b+c; 
		}
		if (!p) {
			p=d*0.3; 
		}
		if (!a || a < Math.abs(c)) {
			a = c; 
			var s = p/4;
		} else {
			var s = p/(2*Math.PI) * Math.asin (c/a);
		}
		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
	},
	elasticOut: function(t, b, c, d, a, p){    //*正弦增強曲線(彈動漸出)
		if (t === 0) {
			return b;
		}
		if ( (t /= d) == 1 ) {
			return b+c;
		}
		if (!p) {
			p=d*0.3;
		}
		if (!a || a < Math.abs(c)) {
			a = c;
			var s = p / 4;
		} else {
			var s = p/(2*Math.PI) * Math.asin (c/a);
		}
		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
	},    
	elasticBoth: function(t, b, c, d, a, p){ 
		if (t === 0) {
			return b;
		}
		if ( (t /= d/2) == 2 ) {
			return b+c;
		}
		if (!p) {
			p = d*(0.3*1.5);
		}
		if ( !a || a < Math.abs(c) ) {
			a = c; 
			var s = p/4;
		}
		else {
			var s = p/(2*Math.PI) * Math.asin (c/a);
		}
		if (t < 1) {
			return - 0.5*(a*Math.pow(2,10*(t-=1)) * 
					Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
		}
		return a*Math.pow(2,-10*(t-=1)) * 
				Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b;
	},
	backIn: function(t, b, c, d, s){     //回退加速(回退漸入)
		if (typeof s == 'undefined') {
		   s = 1.70158;
		}
		return c*(t/=d)*t*((s+1)*t - s) + b;
	},
	backOut: function(t, b, c, d, s){
		if (typeof s == 'undefined') {
			s = 1.70158;  //回縮的距離
		}
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
	}, 
	backBoth: function(t, b, c, d, s){
		if (typeof s == 'undefined') {
			s = 1.70158; 
		}
		if ((t /= d/2 ) < 1) {
			return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
		}
		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
	},
	bounceIn: function(t, b, c, d){    //彈球減振(彈球漸出)
		return c - Tween['bounceOut'](d-t, 0, c, d) + b;
	},       
	bounceOut: function(t, b, c, d){//*
		if ((t/=d) < (1/2.75)) {
			return c*(7.5625*t*t) + b;
		} else if (t < (2/2.75)) {
			return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b;
		} else if (t < (2.5/2.75)) {
			return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;
		}
		return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;
	},      
	bounceBoth: function(t, b, c, d){
		if (t < d/2) {
			return Tween['bounceIn'](t*2, 0, c, d) * 0.5 + b;
		}
		return Tween['bounceOut'](t*2-d, 0, c, d) * 0.5 + c*0.5 + b;
	}
};
           

Tween的使用:

(function(){
        var box = document.querySelector("#box");
        //easeOut: function(t, b, c, d)     //減速曲線
        var t = 0;//動畫執行到第幾次(動畫已經消耗的時間)
        var b = 0;//動畫開始前的初始值
        var c = 500;//動畫初始值和目标點的內插補點
        var d = 10;//動畫執行總次數
        var s = 100;//回退的距離
        var btns = document.querySelectorAll("button");
        btns[0].onclick = function(){
            t++;
            var val = Tween["easeOut"](t, b, c, d);
            box.style.transform = 'translateX('+ val +'px)';
        };

    })();
           

動畫幀中使用Tween:

(function(){
        var box = document.querySelector("#box");
        //bounceIn: function(t, b, c, d)     //彈球減振(彈球漸出)
        var t = 0;//動畫執行到第幾次(動畫已經消耗的時間)
        var b = 0;//動畫開始前的初始值(如初始寬度等)
        var c = 500;//動畫初始值和目标點的內插補點(如希望動畫走600,初始值為100,則內插補點應設定為500)
        var d = 20;//動畫執行總次數
        var s = 100;//回退的距離
        var btns = document.querySelectorAll("button");
        var timer = 0;
        btns[0].onclick = function(){
            cancelAnimationFrame(timer);
            timer = requestAnimationFrame(move);
            function move(){
                t++;
                var val = Tween["bounceIn"](t, b, c, d);
                box.style.transform = 'translateX('+ val +'px)';
                console.log(t);
                
                //判斷當執行次數到達設定的次數時,不再繼續執行
                if(t<d){
                    timer = requestAnimationFrame(move);
                }
            }
        };
        btns[1].onclick = function(){
            cancelAnimationFrame(timer);
        };
    })();
           

7.動畫架構mTween的使用

- css(el,attr[,value]) css 函數 設定或擷取樣式
      - 注意: 非數值類樣式的處理
      - 注意: transform 相關樣式的處理問題
    - mTween(option) 動畫函數
      - option:{
         el: element要動畫的元素,
         attr: {
           要動畫的樣式: '目标值',
           要動畫的樣式2: '目标值'
         },
         duration: nub||op, 動畫時間
          - op: {
            multiple: 根據距離計算動畫時間比例
            max: 動畫最大時間
            min: 動畫最小時間
          }
         fx:'動畫形式',
         moveing: function(){}, 動畫執行中回調
         cb:function(){} 動畫執行之後回調
      }
    - mTween.stop(el) 停止某個元素的動畫
           

css(el,attr[,value]) css 函數 設定或擷取樣式,兩個參數時是擷取,三個參數時是設定樣式。因為css方法主要是配合動畫使用的,是以機關進行了處理。

  • - 注意: 非數值類樣式的處理:非數值類樣式隻能擷取,不能設定,更不能用于動畫;
  • - 注意: transform 相關樣式的處理問題:transform 不能擷取計算後樣式,是以必須通過css()方法進行操作,且必須先設定(給定初始化值),再擷取即可

隻有以下樣式可以用于動畫:

"background"
    "opacity"
    "rotate",
    "rotateX",
    "rotateY",
    "rotateZ",
    "translateX",
    "translateY",
    "translateZ",
    "scale",
    "scaleX",
    "scaleY",
    "skewX",
    "skewY"
    "width",
    "height",
    "left",
    "top",
    "right",
    "bottom",
    "marginBottom",
    "marginleft",
    "marginRight",
    "marginTop",
    "paddingLeft",
    "paddingRight",
    "paddingTop",
    "paddingBottom"
           
<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #box {
            position: absolute;
            left: 0;
            top: 100px;
            width: 100px;
            height: 100px;
            background: red;
        }
    </style>
</head>
<body>
<div id="box"></div>
<script src="mTween.js"></script>
<script>
(function(){
    var box = document.querySelector("#box");
    //擷取樣式
    console.log(css(box,"width"));//100注意沒有機關,mTween架構已經對機關進行了處理
    //設定樣式
    css(box,"height",400);
    //非數值類樣式隻能擷取,不能設定,但是顔色可以設定
    css(box,"background","blue");
    console.log(css(box,"background"));//rgb(0, 0, 255) none repeat scroll 0% 0% / auto padding-box border-box
    css(box,"float","left");
    console.log(css(box,"float"));//none
    
})();    
</script>    
</body>
</html>
           

transform 相關樣式的處理問題:

//transform不能擷取計算後樣式,是以所有操作必須通過css()方法進行。且需要先設定再擷取
    console.log(css(box,"translateX"));//undefined
    css(box,"translateX",20);
    console.log(css(box,"translateX"));//20
           

mTween同時設定多個值:需要傳一個對象進去

//同時設定多個樣式,需要傳入一個對象
    css(box,{
        "width":200,
        "height":200,
        "background":"blue",
        "translateX":200
    });
           

動畫架構的使用:

設定屬性值:

mTween({
                el:box,
                attr:{
                    width:200,
                    height:200,
                    // translateX:20
                    rotate:360
                });
           

設定動畫持續時間: 

//動畫持續時間(機關秒),預設時間400毫秒
                // duration:1000
                //動畫持續時間第二種用法,比例設定:
                duration:{
                    multiple: 1,//根據距離計算動畫時間比例:擷取到attr樣式中最大內插補點,計算時間,此處360,然後360*1 就為360毫秒
                    min: 200,//動畫最大時間:如果 multiple*最大內插補點的時間小于min,則使用min的時間,非min和max,則使用multiple*最大內插補點的時間
                    max: 1000//動畫最小時間:如果 multiple*最大內插補點的時間大于max,則使用max的時間,非min和max,則使用multiple*最大內插補點的時間
                },
           

設定動畫執行樣式:

//動畫執行樣式(參照transition)
                fx:"linear",
           

設定回調函數:動畫執行中和動畫執行結束 回調

//回調:動畫執行中和動畫執行結束
                cb:function(){
                    console.log("動畫執行完成");
                    //控制動畫過程:想在動畫執行完成後,再執行其他的動畫,直接在cb函數值再進行調用
                    mTween({
                        el:box,
                        attr:{
                            translateX:40  
                        }
                    });
                    
                },
                //動畫執行過程中:計算機每秒執行60次,在duration給定時間内,會列印duration/60次。即一次列印用時1000/60 = 16.6666666次。總共有16.666666*3次約等于50次
                moveing:function(){
                    console.log("動畫執行過程中");//列印66次
                }
           

動畫執行過程中結束動畫:

//想在動畫執行過程中結束動畫,mTween.stop(動畫執行的元素)
                mTween.stop(box);
           

完整示例:

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #box {
            width: 100px;
            height: 100px;
            background: red;
            margin-bottom: 50px;
        }
    </style>
</head>
<body>
    <div id="box"></div>
    <button>執行</button>
    <button>停</button>
    <script src="mTween.js"></script>
    <script>
        var box = document.querySelector("#box");
        var btns = document.querySelectorAll("button");
        btns[0].onclick = function(){
            //如果要設定transform,一定要先通過css()方法進行設定
            css(box,"translateX",0);
            css(box,"rotate",0);
            //動畫架構的使用
            mTween({
                el:box,
                attr:{
                    width:200,
                    height:200,
                    // translateX:20
                    rotate:360
                },

                //動畫持續時間(機關秒),預設時間400毫秒
                // duration:1000
                //動畫持續時間第二種用法,比例設定:
                duration:{
                    multiple: 1,//根據距離計算動畫時間比例:擷取到attr樣式中最大內插補點,計算時間,此處360,然後360*1 就為360毫秒
                    min: 200,//動畫最大時間:如果 multiple*最大內插補點的時間小于min,則使用min的時間,非min和max,則使用multiple*最大內插補點的時間
                    max: 1000//動畫最小時間:如果 multiple*最大內插補點的時間大于max,則使用max的時間,非min和max,則使用multiple*最大內插補點的時間
                },

                //動畫執行樣式(參照transition)
                fx:"linear",

                //回調:動畫執行中和動畫執行結束
                cb:function(){
                    console.log("動畫執行完成");
                    //控制動畫過程:想在動畫執行完成後,再執行其他的動畫,直接在cb函數值再進行調用
                    mTween({
                        el:box,
                        attr:{
                            translateX:40  
                        }
                    });
                    
                },
                //動畫執行過程中:計算機每秒執行60次,在duration給定時間内,會列印duration/60次。即一次列印用時1000/60 = 16.6666666次。總共有16.666666*3次約等于50次
                moveing:function(){
                    console.log("動畫執行過程中");//列印66次
                }
            });
            
            btns[1].onclick = function(){
                //想在動畫執行過程中結束動畫,mTween.stop(動畫執行的元素)
                mTween.stop(box);
            };
        };

    </script>
</body>
</html>
           

8.動畫架構mTween示例—無縫滾動幻燈片