概述
Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。包括以下工具:
- 在 CSS 过渡和动画中自动应用 class
- 可以配合使用第三方 CSS 动画库,如 Animate.css
- 在过渡钩子函数中使用 JavaScript 直接操作 DOM
- 可以配合使用第三方 JavaScript 动画库,如 Velocity.js
在这里,我们只会讲到进入、离开和列表的过渡,你也可以看下一节的管理过渡状态。
单元素 / 组件的过渡
transition
的封装组件
过渡的类名
v-enter
v-enter-active
v-enter-to
v-leave
v-leave-active
v-leave-to
注意:如果<transition>
没有名字,则v-
是这些类名的默认前缀。如果像下面示例中,使用<transition name="fade">
,那么v-enter
就会替换为fade-enter
效果
这个示例中,.fade-ernter
和.fade-enter-active
先被添加,随后立即删除.fade-enter
,并添加.fade-enter-to
,enter进程结束后,一起删除.fade-enter-active
和.fade-enter-to
。
CSS过渡
常用的过渡都是CSS过渡
效果
CSS动画
CSS动画和CSS过渡用法相同,区别是动画中v-enter
类名在节点插入DOM后不会立即删除,而是在animationed
事件触发时删除
效果
自定义过渡的类名
可以通过attribute
来自定义过渡类名:
enter-class
enter-active-class
enter-to-class
leave-class
leave-active-class
leave-to-class
注意,自定义过渡类名,优先级高于普通类名
还可以使用第三方CSS动画库,如Animate.css
效果
同时使用过渡和动画
Vue 的事件监听器可以是transitioned
或animationed
,取决于给元素应用的CSS规则。
但在一些场景中,需要给同一个元素同时设置两种过渡动效。transition
和animation
结束时间不一样,需要使用type
attribute 并设置 animation
或transition
来声明需要Vue监听的类型。
显性的过渡持续时间
在很多情况下,Vue 可以自动得出过渡效果的完成时机。默认情况下,Vue 会等待其在过渡效果的根元素的第一个 transitionend
或 animationend
事件。然而也可以不这样设定——比如,我们可以拥有一个精心编排的一系列过渡效果,其中一些嵌套的内部元素相比于过渡效果的根元素有延迟的或更长的过渡效果。
在这种情况下你可以用 <transition>
组件上的 duration
prop 定制一个显性的过渡持续时间 (以毫秒计):
<transition :duration="1000">...</transition>
复制代码
你也可以定制进入和移出的持续时间:
<transition :duration="{ enter: 500, leave: 800 }">...</transition>
复制代码
JavaScript 钩子
可在 attribute 中声明 JavaScript 钩子
钩子函数 结合 CSS
这些钩子函数可以结合 CSS transitions
/ animations
使用,也可以单独使用。
JavaScript 函数 结合 transitions 使用示例
效果
JavaScript 过渡
注意
- 当只用 JavaScript 过渡的时候, 在
enter
和leave
中必须使用done
进行回调。否则,它们将被同步调用,过渡会立即完成。 - 推荐对于仅使用 JavaScript 过渡的元素添加
v-bind:css="false"
,Vue会跳过CSS的检测。这也可以避免过渡过程中CSS的影响。
Velocity 和 jQuery.animate 的工作方式类似,也可以用来实现 JavaScript 动画
效果
多个元素的过渡
key
先看一个示例-使用key
效果
对于多个元素的过渡,可以使用v-if
/ v-else
。
但当有相同标签名的元素切换时,需要通过key
设置唯一的值来标记以让Vue区分,否则Vue为了效率只会替换相同标签内部的内容。
上面的示例就正确使用了key
,如果不加key
的话,就会默认替换标签内部的on
为off
,效果如下。
使用多个v-if
的多个元素的过渡可以重写为绑定了动态 property 的单个元素过渡。
<transition>
<button v-if="docState === 'saved'" key="saved">
Edit
</button>
<button v-if="docState === 'edited'" key="edited">
Save
</button>
<button v-if="docState === 'editing'" key="editing">
Cancel
</button>
</transition>
复制代码
可以重写为
<transition>
<button v-bind:key="docState">
{{ buttonMessage }}
</button>
</transition>
复制代码
// ...
computed: {
buttonMessage: function () {
switch (this.docState) {
case 'saved': return 'Edit'
case 'edited': return 'Save'
case 'editing': return 'Cancel'
}
}
}
复制代码
过渡模式
还有一个问题,上面使用了key
的示例,在on
按钮和off
按钮的过渡中,两个按钮都被重绘了,一个离开过渡的时候,另一个开始进入过渡。这是<transition>
的默认行为——进入和离开同时发生。
因此提供了过渡模式:
in-out
:新元素过渡 => 当前元素过渡离开out-in
:当前元素过渡 => 新元素过渡进入
现在用out-in
重写之前的开关按钮过渡:
<transition name="fade" mode="out-in">
<!-- ... the buttons ... -->
<transition>
复制代码
效果
多个组件的过渡
多个组件的过渡更简单,不需要key
,相反,只需要使用动态组件
效果
列表过渡
使用<transition-group>
组件,同时渲染整个列表。
组件特点:
- 不同于
<transition>
,它会以一个真实元素呈现:默认为一个<span>
。也可以通过tag
更换为其他元素。 - 过渡模式不可用,因为不再相互切换特有的元素。
- 内部元素总是需要提供唯一的
key
值。 - CSS过渡的类将会应用在内部的元素中,而不是这个组 / 容器本身。
列表的进入 / 离开过渡
效果
这个例子中,当添加和移除元素的时候,周围的元素会瞬间移动到他们的新布局的位置,而不是平滑的过渡,下面来解决这个问题。
列表的排序过渡
效果
<transition-group>
组件不仅可以进入和离开动画,还可以改变定位。
Vue使用了一个叫FLIP简单的动画队列,使用transforms
将元素从之前的位置平滑过渡到新的位置。
现在将这个技术和之前的示例结合,使列表的一切变动都有动画过渡。
效果
注意!使用FLIP过渡的元素不能设置为display: inline
,作为替代方案,可以设置为display: inline-block
,或放置于flex中。