vue中动画

185 阅读7分钟

css动画

transition 过渡动画

<!DOCTYPE html>
<html lang="en">
<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>vue中的css动画原理</title>
  <script src="../vue.js"></script>
  <style>
    .fade-enter,
    .fade-leave-to {
      opacity: 0;
    }
    .fade-enter-active, 
    .fade-leave-active {
      transition: opacity 1s;
    }
  </style>
</head>

<body>
  <div id="root">
    <!-- transition标签包裹 实现组件过渡动画效果 -->
    <transition name="fade">
      <!-- <child v-if="show"></child> -->
      <child v-show="show"></child>
    </transition>
    <button @click="change">toggle</button>
  </div>

  <script>
    Vue.component("child", {
      template: `<div>child</div>`
    })
    var vm = new Vue({
      el: "#root",
      data: {
        show: true
      },
      methods: {
        change: function() {
          this.show = !this.show
        }
      }
    })
  </script>
</body>
</html>

通过@keyframes实现

 <style>
    @keyframes bounce-in {
      0% {
        transform: scale(0);
      }
      50% {
        transform: scale(1.5);
      }
      100% {
        transform: scale(1);
      }
    }
    .fade-enter-active{
      transform-origin: left center;
      animation: bounce-in 1s;
    }
    .fade-leave-active {
      transform-origin: left center;
      animation: bounce-in 1s reverse;
    }
  </style>

animate.css库

通过animate.css库 取代@keyframes

  1. animate.css官网 daneden.github.io/animate.css… npm install animate.css --save安装
  2. 头部引入 animate.css库 或
  3. 注意:需要使用自定义class名使用动画,如 enter-active-class="animated swing" 其中'animated'为必须,后面跟要实现的动画效果名

<body>
  <div id="root">
    <!-- transition标签包裹 实现组件过渡动画效果 -->
    <transition name="fade" enter-active-class="animated swing" 
    leave-active-class="animated shake">
      <!-- <child v-if="show"></child> -->
      <child v-show="show"></child>
    </transition>
    <button @click="change">toggle</button>
  </div>

  <script>
    Vue.component("child", {
      template: `<div>child</div>`
    })
    var vm = new Vue({
      el: "#root",
      data: {
        show: true
      },
      methods: {
        change: function () {
          this.show = !this.show
        }
      }
    })
  </script>
</body>

vue中同时使用过渡和动画

  1. 解决上面代码第一次显示没有动画的问题:transition标签加上自定义入场动画名appear。
  2. 同时实现动画和过渡效果:由于animate.css给定的动画时长是1s,opacity时长是3s,需要设置type="opacity",来使得动画播放时长以opacity时长3s为准。
    还需style标签中加入以下样式
.fade-enter, .fade-leave-to {
  opacity: 0;
}
.fade-enter-active, .fade-leave-active {
  transition: opacity 3s;
}
  1. 还可自定义动画播放时长:transition标签加上:duration属性(:duration="{enter:2000, leave: 5000}")入场时间为2s,隐藏时间为3s

js动画

vue中的js动画与velocity.js的结合

  1. 动画钩子@before-enter="handleBeforeEnter",handleBeforeEnter会在el显示前的一瞬间触发。
<body>
  <div id="root">
    <transition name="fade" @before-enter="handleBeforeEnter">
      <div v-show="show">hello world</div>
    </transition>
    <button @click="handleClick">toggle</button>
  </div>
  <script>
    var vm = new Vue({
      el: "#root",
      data: {
        show: true
      },
      methods: {
        handleClick: function() {
          this.show = !this.show
        },
        handleBeforeEnter: function(el) { // handleBeforeEnter 会在el(这里指div)显示前的一瞬间触发
          // console.log('handleBeforeEnter');
          el.style.color = "red"
        }
      }
    })
  </script>
</body>
  1. 动画钩子 @enter="handleEnter",函数handleEnter(el,done),动画开始时执行,接收两个参数,el和回调函数。
<body>
  <div id="root">
    <transition name="fade" @before-enter="handleBeforeEnter" @enter="handleEnter">
      <div v-show="show">hello world</div>
    </transition>
    <button @click="handleClick">toggle</button>
  </div>
  <script>
    var vm = new Vue({
      el: "#root",
      data: {
        show: false
      },
      methods: {
        handleClick: function() {
          this.show = !this.show
        },
        handleBeforeEnter: function(el) { // handleBeforeEnter 会在el(这里指div)显示前的一瞬间触发
          // console.log('handleBeforeEnter');
          el.style.color = "red"
        },
        handleEnter: function(el, done) {
          setTimeout(() => {
            el.style.color = "green" // el先是显示红色,2s后变为绿色
            done();  // 调用done,表示动画执行完毕
          },2000);
        }
      }
    })
  </script>
</body>
  1. 动画2中的done() 执行完毕后,紧接着是 动画钩子 @after-enter="handleAfterEnter" ,handleAfterEnter(el)接收一个参数el。
<body>
  <div id="root">
    <transition name="fade" @before-enter="handleBeforeEnter" 
    @enter="handleEnter" @after-enter="handleAfterEnter">
      <div v-show="show">hello world</div>
    </transition>
    <button @click="handleClick">toggle</button>
  </div>
  <script>
    var vm = new Vue({
      el: "#root",
      data: {
        show: false
      },
      methods: {
        handleClick: function() {
          this.show = !this.show
        },
        handleBeforeEnter: function(el) { // handleBeforeEnter 会在el(这里指div)显示前的一瞬间触发
          // console.log('handleBeforeEnter');
          el.style.color = "red"
        },
        handleEnter: function(el, done) {
          setTimeout(() => {
            el.style.color = "green" // el先是显示红色,2s后变为绿色
          },2000);
          setTimeout(() => {
            done()  // 4s的时候绿色执行完
          },4000);
        },
        handleAfterEnter: function(el) { // done() 执行完毕后后执行
          el.style.color = "#000"  // el开始显示红色,2s后变为绿色,再过2s后变为黑色
        }
      }
    })
  </script>
</body>
  1. 离开的动画钩子,@before-leave @leave @after-leave与enter进入的动画钩子同理,用法一致。

velocity.js 需要引入velocity.js, 用法简单,简单的代码可以完成复杂动画效果。

<!DOCTYPE html>
<html lang="en">
<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>vue中的js动画与velocity.js的结合</title>
  <script src="../vue.js"></script>
  <script src="./velocity.js"></script>
</head>
<body>
  <div id="root">
    <transition name="fade" @before-enter="handleBeforeEnter" @enter="handleEnter" @after-enter="handleAfterEnter">
      <div v-show="show">hello world</div>
    </transition>
    <button @click="handleClick">toggle</button>
  </div>
  <script>
    var vm = new Vue({
      el: "#root",
      data: {
        show: false
      },
      methods: {
        handleClick: function () {
          this.show = !this.show
        },
        handleBeforeEnter: function (el) { 
          el.style.opacity = 0
        },
        handleEnter: function (el, done) {
          Velocity(el, {opacity:1}, {duration: 1000, complete: done})
          // opacity 由0到1,过渡时间1s,动画执行完done告知,然后控制台打印‘动画执行完毕’
        },
        handleAfterEnter: function (el) { 
          console.log('动画执行完毕');
        }
      }
    })
  </script>
</body>
</html>

多个元素或组件的过渡

多个元素过渡动画

<!DOCTYPE html>
<html lang="en">
<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>
  <script src="../vue.js"></script>
  <style>
    .v-enter, .v-leave-to {
      opacity: 0;
    }
    .v-enter-active, .v-leave-active {
      transition: opacity 1s;
    }
  </style>
</head>

<body>
  <div id="root">
    <!-- mode="out-in" 控制两个div显示隐藏顺序,out-in表示一个隐藏后另一个再显示。反之in-out同理 -->
    <transition mode="out-in">
      <div v-if="show" key="hello">hello world</div>
      <div v-else key="bye">bye</div>
    </transition>
    <button @click="handleClick">toggle</button>
  </div>
  <script>
    var vm = new Vue({
      el: "#root",
      data: {
        show: true
      },
      methods: {
        handleClick: function () {
          this.show = !this.show
        }
      }
    })
  </script>
</body>
</html>

多个组件过渡动画

借助component动态组件来实现两个组件的切换,

<!DOCTYPE html>
<html lang="en">
<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>
  <script src="../vue.js"></script>
  <style>
    .v-enter, .v-leave-to {
      opacity: 0;
    }
    .v-enter-active, .v-leave-active {
      transition: opacity 1s;
    }
  </style>
</head>

<body>
  <div id="root">
    <!-- mode="out-in" 控制两个div显示隐藏顺序,out-in表示一个隐藏后另一个再显示。反之in-out同理 -->
    <transition mode="out-in">
      <component :is=type></component>
    </transition>
    <button @click="handleClick">toggle</button>
  </div>
  <script>
    Vue.component('child-one', {
      template:"<div>child-one</div>"
    })
    Vue.component('child-two', {
      template: "<div>child-two</div>"
    })
    var vm = new Vue({
      el: "#root",
      data: {
        type: 'child-one'
      },
      methods: {
        handleClick: function () {
          // this.show = !this.show
          this.type = this.type === 'child-one' ? 'child-two' : 'child-one'
          // 如果显示的组件是child-one组件,就切换成child-two组件,否则切换child-one组件
        }
      }
    })
  </script>
</body>
</html>

vue中的列表过渡

只需在想要设定动画效果的元素外层包裹一层transition-group标签即可,然后需要设置style样式,才会有过渡动画效果。

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

<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>
  <script src="../vue.js"></script>
  <style>
    .v-enter,
    .v-leave-to {
      opacity: 0;
    }

    .v-enter-active,
    .v-leave-active {
      transition: opacity 1s;
    }
  </style>
</head>

<body>
  <div id="root">
    <transition-group>
      <div v-for="item of List" :key="item.id">{{item.title}}</div>
    </transition-group>
    <button @click="handleClick">Add</button>
  </div>
  <script>
    // 点击add按钮 实现增加页面数据效果
    var count = 0;
    var vm = new Vue({
      el: "#root",
      data: {
        List: []
      },
      methods: {
        handleClick: function () {
          this.List.push({
            id: count ++,
            title: "hello world"
          })
        }
      }
    })
  </script>
</body>
</html>

动画封装

可以将动画封装在一个组件,使用的时候,直接调用组件即可。

<body>
  <div id="root">
    <fade :show="show">
      <div>hello world</div>
    </fade>
    <fade :show="show">
      <h1>hello world</h1>
    </fade>
    <button @click="handleClick">toggle</button>
  </div>
  <script>
    Vue.component('fade', {
      props: ['show'],
      template: `
          <transition @befor-enter="handleBeforEnter" @enter="handleEnter">
            <slot v-if='show'></slot>
          </transition>`,
      methods: {
        handleBeforEnter: function(el) {
          el.style.color = "red"
        },
        handleEnter: function(el, done) {
          setTimeout(() => {
            el.style.color = "green";
            done()
          },2000);
        }
      }
    })
    var vm = new Vue({
      el: "#root",
      data: {
        show: false,
      },
      methods: {
        handleClick: function () {
          this.show = !this.show
        }
      }
    })
  </script>
</body>

这里将动画都写进''fade'组件,需要使用动画的时候,直接调用组件fade即可,十分方便。