Vue(八)-Vue动画效果-单组件

545 阅读8分钟

一、Vue控制动画的几种方法

1. css的transition

2. css的animation

3. js操作动画

二、单元素/组件的过渡

在讲Vue的动画前,先了解一下动画在vue中的存在时间

<div id="demo">
  <button v-on:click="show = !show">
    Toggle
  </button>
  <transition name="fade">
    <p v-if="show">hello</p>
  </transition>
</div>
new Vue({
  el: '#demo',
  data: {
    show: true
  }
})
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
  opacity: 0;
}

代码逻辑:

Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。

transition 组件中的DOM元素,在下列情形中,根据css类添加进入/离开过渡动画

  • 条件渲染 (使用 v-if)
  • 条件展示 (使用 v-show)
  • 动态组件
  • 组件根节点

三、过渡的类名(动画的生命周期)

在进入/离开的过渡中,会有 6 个 class 切换,分时间段添加到DOM元素上。

对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 <transition>,则 v- 是这些类名的默认前缀。如果你使用了 <transition name="my-transition">,那么 v-enter 会替换为 my-transition-enter。

v-enter-active和v-leave-active两个类可以在前面定义,过程时间,延迟和曲线函数。

v-enter表示dom元素进入动画第一帧的状态,之后变化到v-enter-to时的状态,再到dom元素正常时候的状态,接着到v-leave时的状态,再到v-leave-to时的状态,之后dom元素消失。

.fade-enter {  width: 100px;  background: red;}
.fade-enter-to {  width: 200px;  background: red;}
p {  background: red;  width: 500px;}
.fade-leave {  width: 200px;
  background: red;
}
.fade-leave-to {  background: red;  width: 100px;}
.fade-enter-active {  transition: all 3s;}
.fade-leave-active {  transition: all 3s;}

p元素出现的状态演示:

100px => 200px => 500px     //0直接变成100px,200px直接变成500px

p元素消失时的状态演示:

500px => 200px => 100px   //最后100px直接消失

一般不加v-enter-to和v-leave类,因为两个都应该是dom元素原本的模样

四、6个class的添加顺序

要理解动画的本质,就是把样式的改变加上时间

1. 先给dom元素加上v-enter和v-enter-active       //初始样式

2. 下一帧去掉v-enter,加上v-enter-to                //变化后的样式 

3. 过渡结束删掉v-enter-to和v-enter-active

4. 现在只剩下dom元素本身的样式

5. 加上v-leave和v-leave-active                          //由于动画本质是样式的改变,所以

6. 下一帧去掉v-leave加上v-leave-to                    //可以理解为dom原本的样式=>v-leave-t

7. 过渡结束删掉v-leave-to和v-leave-active           //o的样式

v-leave只存在一帧具体动画可以自己推断,如果原本的dom元素存在样式,一般直接忽略v-leave的样式,直接原本样式=>v-leave-to的样式,因为时间太短

五、Vue的animation用法

Vue的animation是依然使用transition来控制dom的动画效果

动画尽量写在active上,因为它全程都在

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

最后的100%尽量变成原来的模样,因为动画结束100%后,仍然需要恢复原来的模样,而此时v-enter-active类已经去掉了,所以会很快地从100%的样式变到原本样式。同理消失时也一样

我们可以使用第三方动画库来使用animation,不用写@语句了(animate.css)

  • enter-class
  • enter-active-class
  • enter-to-class (2.1.8+)
  • leave-class
  • leave-active-class
  • leave-to-class (2.1.8+)

来使用库

  <transition
    name="custom-classes-transition"
    enter-active-class="animated tada"
    leave-active-class="animated bounceOutRight"
  >

动画有两种实现方式:在transition上或者在css类上

transition上的优先级高于普通的类名,这对于 Vue 的过渡系统和其他第三方 CSS 动画库,如 Animate.css结合使用十分有用。

通常呢,animation是写在v-active类上的,因为active类始终存在

六、过渡和动画的区别

过渡就是从一个状态向另一个状态插入值。很简单。从起始状态,到结束状态

动画有点不同,你可以在一个声明中设置多个状态。比如,你可以在动画 50% 的位置设置一个关键帧,然后在 70% 的位置设置一个完全不同的状态

动画也可以实现过渡的功能,只需要从头到尾插入状态,但是过渡无法像动画一样插入多个值。

七、动画的js钩子

<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>

上面的事件就是js的钩子,之后要在method里面定义函数

  enter: function (el, done) {
    // ...
    done()
  },

当只用 JavaScript 过渡的时候,enterleave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。

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

原生js和库的用法如下:

    beforeEnter: function (el) {
      el.style.opacity = 0
      el.style.transformOrigin = 'left'
    },
    enter: function (el, done) {
      Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 })
      Velocity(el, { fontSize: '1em' }, { complete: done })
    },

八、钩子的done

没有调用done()的话,afterenter和afterleave的钩子函数不会调用。
然后你发现你的show变成了false以后,元素还不会消失,因为vue只有调用了afterleave后才会触发display:none把元素隐藏起来实现元素的v-show效果。如果你在leave中的钩子函数直接写displa:none会发现元素直接消失,因为这个属性没有过渡效果。

Vue有很多种,动画方式js或者css,使用js会让你摆脱css的限制,但是必须要加done(),这样vue才知道动画什么时候结束。

The moment you call done, Vue considers your transition over and transitions. Without calling it at all, Vue infers from the transition CSS property on your element that it is a 2s transition. This is why omitting done works.

你调用done的时刻,vue认为你的动画结束了,如果没有调用done,vue会从css里辨认出过渡的时间。

done在leave钩子上,那么done调用的时间就是leave类删掉样式属性的时间,不是过渡的时间,但是如果done调用的时间小于动画时间是不会有动画的(过渡完之后就会删掉相应属性)代码

参考链接

九、transition 实现

<transtion> 组件的实现是 export 出 一个对象,从这里我们能看出它会将预先设定好的 props 绑定到 transition 上,而后我们只需对其中的点进行输入即可得到对应的样式输出,具体如何进行的过程,就不需要我们去考虑了

export default {
  name: 'transition',
  props: transitionProps,
  abstract: true,
  render (h: Function) {
    // 具体 render 等会再看
  }
}

其中支持的 props 如下,你可以对 enterleave 的样式进行任意形式的重写

export const transitionProps = {
  name: String,
  appear: Boolean,
  css: Boolean,
  mode: String,
  type: String,
  enterClass: String,
  leaveClass: String,
  enterToClass: String,
  leaveToClass: String,
  enterActiveClass: String,
  leaveActiveClass: String,
  appearClass: String,
  appearActiveClass: String,
  appearToClass: String,
  duration: [Number, String, Object]
}
vue的大小写转化,由于xml无法区分大写,所以会自动转换为中划线

参考文章

Props:

  • name - string,用于自动生成 CSS 过渡类名。例如:name: 'fade' 将自动拓展为.fade-enter.fade-enter-active等。默认类名为 "v"
  • appear - boolean,是否在初始渲染时使用过渡。默认为 false
  • css - boolean,是否使用 CSS 过渡类。默认为 true。如果设置为 false,将只通过组件事件触发注册的 JavaScript 钩子。
  • type - string,指定过渡事件类型,侦听过渡何时结束。有效值为 "transition""animation"。默认 Vue.js 将自动检测出持续时间长的为过渡事件类型。
  • mode - string,控制离开/进入过渡的时间序列。有效的模式有 "out-in""in-out";默认同时进行。
  • duration - number | { enter: number, leave: number } 指定过渡的持续时间。默认情况下,Vue 会等待过渡所在根元素的第一个 transitionendanimationend 事件。
  • enter-class - string
  • leave-class - string
  • appear-class - string
  • enter-to-class - string
  • leave-to-class - string
  • appear-to-class - string
  • enter-active-class - string
  • leave-active-class - string
  • appear-active-class - string

总结

vue 给我们提供了一整套 css 以及 js 的钩子,这些钩子本身都已经帮我定义好并绑定在实例上面,剩下的就是需要我们自己去重写 css 或者 js 钩子函数。