利用requestAnimationFrame重新播放(触发)CSS3动画

in css动画 with 0 comments, 6092 views

css动画

css3中引入了animation模块,自此css动画进入了我们的视野。css动画名符其实,会写css样式就可以创作动画,对一些不怎么会JS的设计师也是比较包容的。但也正因为如此,当你需要重新播放或者说手动触发动画时,css的局限性就突显出来了,毕竟它不是一门编程语言。像这种在页面中创建一个按钮,点击按钮时开始播放一段动画这种活交给JS才是最合适的。

原理和思路

重新播放css动画,我们只需要将CSS动画效果删除,然后再重新加上css动画效果即可。那么如何让浏览器理解我们的意图呢,今天的主角requestAnimationFrame,这个任务就交给它来完成。requestAnimationFrame会告诉浏览器--你需要执行一个动画,并要求在下一次重绘前调用指定的回调函数更新动画。也就是requestAnimationFrame需要传入一个回调函数作为参数,这个函数会在浏览器下一次重绘之前执行。 这个机制可以用花费最短的时间让浏览器理解我们需要重新播放动画的意图。

当然requestAnimationFrame只是其中的一步,我们还需要再加上个小技巧--分离动画样式.

关键代码

<template>
    <div class="page-animate">
        <button @click="handleAnimate">开始动画</button>
        <div class="rabbit-box">
            <div class="rabbit" ref="rabbit"></div>
        </div>
    </div>
</template>

<script>
  export default {
    name: "animate",
    methods: {
      handleAnimate() {
        let $rabbit = this.$refs.rabbit;
        $rabbit.classList.remove('animated');
        window.requestAnimationFrame(()=> {
          window.requestAnimationFrame(()=>{
            $rabbit.classList.add('animated');
          })
        })
      }
    }
  }
</script>

<style lang="less">
.page-animate {
    .rabbit-box {
        margin-top: 10px;
        width: 100px;
        height: 100px;
        background:#e2b29f;
        font-size:120%;
        padding: 100px;
        border-radius: 50%;
    }

    .rabbit {
        width:5em;
        height:3em;
        background:#ffffff;
        border-radius:70% 90% 60% 50%;
        position:relative;
        box-shadow: -0.2em 1em 0 -0.75em #b78e81;
        transform:rotate(0deg) translate(-2em,0);
        z-index:1;
        .no-flexbox & {margin:10em auto 0;}
        //tail, eye, feet
        &:before {
            content:"";
            position:absolute;
            width:1em;
            height:1em;
            background:white; // tail
            border-radius:100%;
            top:0.5em;
            left:-0.3em;
            box-shadow:
                    4em 0.4em 0 -0.35em #3f3334, // eye
                    0.5em 1em 0 white, // back foot
                    4em 1em 0 -0.3em white, // front foot
                    4em 1em 0 -0.3em white,
                    4em 1em 0 -0.4em white;;
        }
        // ears
        &:after {
            content:"";
            position:absolute;
            width:.75em;
            height:2em;
            background:white;
            border-radius:50% 100% 0 0;
            transform:rotate(-30deg);
            right:1em;
            top:-1em;
            border-top:1px solid #f7f5f4;
            border-left: 1px solid #f7f5f4;
            box-shadow:-0.5em 0em 0 -0.1em white;
        }
        &.animated {
            animation: hop 1s linear;
            &:before {
                animation: kick 1s linear;
            }
        }
    }

    @keyframes hop {
        20% {
        transform:rotate(-10deg) translate(1em,-2em);
            box-shadow: -0.2em 3em 0 -1em #b78e81;
        }
        40% {
        transform:rotate(10deg) translate(3em,-4em);
            box-shadow: -0.2em 3.25em 0 -1.1em #b78e81;
        }
        60%,75% {
        transform:rotate(0) translate(4em,0);
            box-shadow: -0.2em 1em 0 -0.75em #b78e81;
        }
    }



    @keyframes kick {
        20%,50% {
            box-shadow:
                    4em 0.4em 0 -0.35em #3f3334,
                    0.5em 1.5em 0 white,
                    4em 1.75em 0 -0.3em white,
                    4em 1.75em 0 -0.3em white,
                    4em 1.9em 0 -0.4em white;
        }
        40% {
            box-shadow:
                    4em 0.4em 0 -0.35em #3f3334,
                    0.5em 2em 0 white,
                    4em 1.75em 0 -0.3em white,
                    4.2em 1.75em 0 -0.2em white,
                    4.4em 1.9em 0 -0.2em white;
        }
    }
}
</style>

效果:

demo.gif

😁为了生动形象一些,特地找了个兔子的CSS动画。css类.rabbit中只定义了兔子的外观,没有定义动画相关的信息。我们把动画相关的信息都放到了.animated类中。

demo传送

handleAnimate函数是我们的关键部分:

总结

javascript相对css更适合用来控制动画,动画的触发机制和浏览器渲染机制相关。

参考

MDN

Responses ${replyToWho} / Cancel Reply