04-过渡&动画效果

118 阅读2分钟

Vue 动画说明

  元素在显示和隐藏的时候可以实现过滤或者动画的效果,常用的过渡和动画都是使用 CSS 来实现的:

  • 在 CSS 中操作 trasition(过滤)animation(动画) 达到不同的效果
  • 为目标元素添加一个父元素 <trasition name='xxx'>,让父元素通过自动应用 class 类名来达到效果(没有指定名字 name,默认就是 v-
  • 过渡与动画时,会为对应元素动态添加的相关 class 类名
    • xxx-enter: 定义显示前的效果
    • xxx-enter-active: 定义显示过程的效果
    • xxx-enter-to: 定义显示后的效果
    • xxx-leave: 定义隐藏前的效果
    • xxx-leave-active: 定义隐藏过程的效果
    • xxx-leave-to: 定义隐藏后的效果

01.png

过渡效果案例

  1. 为目标元素添加父元素 <trasition name='xxx'>
  2. 定义 class 过渡样式
    1. 指定过渡样式:trasition
    2. 指定隐藏时的样式:opacity(持续时间)/其它
  3. 功能实现:点击按钮后,显示隐藏文本
    1. 效果1:显示和隐藏有渐变效果
    2. 效果2:显示和隐藏有平移效果,并持续时长不同
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
    <style>
        /* 显示或隐藏的过渡效果 */
        .gradual-enter-active,
        .gradual-leave-active {
            transition: opacity 1s;
        }

        /* 显示前或隐藏后的效果 */
        .gradual-enter,
        .gradual-leave-to {
            opacity: 0;
        }

        /* 显示过渡效果 */
        .tran-enter-active {
            transition: all 1s;
        }

        /* 隐藏过渡效果 */
        .tran-leave-active {
            transition: all 5s;
        }

        /* 显示前或隐藏后的效果 */
        .tran-enter,
        .tran-leave-to {
            opacity: 0;
            transform: translateX(10px);
        }
    </style>
</head>
<body>
    <div id="app">
        <button @click="isShow = !isShow">渐变</button>
        <transition name="gradual">
            <p v-show="isShow">渐变过渡效果的文档</p>
        </transition>
        <hr>
        <button @click="isShow1 = !isShow1">平移</button>
        <transition name="tran">
            <p v-show="isShow1">平移的效果的文档</p>
        </transition>
    </div>
    <script>
        let app = new Vue({
            data() {
                return {
                    isShow: true,
                    isShow1: true
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

02.gif

动画效果案例

  CSS 动画用法同 CSS 过渡,只不过采用 animation 作为指定动画效果:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
    <style>
        .bounce-enter-active {
            animation: bounce-in 1s;
        }
        .bounce-leave-active {
            animation: bounce-in 3s reverse;
        }

        @keyframes bounce-in {
            0% {
                transform: scale(0);
            }

            50% {
                transform: scale(1.5);
            }

            100% {
                transform: scale(1);
            }
        }
    </style>
</head>
<body>
    <div id="app">
        <button @click="isShow = !isShow">动画</button>
        <!--appear 第一次出现就要有动画-->
        <transition name="bounce" appear>
            <p v-show="isShow">Lorem ipsum dolor sit amet consectetur adipisicing elit. Adipisci ea tempore non quisquam reiciendis, numquam necessitatibus debitis similique. Ipsum, doloribus ea! Non voluptate reprehenderit porro possimus quia culpa commodi neque!</p>
        </transition>
    </div>
    <script>
        let app = new Vue({
            data() {
                return {
                    isShow: true
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

03.gif

多个元素过渡

  当有相同标签名的元素切换时,需要通过 key 特性设置唯一的值来标记以让 Vue 区分它们,否则 Vue为了效率只会替换相同标签内部的内容。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
    <style>
        /* 显示过渡效果 */
        .tran-enter-active {
            transition: all 2s;
        }

        /* 隐藏过渡效果 */
        .tran-leave-active {
            transition: all 2s;
        }

        /* 显示前或隐藏后的效果 */
        .tran-enter,
        .tran-leave-to {
            opacity: 0;
            transform: translateX(10px);
        }
    </style>
</head>
<body>
    <div id="app">
        <button @click="isShow = !isShow">平移</button>
        <!-- mode:in-out ; out-in 切换的方式 -->
        <transition name="tran" mode="out-in">
            <p v-if="isShow" key="1">11111111111111111</p>
            <p v-else key="2">222222222222</p>
        </transition>
    </div>
    <script>
        let app = new Vue({
            data() {
                return {
                    isShow: true
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

04.gif

多个组件的过渡

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
    <style>
        /* 显示过渡效果 */
        .tran-enter-active {
            transition: all 1s;
        }

        /* 隐藏过渡效果 */
        .tran-leave-active {
            transition: all 1s;
        }

        /* 显示前或隐藏后的效果 */
        .tran-enter,
        .tran-leave-to {
            opacity: 0;
            transform: translateX(10px);
        }
    </style>
</head>
<body>
    <div id="app">
        <transition name="tran" mode="out-in">
            <!-- 通过绑定is来确定当前的组件 -->
            <component :is="which"></component>
        </transition>
        <button @click="which = which == 'component-a' ? 'component-b' : 'component-a'">切换</button>
    </div>
    </div>
    <script>
        const ComponentA = {
            template: `
                <div>
                    ComponentA
                </div>
                `
        }

        const ComponentB = {
            template: `
                <div>
                    ComponentB 
                </div>
                `
        }

        let app = new Vue({
            data() {
                return {
                    which: 'component-a'
                }
            },
            components: {
                ComponentA,
                ComponentB
            }
        }).$mount('#app');
    </script>
</body>
</html>

05.gif

列表过渡

  <transition-group> 不同于 transition, 它会以一个真实元素呈现(默认为一个 <span>),你也可以通过 tag 特性更换为其它元素。需要提供唯一的 key 属性值:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
    <style>
        /* 进场动画 */
        .tran-enter-active {
            animation: aaa 1.5s;
        }
    
        /* 出场动画 */
        .tran-leave-active {
            animation: aaa 1.5s reverse;
        }
    
        @keyframes aaa {
            0% {
                opacity: 0;
                transform: translateX(100px);
            }
    
            100% {
                opacity: 1;
                transform: translateX(0px);
            }
        }
    </style>
</head>
<body>
    <div id="app">
        <!-- 双向绑定的指令 -->
        <input type="text" v-model="mytext"/>
        <button @click="handleAdd()">add</button>

        <div v-show="!datalist.length">待办事项空空如也</div>

        <transition-group name="tran" tag="ul" v-show="datalist.length">
            <li v-for="(item,index) in datalist" :key="item">
                {{item}}--{{index}}
                <button @click="handleDel(index)">del</button> 
            </li>
        </transition-group>
    </div>
    </div>
    <script>

        let app = new Vue({
            data() {
                return {
                    mytext:"11111",
                    datalist:["111","222","333"]
                }
            },
            methods:{
                handleAdd(){
                    this.datalist.push(this.mytext);
                    this.mytext = ""; //清空value
                },
                handleDel(index){
                    this.datalist.splice(index,1);
                }
            }
        }).$mount('#app');
    </script>
</body>
</html>

06.gif