bluezhan / vue2

【🔥Vue.js资讯📚】目前web前端开发非常火爆的框架;定时更新,欢迎 Star 一下。
https://itemsets.github.io/vue2
MIT License
444 stars 117 forks source link

关于Vue2.0的过渡效果与过渡状态 #2

Open bluezhan opened 7 years ago

bluezhan commented 7 years ago

前言

因为是MVVM模式,加上又是单页面应用,会考虑到页面的切换过渡效果和各种组件、控件、插件的界面动态切换效果。固然就会在这一块加入概念和处理方式。

大概的处理方式就是:

看一下官方过渡效果

通过 Vue 2.0 的过渡系统, 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。 包括以下工具:

单元素/组件的过渡

贴个例子:

<div id="demo">
  <button v-on:click="show = !show">
    点击我切换(Toggle)
  </button>
  <transition name="fade">
    <p v-if="show">我就是个动画</p>
  </transition>
</div>
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s
}
.fade-enter, .fade-leave-active {
  opacity: 0
}
new Vue({
  el: '#demo',
  data: {
    show: true
  }
})

在上面的案例,会发现:有个 transition 的封装元素,而且还会发生CSS的类的命名格式。

Vue 2.0 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加 entering/leaving 过渡

在 transition 的封装元素里有个name属性并赋了值 fade ;上面说得很明白了,可以给任何元素和组件添加 entering/leaving 过渡。这个时候去瞄一下CSS的类命名就完全明白了。

本来这里作者是想封装个基本动画的;最后是没必要的,所以需要自己添加,也可以引入动画库和插件。

这里应该还涉及到 transition 的封装组件的状态和处理机制,这才是好玩的东西,也是个重点。下面讲到,点击我吧。

我们先来看一段Vue2.0源码:

// 这是切换CSS的类命名
var autoCssTransition = cached(function (name) {
  return {
    enterClass: (name + "-enter"),
    leaveClass: (name + "-leave"),
    appearClass: (name + "-enter"),
    enterActiveClass: (name + "-enter-active"),
    leaveActiveClass: (name + "-leave-active"),
    appearActiveClass: (name + "-enter-active")
  }
});
  // 开始 enter 的 transition 
  beforeEnterHook && beforeEnterHook(el);
  if (expectsCSS) {
    addTransitionClass(el, startClass);
    addTransitionClass(el, activeClass);
    nextFrame(function () {
      removeTransitionClass(el, startClass);
      if (!cb.cancelled && !userWantsControl) {
        whenTransitionEnds(el, type, cb);
      }
    });
  }
 // 触发 leave 的 transition 
  if (expectsCSS) {
      addTransitionClass(el, leaveClass);
      addTransitionClass(el, leaveActiveClass);
      nextFrame(function () {
        removeTransitionClass(el, leaveClass);
        if (!cb.cancelled && !userWantsControl) {
          whenTransitionEnds(el, type, cb);
        }
      });
    }

从上面看出来添加了startClass接着就是删除了它,初始化元素的状态并集合 transition 的封装组件的状态和处理机制。

看官方解析:

元素封装成过渡组件之后,在遇到插入或删除时,Vue 2.0 将

过渡的-CSS-类名

会有 4 个(CSS)类名在 enter/leave 的过渡中切换

transition

对于这些在 enter/leave 过渡中切换的类名,v- 是这些类名的前缀。使用 <name="my-transition>" 可以重置前缀,比如 v-enter 替换为 my-transition-enter

v-enter-activev-leave-active 可以控制 进入/离开 过渡的不同阶段,在下面章节会有个示例说明。

不过看起来是很复杂的,我就简单说上几句:

  • v-enter: 就是元素插入时的初始化状态,自己爱咋样定义就咋样定义,不过在下一个帧移除。
  • v-enter-active: 就是和v-enter在下一行代码插入的,不过它是在 transition/animation 完成之后移除的。
  • v-leave: 被触发离开时生效,在下一个帧移除。基本这个鬼是用不到的。
  • v-leave-active: 就是和v-leave在下一行代码插入的,在 transition/animation完成之后移除。

其实如果感觉到很困惑的话,一定是对DOM插入状态和CSS3.0动画的理解不彻底。

有时候去看看源码就很明白很清楚了

bluezhan commented 7 years ago

添加CSS 3.0 动画

在上面的例子里什么都没变就是修改的样式的调用,改用了CSS3.0的 animation 动画。

.bounce-enter-active {  animation: bounce-in .5s; }
.bounce-leave-active {  animation: bounce-out .5s; }
@keyframes bounce-in {
  0% {  transform: scale(0); }
  50% {  transform: scale(1.5); }
  100% {  transform: scale(1); }
}
@keyframes bounce-out {
  0% {  transform: scale(1); }
  50% {  transform: scale(1.5); }
  100% {  transform: scale(0); }
}

自定义过渡类名

我们可以通过以下特性来自定义过渡类名:

 <transition
    name="custom-classes-transition"
    enter-active-class="animated tada"
    leave-active-class="animated bounceOutRight"
  >
    <p v-if="show">hello</p>
  </transition>

同时使用 Transitions 和 Animations

Vue 2.0 为了知道过渡的完成,必须设置相应的事件监听器。它可以是transitionendanimationend ,这取决于给元素应用的 CSS 规则。如果你使用其中任何一种,Vue 2.0 能自动识别类型并设置监听。

但是,在一些场景中,你需要给同一个元素同时设置两种过渡动效,比如 animation 很快的被触发并完成了,而transition 效果还没结束。在这种情况中,你就需要使用 type特性并设置 animationtransition 来明确声明你需要 Vue 2.0 监听的类型。

官方没有给出例子,而且不一目了然。

给同一个元素同时设置两种过渡动效animationtransition ;它们的是同时执行的。

    .fade-enter-active ,
    .fade-leave-active {
        animation: bounce-in 1.5s;
        transition: opacity .5s;
    }
   <transition name="fade" type="animation">
         <p v-if="show">我就是个动画</p>
   </transition>

看到没,就是transition的属性type处理了。

bluezhan commented 7 years ago

JavaScript 钩子

所谓JavaScript 钩子,就是开放过渡效果接口;可以在属性中声明 JavaScript 钩子。

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"
  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>
methods: {
  // --------
  // 进入中
  // --------
  beforeEnter: function (el) {/*...*/ },
  // 此回调函数是可选项的设置
  // 与 CSS 结合时使用
  enter: function (el, done) {
    /*...*/
    done()
  },
  afterEnter: function (el) {/*...*/},
  enterCancelled: function (el) {/*...*/},
  // --------
  // 离开时
  // --------
  beforeLeave: function (el) {/*...*/},
  // 此回调函数是可选项的设置
  // 与 CSS 结合时使用
  leave: function (el, done) {
    /*...*/
    done()
  },
  afterLeave: function (el) {/*...*/},
  // leaveCancelled 只用于 v-show 中
  leaveCancelled: function (el) {/*...*/}
}

当只用 JavaScript 过渡的时候, 在 enter 和 leave 中,回调函数 done 是必须的 。 否则,它们会被同步调用,过渡会立即完成。

推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css="false",Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。

这里引进了 Velocity.js What is Velocity.js?

Velocity专为动画而设计 ,简单易用,功能强大,广泛地被一些主流公司所使用(包括Tumblr, Microsoft and WhatsApp)。并且Velocity 是基于MIT许可协议的开源库。

Velocity模仿了jQuery的语法,可以完美地同jQuery协作,当然也能独立地使用,所以对你来说应该很容易学。由于jQuery使用普遍,我也将向你展示Velocity如何同它协作。

Note: 为了提高你所有动画的性能,只需要简单地将目前jQuery的animate()函数调用换成velocity(),因为Velocity将原来jQueryanimate()函数的语法和功能在velocity()函数内部都做了解释映射,所以能兼容以前animate()的使用方式(velocity()还扩展了animate()的功能)。但即使是这样的一个小改变,也能使你的网站有一个显著的性能提升。

<!--
Velocity works very much like jQuery.animate and is
a great option for JavaScript animations
-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<div id="example-4">
  <button @click="show = !show">
    Toggle
  </button>
  <transition
    v-on:before-enter="beforeEnter"
    v-on:enter="enter"
    v-on:leave="leave"
    v-bind:css="false"
  >
    <p v-if="show">
      Demo
    </p>
  </transition>
</div>
new Vue({
  el: '#example-4',
  data: {
    show: false
  },
  methods: {
    beforeEnter: function (el) {
      el.style.opacity = 0
    },
    enter: function (el, done) {
      Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 })
      Velocity(el, { fontSize: '1em' }, { complete: done })
    },
    leave: function (el, done) {
      Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 })
      Velocity(el, { rotateZ: '100deg' }, { loop: 2 })
      Velocity(el, {
        rotateZ: '45deg',
        translateY: '30px',
        translateX: '30px',
        opacity: 0
      }, { complete: done })
    }
  }
})
bluezhan commented 7 years ago

初始渲染的过渡 - appear 特性

可以通过 appear 特性设置节点的在初始渲染的过渡。 这里默认和进入和离开过渡一样,同样也可以自定义 CSS 类名。

<transition
  appear
  appear-class="custom-appear-class"
  appear-active-class="custom-appear-active-class"
>
  <!-- ... -->
</transition>
<transition
  appear
  v-on:before-appear="customBeforeAppearHook"
  v-on:appear="customAppearHook"
  v-on:after-appear="customAfterAppearHook"
>
  <!-- ... -->
</transition>

多个元素的过渡 - 元素切换 key 特性

 <!-- v-if / v-else -->
<transition>
  <table v-if="items.length > 0">
    <!-- ... -->
  </table>
  <p v-else>Sorry, no items found.</p>
</transition>
<!-- key -->
<transition>
  <button v-bind:key="docState">
    {{ buttonMessage }}
  </button>
</transition>
// ... key 的处理
computed: {
  buttonMessage: function () {
    switch (docState) {
      case 'saved': return 'Edit'
      case 'edited': return 'Save'
      case 'editing': return 'Cancel'
    }
  }
}

过渡模式 - in-out和out-in

<transition name="fade" mode="out-in">
     <button v-if="flag" key="save" v-on:click="flag = !flag">save</button>
   <button v-else key="edit" v-on:click="flag = !flag">edit</button>
 </transition>

多个组件的过渡

多个组件的过渡很简单很多 - 我们不需要使用 key 特性。相反,我们只需要使用动态组件:

<transition name="component-fade" mode="out-in">
  <component v-bind:is="view"></component>
</transition>
new Vue({
  el: '#transition-components-demo',
  data: {
    view: 'v-a'
  },
  components: {
    'v-a': {
      template: '<div>Component A</div>'
    },
    'v-b': {
      template: '<div>Component B</div>'
    }
  }
})
bluezhan commented 7 years ago

过渡状态

Vue 的过渡系统提供了非常多简单的方法设置进入、离开和列表的动效。那么对于数据元素本身的动效呢,比如:

所有的原始数字都被事先存储起来,可以直接转换到数字。做到这一步,我们就可以结合 Vue 的响应式和组件系统,使用第三方库来实现切换元素的过渡状态。