zoukankan      html  css  js  c++  java
  • 深入理解 Vuejs 动画效果

    本文主要归纳在 Vuejs 学习过程中对于 Vuejs 动画效果的各个相关要点。由于本人水平有限,如文中出现错误请多多包涵并指正,感谢。如果需要看更清晰的代码高亮,请跳转至我的个人站点的 深入理解 Vuejs 动画效果 查看本文。

    Vue 中的 CSS 动画原理

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

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

     

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

     

    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-class 与 leave-active-class 为 animate 库中相应的样式。下面示例即是入场动画使用 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

    上面一节的示例中,当我们在页面刚刚刷新时(第一次元素显示时)也加上一些动画效果,则需要加上 appear 和 appear-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 的效果,还另外有过渡的动画效果时。这个时候我们可以这样进行代码的编写。

    即在 animated 的 class 之后再添加 过渡动画的 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-leave 、leave 和 after-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-in 、in-out 分别表示多个属性切换时候的不同的出场、入场顺序效果。

      <div id="app">
        <transition mode="out-in" name="fade">
          <div v-if="show" key="hello">hello world</div>
          <div v-else key="bye">Bye World</div>
        </transition>
    
        <button @click="handleClick">切换</button>
      </div>
    

    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

     

    添加 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 预览

  • 相关阅读:
    PowerShell 学习(一):运算符
    Create word clouds with Wordle
    淘宝惊现“同店购”?
    “二叉查找树”学习
    云计算软件之——OpenNebula
    "栈"应用——求解迷宫
    "队列"学习
    “串”学习——三种表示方法
    尖端技术104之计算机技术的未来
    “二叉树”——链表表示
  • 原文地址:https://www.cnblogs.com/evenyao/p/9643171.html
Copyright © 2011-2022 走看看