继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

深入理解 Vuejs 动画效果

慕标5832272
关注TA
已关注
手记 1229
粉丝 229
获赞 1001

Vue 中的 CSS 动画原理

将标签外部添加 transition 标签,将其包裹起来。他的原理图如下,即当一个元素被transition 包裹之后,Vue 会自动分析元素的 CSS 样式,然后构建一个动画流程。

下面示例图中的线和点,就可以称之为一个动画流程。Vue 会在动画即将执行的瞬间,往内部被包裹的的 div 上增添两个 class 名,分别是 fade-enterfade-enter-active 。当动画第一帧执行结束之后;Vue 会在动画执行到第二帧的时候,把之前添加的 fade-enter 这个 class 去除,然后再增加一个 fade-enter-toclass 名;接着动画继续执行,执行到结束的瞬间,Vue 会把之前添加的 fade-enter-activefade-enter-to 两个 class 都去除掉。

webp

当动画从显示状态变为隐藏状态时,原理图如下,流程跟上相似:

webp

Vue 过渡动画案例代码

<!DOCTYPE html><html lang="en"><head>
  <meta charset="UTF-8">
  <title>Vue中的css动画原理</title>
  <script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script>
  <style>
    .fade-enter {      opacity: 0;
    }    .fade-enter-active {      transition: opacity 2s;
    }    .fade-leave-to {      opacity: 0;
    }    .fade-leave-active {      transition: opacity 2s;
    }  </style></head><body>

  <div id="app">
    <transition name="fade">
      <div v-if="show">
        hello world      </div>
    </transition>

    <button @click="handleClick">切换</button>
  </div>

  <script>

    var vm = new Vue({
      el: "#app",
      data: {
        show: true
      },
      methods: {
        handleClick: function(){          this.show = ! this.show
        }
      }
    })  </script></body></html>

JSbin 预览


因为 transition 上设置的 name 属性名为 fade。所以 style 中 CSS 样式为 fade 开头。如果 transition 上没有设置 name 属性名,那么style 中 CSS 样式为 v 开头,即 v-enterv-center-active 等。

Vue 中使用 CCS3 @keyframes 动画

<!DOCTYPE html><html lang="en"><head>
  <meta charset="UTF-8">
  <title> keyframes 动画 </title>
  <script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script>
  <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></head><body>

  <div id="app">
    <transition name="fade">
      <div v-if="show">
        hello world      </div>
    </transition>

    <button @click="handleClick">切换</button>
  </div>

  <script>

    var vm = new Vue({
      el: "#app",
      data: {
        show: true
      },
      methods: {
        handleClick: function(){          this.show = ! this.show
        }
      }
    })  </script></body></html>

JSbin 预览

自定义

如果 CSS 样式没有进行这种方式命名,而是我们通过自定义的方式命名的,如下:

    .active {      transform-origin: left center;      animation: bounce-in 1s;
    }    .leave {      transform-origin: left center;      animation: bounce-in 1s reverse;
    }

那么在 transition 标签里面就要对这个自定义的 class 进行声明。

    <transition name="fade"
                enter-active-class="active"
                leave-active-class="leave"
      >
      <div v-if="show">
        hello world      </div>
    </transition>


Animate.css 库

Animate.css库官网 提供了众多 CSS 效果。引入和使用的原理和 iconfont 类似。

  • 下载该库之后,在 link 标签下引入。

  <link rel="stylesheet" type="text/css" href="./animate.css">
  • 然后在 transition 标签中定义 enter-active-classleave-active-classanimate 库中相应的样式。下面示例即是入场动画使用 swing,出场动画使用 shake

    <transition name="fade"
                enter-active-class="animated swing"
                leave-active-class="animated shake"
    >
      <div v-if="show">
        hello world      </div>
    </transition>

JSbin 预览

值得注意的是,当引入并使用 Animate.css 库时,必须使用自定义 class 名的形式使用 Animate.css。同时,class 当中必须包含一个 animated ,然后再将相应的效果添加到 animated 之后。

appear

上面一节的示例中,当我们在页面刚刚刷新时(第一次元素显示时)也加上一些动画效果,则需要加上 appearappear-active-class

    <transition name="fade"
                appear
                enter-active-class="animated swing"
                leave-active-class="animated shake"
                appear-active-class="animated swing"
    >
      <div v-if="show">
        hello world      </div>
    </transition>

JSbin 预览

同时使用过渡和动画

之前提到的 Animate.css 库 提供的动画是 @keyframes 类型 CSS3 的动画。假如我们希望动画不仅仅只有 @keyframes 的效果,还另外有过渡的动画效果时。这个时候我们可以这样进行代码的编写。

即在 animatedclass 之后再添加 过渡动画的 CSS class

    .fade-enter,    .fade-leave-to {      opacity: 0;
    }    .fade-enter-active,    .fade-leave-active {      transition: opacity 3s;
    }
    <transition
                type="transition"
                name="fade"
                appear
                enter-active-class="animated swing fade-enter-active"
                leave-active-class="animated shake fade-leave-active"
                appear-active-class="animated swing"
    >
      <div v-if="show">
        hello world      </div>
    </transition>

JSbin 预览

动画执行时长: 值得注意的是,animate 之中的动画执行是 1s,当过渡动画超过 1s 时,在 transition 里面添加属性 type ,就会以 transition 里面动画的时长为动画执行时长。同样的,这个执行时长也可以自定义,通过 :duration 属性来进行设置,例如当属性被设置为 :duration="10000" ,即时长为 10s。除此之外,还可以单独设置出场、入场动画为不同的时长,:duration="{ enter: 5000, leave: 10000 }"


Vue 中的 JS 动画

动画钩子

before-enter

before-enter 会接收到一个参数 el ,即指的是动画 transition 包裹的标签。

  <div id="app">
    <transition name="fade" @before-enter="handleBeforeEnter">
      <div v-show="show">
        hello world      </div>
    </transition>

    <button @click="handleClick">切换</button>
  </div>
    var vm = new Vue({      el: "#app",      data: {        show: true
      },      methods: {        handleClick: function(){          this.show = ! this.show
        },        // 接收到一个参数 el  代指被包裹的标签 
        handleBeforeEnter: function(el){
          el.style.color = 'red'
        }
      }
    })


enter

enter 会接收两个参数,一个为 el,指的仍然是动画 transition 包裹的标签。 一个为 done,是一个回调函数。

  <div id="app">
    <transition name="fade" @before-enter="handleBeforeEnter" @enter="handleEnter">
      <div v-show="show">
        hello world      </div>
    </transition>

    <button @click="handleClick">切换</button>
  </div>
    var vm = new Vue({      el: "#app",      data: {        show: true
      },      methods: {        handleClick: function(){          this.show = ! this.show
        },        handleBeforeEnter: function(el){
          el.style.color = 'red'
        },        handleEnter: function(el, done){
          setTimeout(() => {
            el.style.color = 'green'
            done()
          },2000)
        }
      }
    })

上面 handleEnter 中的 setTimeout 执行完之后,调用了 done()。而当done() 被调用的时候,Vue 又会触发一个 after-enter 事件。

after-enter

after-enter 也要接收到参数 el

  <div id="app">
    <transition name="fade" 
                @before-enter="handleBeforeEnter" 
                @enter="handleEnter"
                @after-enter="handleAfterEnter"
      >
      <div v-show="show">
        hello world      </div>
    </transition>

    <button @click="handleClick">切换</button>
  </div>
    var vm = new Vue({      el: "#app",      data: {        show: true
      },      methods: {        handleClick: function(){          this.show = ! this.show
        },        handleBeforeEnter: function(el){
          el.style.color = 'red'
        },        handleEnter: function(el, done){
          setTimeout(() => {            // 2s 之后改变颜色
            el.style.color = 'green'
          },2000)

          setTimeout(() => {            // 4s 之后 done()
            done()
          },4000)
        },        handleAfterEnter: function(el){
          el.style.color = "#000"
        }
      }
    })


出场动画钩子

相应的。出场动画的钩子函数为 before-leaveleaveafter-leave 。用法与上面所讲的入场动画钩子函数相似。

动画钩子示例

JSbin 预览

velocity.js 动画库

velocityjs 官网 下载 velocity.js 文件。并通过 script 标签引入 velocity.js

按照下面的写法,将 el{opacity: 1}{duration: 1000, complete: done} 当做参数传递给 Velocity

    var vm = new Vue({      el: "#app",      data: {        show: true
      },      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})
        },        handleAfterEnter: function(el){
          alert('动画结束')
        }
      }
    })

JSbin 预览

多个元素与组件的过渡动画

多个元素间过渡动画

在下面的示例中,之所以加上 key 值,是为了让 Vue 不去复用 DOM,达到我们想要的效果。给 transition 添加 mode 属性,out-inin-out 分别表示多个属性切换时候的不同的出场、入场顺序效果。

webp

JSbin 预览

多个组件间过渡动画

在下面的示例中,两个组件通过 button 点击之后触发的事件,进行内容的显示和隐藏的切换。

    .fade-enter,    .fade-leave-to {      opacity: 0;
    }    .fade-enter-active,    .fade-leave-active {      transition: opacity 1s;
    }
  <div id="app">    <transition mode="out-in" name="fade">
      <child v-if="show"></child>
      <child-one v-else></child-one>
    </transition>

    <button @click="handleClick">切换</button>
  </div>
    Vue.component('child',{      template: '<div>child</div>'
    })

    Vue.component('child-one',{      template: '<div>child-one</div>'
    })    var vm = new Vue({      el: "#app",      data: {        show: true
      },      methods: {        handleClick: function(){          this.show = ! this.show
        }
      }
    })

JSbin 预览

动态组件

除此之外也可以参考之前 深入理解 Vuejs 组件 中动态组件的方式。给 component 外边的 transition 添加 mode

JSbin 预览

列表过渡

参照下面 JSbin 中的示例,构造了一段代码,简单的实现了一个点击 button 按钮添加列表展示数据的 demo。现在我们要针对一整个列表,在增加或者删除的时候实现过渡效果。这里就需要一个新的标签 transition-group

webp

添加 transition-group 等同于给每一个 div 之外添加 transition。相当于把列表的过渡转化成单个元素标签的过渡。

除此之外跟前几节的过渡动画一样,需要在 style 中添加相应的样式。

JSbin 预览

动画封装

当需要频繁使用一个动画效果的时候,我们将动画封装到一个组件之中是很好的方法。结合之前的动画钩子,可以实现将模板、样式都封装到组件的效果。当需要使用的时候,直接使用该组件模板标签,并添加相应的 show 属性即可。

  <div id="app">
    <fade :show="show">
      <div>hello world</div>
    </fade>

    <fade :show="show">
      <h1>hello world</h1>
    </fade>

    <button @click="handleClick">toggle</button>
  </div>
    // 封装 fade 子组件
    Vue.component('fade',{      props: ['show'],     // 接收父组件传递过来的 show 参数
      // template 模板,并使用动画钩子将样式封装在函数中
      template: `           
        <transition @before-enter="handleBeforeEnter"
                    @enter="handleEnter"
                    @after-enter="handleAfterEnter">
          <slot v-if="show"></slot>
        </transition>
      `,     
      methods: {        handleBeforeEnter: function(el){
          el.style.color = 'red'
        },        handleEnter: function(el,done){
          setTimeout(() => {
            el.style.color = 'green'
          },2000)

          setTimeout(() => {
            done()
          },4000)
        },        handleAfterEnter: function(el){
          el.style.color = "#000"
        }
      }
    })    var vm = new Vue({      el: "#app",      data: {        show: true
      },      methods: {        handleClick: function(){          this.show = ! this.show
        }
      }
    })

JSbin 预览



作者:evenyao
链接:https://www.jianshu.com/p/0d690ee15406


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP