04-Vue中的动画

nobility 发布于 2022-01-31 1872 次阅读


Vue中的动画

单元素/组件动画

使用transition标签进行包裹的元素就是要执行动画的元素,transition是Vue封装的组件,可使用v-ifv-show以及动态组件

  • 入场动画:

    • 第一帧会自动为要执行动画的元素添加.v-enter和.v-enter-active两个类名
    • 第二帧会将.v-enter去除,并添加.v-enter-to类名
    • 动画结束会将.v-enter-to.v-enter-active两个类名去除
  • 出场动画:

    • 第一帧会自动为要执行动画的元素添加.v-leave和.v-leave-active两个类名
    • 第二帧会将.v-leave去除,并添加.v-leave-to类名
    • 动画结束会将.v-leave-to.v-leave-active两个类名去除

也就是说,.v-enter.v-leave为动画前的状态,.v-enter-to.v-leave-to为动画后的状态,.v-enter-active.v-leave-active为动画(监听过渡)

可为transition定义name属性来修改类名的前缀,若不定义name属性则会默认以v作为前缀

过渡

  • 入场过渡只要实现.v-enter.v-enter-active,动画会平滑从入场状态过渡到原本状态.v-enter-to就是元素原本状态,所以可省)
  • 出场过渡只要实现.v-leave-to.v-leave-active,动画会平滑从原本状态过渡到出场状态.v-leave就是元素原本状态,所以可省)
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>hello world</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- CDN方式引入Vue -->
  <style>
    .v-enter{
      opacity: 0;
    }
    .v-leave-to{
      opacity: 0;
    }
    .v-enter-active,
    .v-leave-active{
      transition: all 1s;
    }
  </style>
</head>

<body>
  <div id="app">
    <button @click="clickHandle">按钮</button>
    <transition>
      <h1 v-show="show">要执行动画的元素</h1>
    </transition>
  </div>
  <script>
    var app = new Vue({ //创建Vue实例
      el: "#app",
      data(){ return { show: true } },
      methods: { clickHandle(){ this.show = !this.show } }
    });
  </script>
</body>

</html>

帧动画

自定义帧动画
  • 入场动画只需要在.v-enter-active中调用帧动画即可
  • 出场动画只需要在.v-leave-active中调用帧动画即可
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>hello world</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- CDN方式引入Vue -->
  <style>
    @keyframes anim{
      0%{ 
        opacity: 0;
      }
      100%{
        opacity: 1;
      }
    }
    .v-enter-active{
      animation: anim 1s;
    }
    .v-leave-active{
      animation: anim 1s reverse;
    }
  </style>
</head>

<body>
  <div id="app">
    <button @click="clickHandle">按钮</button>
    <transition>
      <h1 v-show="show">自定义帧动画</h1>
    </transition>
  </div>
  <script>
    var app = new Vue({ //创建Vue实例
      el: "#app",
      data(){ return { show: true } },
      methods: { clickHandle(){ this.show = !this.show } }
    });
  </script>
</body>

</html>
animate.css

将入场动画.v-enter-active和出场动画.v-leave-active自定义为animate.css库中的类名即可

  • 要想使animate.css中的帧动画生效必须加animated
  • animate.css的4.0版本中又将所有的类名增加了animate__的前缀(两个短横线)
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>hello world</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- CDN方式引入Vue -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
  <style>
    @keyframes anim{
      0%{ opacity: 0; }
      100%{ opacity: 1; }
    }
    .enter{
      animation: anim 1s;
    }
    .leave{
      animation: anim 1s reverse;
    }
  </style>
</head>

<body>
  <div id="app">
    <button @click="clickHandle">按钮</button>
    <transition enter-active-class="enter" leave-active-class="leave">
      <!-- 可使用xxx-class属性自定义要添加的类名 -->
      <h1 v-show="show">自定义帧动画</h1>
    </transition>
    <transition
    appear
    appear-active-cliss="animate__animated animate__backInDown"
    enter-active-class="animate__animated animate__backInDown"
    leave-active-class="animate__animated animate__backOutDown">
      <h1 v-show="show">Animate.css</h1>
      <!-- appear和appear-active-cliss用于元素首次出现时的动画效果 -->
    </transition>
  </div>
  <script>
    var app = new Vue({ //创建Vue实例
      el: "#app",
      data(){ return { show: true } },
      methods: { clickHandle(){ this.show = !this.show } }
    });
  </script>
</body>

</html>

同时使用过渡和帧动画

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>hello world</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- CDN方式引入Vue -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
  <style>
    .v-enter,
    .v-leave-to{
      opacity: 0;
    }
    .v-enter-active,
    .v-leave-active{
      transition: all 0.5s;
    }
  </style>
</head>

<body>
  <div id="app">
    <button @click="clickHandle">按钮</button>
    <h2>
      在添加上原来的v-enter-active和v-leave-active类即可,
      但是若两种动画时长不一样时会出现诡异的效果,animate.css为1s,过渡动画为0.5s
      可通过type属性进行确定以哪种动画市场为准,一般时间以长的为准(可选animation或transition)
      也可使用绑定duration属性来自定义决定动画时长,该值可以是一个数字(单位毫秒),也可是一个对象
    </h2>
      <transition
      type="animation"
      enter-active-class="animate__animated animate__backInDown v-enter-active"
      leave-active-class="animate__animated animate__backOutDown v-leave-active">
        <h1 v-show="show">type属性确定动画时长</h1>
      </transition>
      <transition
      :duration="1000"
      enter-active-class="animate__animated animate__backInDown v-enter-active"
      leave-active-class="animate__animated animate__backOutDown v-leave-active">
        <h1 v-show="show">绑定duration属性确定动画时长(数值方式)入场和出场</h1>
      </transition>
      <transition
      :duration="{enter:3000,leave:2000}"
      enter-active-class="animate__animated animate__backInDown v-enter-active"
      leave-active-class="animate__animated animate__backOutDown v-leave-active">
        <h1 v-show="show">绑定duration属性确定动画时长(对象方式)分别定义入场和出场</h1>
      </transition>
  </div>
  <script>
    var app = new Vue({ //创建Vue实例
      el: "#app",
      data(){ return { show: true } },
      methods: { clickHandle(){ this.show = !this.show } }
    });
  </script>
</body>

</html>

JS动画

自定义JS动画

transition标签在入场和出场时会自动向外触发事件,外部可通过对这些事件的监听来执行对应的回调

事件名 描述 回调 描述
before-enter 入场动画开始前 callback(el) el是要执行动画的DON元素
enter 入场动画 callback(el,done) el是要执行动画的DON元素,done是用来告诉Vue动画结束的回调函数
after-enter 入场动画结束 callback(el) el是要执行动画的DON元素
leave-enter 出场动画开始前 callback(el) el是要执行动画的DON元素
leave 出场动画 callback(el,done) el是要执行动画的DON元素,done是用来告诉Vue动画结束的回调函数
leave-enter 出场动画结束 callback(el) el是要执行动画的DON元素
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>hello world</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- CDN方式引入Vue -->
</head>

<body>
  <div id="app">
    <button @click="clickHandle">按钮</button>
      <transition
      @before-enter="beforeEnter"
      @enter="enter"
      @after-enter="afterEnter"
    
      @before-leave="beforeLeave"
      @leave="leave"
      @after-leave="afterLeave"
      >
        <h1 v-show="show">JS动画</h1>
      </transition>
  </div>
  <script>
    var app = new Vue({ //创建Vue实例
      el: "#app",
      data(){ return { show: true } },
      methods: {
        clickHandle(){ this.show = !this.show },

        beforeEnter(el){ console.log("beforeEnter"); },
        enter(el,done){ console.log("enter"); done() }, //若不调用done()方法,则afterEnter不会执行,因为Vue不知道何时动画结束
        afterEnter(el){ console.log("afterEnter"); },

        beforeLeave(el){ console.log("beforeLeave"); },
        leave(el,done){ console.log("leave"); done() }, //若不调用done()方法,则afterLeave不会执行,因为Vue不知道何时动画结束
        afterLeave(el){ console.log("afterLeave"); },
        }
    });
  </script>
</body>

</html>
velocity.js

enterleave事件绑定函数中使用velocity.js对元素做动画即可

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>hello world</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- CDN方式引入Vue -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
</head>

<body>
  <div id="app">
    <button @click="clickHandle">按钮</button>
      <transition
      @enter="enter"
      @leave="leave"
      >
        <h1 v-show="show">JS动画</h1>
      </transition>
  </div>
  <script>
    var app = new Vue({ //创建Vue实例
      el: "#app",
      data(){ return { show: true } },
      methods: {
          clickHandle(){ this.show = !this.show },

          enter(el, done){ 
            Velocity(el, { opacity: 1 }, { duration: 1000, complete: done });
            // Velocity.js会再结束时自动执行done()函数
          },

          leave(el, done){
            Velocity(el, { opacity: 0 }, { duration: 1000, complete: done });
            // Velocity.js会再结束时自动执行done()函数
          }
        }
    });
  </script>
</body>

</html>

多元素/组件动画

多元素切换

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>hello world</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- CDN方式引入Vue -->
  <style>
    .v-enter,
    .v-leave-to{
      opacity: 0;
    }
    .v-enter-active,
    .v-leave-active{
      transition: all 1s;
    }
  </style>
</head>
<body>
  <div id="app">
    <h2>
      transition组件中只能有一个DOM元素,若有多个元素则必须使用v-if或动态组件显示一个,v-show却不行<br>
      Vue的v-if、v-else-if和v-else会经可能的复用DOM,所以不会有动画效果,可以为DOM增加一个key值得以解决<br>
      可以为transition增加一个mode属性,该属性值可选 in-out 和 out-in 两种效果
    </h2>
    <button @click="clickHandle">按钮</button>
      <transition mode="in-out">
        <h1 v-if="show" key="one">one</h1>
        <h1 v-else key="two">two</h1>
      </transition>
  </div>
  <script>
    var app = new Vue({ //创建Vue实例
      el: "#app",
      data(){ return { show: true } },
      methods: { clickHandle(){ this.show = !this.show } }
    });
  </script>
</body>

</html>

列表动画

对列表渲染的元素进行动画,使用transition-group包裹列表元素即可,用法与transition一致,该标签的实质是为每一个列表项添加一个transition标签

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>hello world</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- CDN方式引入Vue -->
  <style>
    .v-enter,
    .v-leave-to{
      opacity: 0;
    }
    .v-enter-active,
    .v-leave-active{
      transition: all 1s;
    }
  </style>
</head>
<body>
  <div id="app">
    <button @click="pushHandle">push</button>
    <button @click="popHandle">pop</button>
    <ul>
      <transition-group>
        <li v-for="item in array" :key="item">{{item}}</li>
      </transition-group>
    </ul>
  </div>
  <script>
    var app = new Vue({ //创建Vue实例
      el: "#app",
      data(){ return { array: [] } },
      methods: {
        pushHandle(){ this.array.push(this.array.length) },
        popHandle(){ this.array.pop() }
      }
    });
  </script>
</body>

</html>
此作者没有提供个人介绍
最后更新于 2022-01-31