1.动画与过渡

过渡与动画的区别:

  • 过渡:元素状态的变化。比如:一个块的颜色慢慢从红到蓝。
  • 动画:元素位置的变化。比如:一个块从左边慢慢移动到右边。

1.1.动画

1.1.1.回顾CSS动画

下面是一个CSS3过渡效果。刷新时,在3秒钟时间内文字向右方移动后再回到原位置。

  1. <style>
  2. /* 定义动画规则 */
  3. @keyframes boxanimate {
  4. 0% {
  5. transform: translateX(0);
  6. }
  7. 50% {
  8. transform: translateX(50px);
  9. }
  10. 100% {
  11. transform: translateX(0);
  12. }
  13. }
  14. .box{
  15. /* 使用animation样式应用divanimate动画 */
  16. animation: boxanimate 3s;
  17. }
  18. </style>
  19. <body>
  20. <div class="box">这是会动的文字</div>
  21. </body>

1.1.2.在Vue中使用CSS动画

上面的动画在Vue中当然也是有效的。

但如果想使用Vue来控制动画的启动,就可以使用绑定class属性的方式。

<style>
    ...
</style>

<body>

    <div id="app">
        <div :class="{box:isAnimate}">这是会动的文字</div>
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        Vue.createApp({
            data() {
                return {
                    isAnimate:true
                }
            }
        }).mount('#app');
    </script>
</body>
  • 上面实例中,当isAnimate为true时,刷新时就会启用动画。

1.1.3.使用事件控制动画

还可以通过Vue事件来控制动画的启动和停止。

<style>
    /* 定义动画规则 */
    @keyframes boxanimate {
        0% {
            transform: translateX(0);
        }
        50% {
            transform: translateX(50px);
        }
        100% {
            transform: translateX(0);
        }
    }

    .box{
        /* 使用animation样式应用divanimate动画 */
        animation: boxanimate 3s;
    }
</style>

<body>

    <div id="app">
        <div :class="{box:isAnimate}" @mouseover="over" @mouseout="out">这是会动的文字</div>
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        Vue.createApp({
            data() {
                return {
                    isAnimate:false
                }
            },
            methods:{
                over(){
                    this.isAnimate = true;
                },
                out(){
                    this.isAnimate = false;
                }
            }
        }).mount('#app');
    </script>
</body>

1.2.过渡

1.2.1.回顾CSS过渡

下面是一个CSS3过渡效果。当鼠标移动到文字上时,在3秒钟时间内背景颜色由红过渡到蓝色。

<style>
    .box {
        background-color: red;
        /*持续时间为3秒*/
        transition: 3s;
    }

    /*这里使用hover来触发过渡*/
    div:hover {
        background-color: blue;
    }
    </style>

    <div class="box">这是会改变背景颜色的文字</div>

附录:常用过渡函数(默认值为ease函数):

  • ease: 开始和结束慢,中间快。
  • linear: 匀速。
  • ease-in: 开始慢。
  • ease-out: 结束慢。
  • ease-in-out: 和ease类似,但比ease幅度大。
  • step-start: 直接位于结束处。
  • step-end: 位于开始处经过时间间隔后结束。

1.2.2.在Vue中实现过渡

在Vue中实现过渡效果时,由于需要触发过渡时机,所以需要绑定多个样式。

<style>
    .box {
        background-color: red;
        /*持续时间为3秒*/
        transition: 3s;
    }

    .boxblue {
        background-color: blue;
    }
</style>

<body>
    <div id="app">
        <div :class="{box:true,boxblue:isAnimate}" @mouseover="over" @mouseout="out">这是会改变背景颜色的文字</div>
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        Vue.createApp({
            data() {
                return {
                    isAnimate: false
                }
            },
            methods: {
                over() {
                    this.isAnimate = true;
                },
                out() {
                    this.isAnimate = false;
                }
            }
        }).mount('#app');
    </script>
</body>
  • 上面实例中,当鼠标悬停和移出时,实际上就是对象boxblue样式的切换使用。

2.入场出场的过渡与动画

上面学到的动画与过渡,实际应用最广泛的就是组件元素的入场动画和出场动画,这可以让组件元素切换时显得更加流畅,提升用户体验度。

比如,下面实例中,元素的显示和隐藏时非常直接,没有过渡,导致用户体验度差。

<body>

    <div id="app">
        <button @click="change">切换</button>
        <mycomponent v-if="isShow"></mycomponent>
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        Vue.createApp({
            data() {
                return {
                    isShow:false
                }
            },
            methods:{
                change(){
                    this.isShow = !this.isShow;
                }
            },
            components:{
                mycomponent:{
                    template: '<div>我是子组件</div>'
                }
            }
        }).mount('#app');
    </script>
</body>

因此,Vue中将动画与过渡进行了封装,以便让我们更快捷的实现入场出场动画。

2.1.过渡型入场出场

<style>
    /*入场动画的开始状态*/
    .v-enter-from {
        opacity: 0;
    }
    /*入场动画的结束状态*/
    .v-enter-to {
        opacity: 1;
    }
    /*入场动画如何过渡*/
    .v-enter-active {
        transition: opacity 3s ease;
    }
</style>

<body>

    <div id="app">
        <button @click="change">切换</button>
        <!-- 使用transition标签包装需要动画的元素 -->
        <transition>
            <mycomponent v-if="isShow"></mycomponent>
        </transition>
    </div>

    ...
</body>
  • 首先,需要将实现入场动画的元素用transition标签包裹。
  • 然后,实现三个固定类名的样式,分别表示开始状态、结束状态、如何过渡。

接下来继续实现出场动画:

<style>
    ...

    .v-leave-from {
        opacity: 1;
    }
    .v-leave-to {
        opacity: 0;
    }
    .v-leave-active {
        transition: opacity 3s ease;
    }
</style>

上面样式可以进行优化:

<style>
    .v-enter-from {
        opacity: 0;
    }
    .v-enter-to {
        opacity: 1;
    }
    .v-enter-active,.v-leave-active {
        transition: opacity 3s ease;
    }
    .v-leave-to {
        opacity: 0;
    }
    .v-leave-active {
        transition: opacity 3s ease;
    }
</style>
  • .v-leave-from可以省略

2.2.动画型入场出场

<style>
    /*入场动画规则*/
    @keyframes boxenter {
        0% {
            transform: translateX(-100px);
        }
        100% {
            transform: translateX(0);
        }
    }
    /*出场动画规则*/
    @keyframes boxleave {
        0% {
            transform: translateX(0);
        }
        100% {
            transform: translateX(-100px);
        }
    }
    /*这里应用入场动画规则*/
    .v-enter-active {
        animation: boxenter 3s;
    }
    /*这里应用出场场动画规则*/
    .v-leave-active {
        animation: boxleave 3s;
    }
</style>

<body>

    <div id="app">
        <button @click="change">切换</button>
        <!-- 使用transition标签包装需要动画的元素 -->
        <transition>
            <mycomponent v-if="isShow"></mycomponent>
        </transition>
    </div>

    ...
</body>

2.3.实现混合效果

将上面实例的样式结合起来,就可以实现元素既有过渡效果,又有动画效果。

<style>
    .v-enter-from {
        opacity: 0;
    }
    .v-enter-to {
        opacity: 1;
    }
    .v-leave-to {
        opacity: 0;
    }

    @keyframes boxenter {
        0% {
            transform: translateX(-100px);
        }
        100% {
            transform: translateX(0);
        }
    }
    @keyframes boxleave {
        0% {
            transform: translateX(0);
        }
        100% {
            transform: translateX(-100px);
        }
    }
    .v-enter-active {
        animation: boxenter 3s;
        transition: opacity 3s ease;
    }
    .v-leave-active {
        animation: boxleave 3s;
        transition: opacity 3s ease;
    }
</style>

2.4.列表动画

上面实例都是对单元素的入场与出场,但实际开发中很多时候都需要使用多元素(比如:列表)。那么Vue也封装了多元素的入场与出场。

<style>
    @keyframes boxenter {
        0% {
            transform: translateX(-100px);
        }
        100% {
            transform: translateX(0);
        }
    }
    .v-enter-active {
        animation: boxenter .5s;
    }
</style>

<body>

    <div id="app">
        <transition>
            <ul>
                <!-- 将transition标签改为transition-group标签即可 -->
                <transition-group>
                    <li v-for="item in arr" :key="item">{{item}}</li>
                </transition-group>
            </ul>
        </transition>
        <button @click="add">添加</button>
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        Vue.createApp({
            data() {
                return {
                    arr: []
                }
            },
            methods:{
                add(){
                    this.arr.unshift(this.arr.length+1);
                }
            }
        }).mount('#app');
    </script>
</body>

上面代码中,需要做动画的元素是一个通过v-for遍历出来的一个列表。此时只要使用 transition-group 标签,就可实现列表出场动画。

但是,上面代码中,列表中的新元素是可以实现动画的,但原有元素还没有动画。我们可以通过增加 v-move样式来指定原有元素的动画。

<style>
    @keyframes boxenter {
        0% {
            transform: translateX(-100px);
        }
        100% {
            transform: translateX(0);
        }
    }
    .v-enter-active {
        animation: boxenter .5s;
    }
    /* 增加v-move样式 */
    .v-move {
        transition: all .5s ease;
    }
</style>