指南
基础概要
- 安装
- 介绍
- Vue 实例
- 模板语法
- computed 属性和 watcher
- class 和 style 绑定
- 根据条件进行渲染
- 列表渲染
- 事件处理
- 表单 input 绑定
- 组件基础
过渡 & 动画
- 进入、离开和列表的过渡
深入组件
- 组件注册
- props
- 自定义事件
- slot
- 动态组件和异步组件
- Handling Edge Cases
- 状态间的过渡
可重用 & 合成
- mixin
- 自定义指令
- render 函数 & jsx
- 插件
- 过滤器
工具
- 生产环境部署
- 单文件组件
- 单元测试
- TypeScript 支持
扩展升级
- 路由
- 状态管理
- 服务端渲染
内部原理
- 深入响应式原理
升级迁移
- 从 Vue 1.x 迁移
- 从 Vue Router 0.7.x 迁移
- 从 Vuex 0.6.x 迁移到 1.0
其他更多
- 对比其他框架
- 加入 Vue.js 社区
- 认识团队
进入、离开和列表的过渡
概述
当从 DOM 中插入、更新或移除项目时,Vue 提供多种应用过渡效果的方式。包括以下工具:
- 在 CSS 过渡和动画中自动处理 class
- 可以配合使用第三方 CSS 动画库,如 Animate.css
- 在过渡钩子函数中使用 JavaScript 直接操作 DOM
- 可以配合使用第三方 JavaScript 动画库,如 Velocity.js
本页面中,我们只会涉及到进入、离开和列表的过渡,然而你也可以查看下一章节管理过渡状态.
单元素/组件的过渡
Vue 提供了 transition
外层包裹容器组件(wrapper component),可以给下列情形中的任何元素和组件添加进入/离开(enter/leave)过渡
- 条件渲染(使用
v-if
) - 条件展示(使用
v-show
) - 动态组件
- 组件根节点
这是一个常见行为的简单示例:
<div id="demo"> |
new Vue({ |
.fade-enter-active, .fade-leave-active { |
hello
当插入或删除包含在 transition
组件中的元素时,Vue 将会做以下处理:
自动嗅探目标元素是否使用了 CSS 过渡或动画,如果使用,会在合适的时机添加/移除 CSS 过渡 class。
如果过渡组件设置了 JavaScript 钩子函数,这些钩子函数将在合适的时机调用。
如果没有检测到 CSS 过渡/动画,并且也没有设置 JavaScript 钩子函数,插入和/或删除 DOM 的操作会在下一帧中立即执行。(注意:这里的帧是指浏览器逐帧动画机制,和 Vue 的
nextTick
概念不同)
过渡类名(Transition Classes)
有 6 种 class 类名会在进入/离开(enter/leave)过渡中处理
v-enter
:进入式过渡(entering transition)的开始状态。在插入元素之前添加,在插入元素之后一帧移除。v-enter-active
:进入式过渡的激活状态。应用于整个进入式过渡时期。在插入元素之前添加,过渡/动画(transition/animation)完成之后移除。此 class 可用于定义进入式过渡的 duration, delay 和 easing 曲线。v-enter-to
:仅适用于版本 2.1.8+。进入式过渡的结束状态。在插入元素之后一帧添加(同时,移除v-enter
),在过渡/动画完成之后移除。v-leave
:离开式过渡(leaving transition)的开始状态。在触发离开式过渡时立即添加,在一帧之后移除。v-leave-active
:离开式过渡的激活状态。应用于整个离开式过渡时期。在触发离开式过渡时立即添加,在过渡/动画(transition/animation)完成之后移除。此 class 可用于定义离开式过渡的 duration, delay 和 easing 曲线。v-leave-to
:仅适用于版本 2.1.8+。离开式过渡的结束状态。在触发离开式过渡之后一帧添加(同时,移除v-leave
),在过渡/动画完成之后移除。
对于这些过渡中切换 class,每个都以过渡的 name 作为前缀。当你使用没有 name 的 <transition>
元素时,会默认前缀为 v-
。举个例子,如果你使用 <transition name="my-transition">
,那么默认的 v-enter
class 将会被替换为 my-transition-enter
。
v-enter-active
和 v-leave-active
可以指定不同的进入/离开过渡 easing 曲线,下面章节可以看到一个示例。
CSS 过渡(CSS Transitions)
最常用到的过渡类型是使用 CSS 过渡。下面是一个示例:
<div id="example-1"> |
new Vue({ |
/* 进入和离开动画可以分别 */ |
hello
CSS 动画(CSS Animations)
CSS 动画用法和 CSS 过渡相同,区别是在动画中 v-enter
类名在元素插入 DOM 后不会立即删除,而是在 animationend
事件触发时删除。
这里是一个示例,为了简洁省略了 CSS 规则的前缀:
<div id="example-2"> |
new Vue({ |
.bounce-enter-active { |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.
自定义过渡的 class 类名(Custom Transition Classes)
你也可以通过提供一下属性来指定自定义过渡类名
enter-class
enter-active-class
enter-to-class
(2.1.8+)leave-class
leave-active-class
leave-to-class
(2.1.8+)
它们将覆盖默认约定的类名,这对于将 Vue 的过渡系统和其他现有的第三方 CSS 动画库(如 Animate.css)集成使用会非常有用。
这里是一个示例:
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css"> |
new Vue({ |
hello
同时使用过渡和动画(Using Transitions and Animations Together)
Vue 为了知道过渡何时完成,必须附加相应的事件监听器。它可以是 transitionend
或 animationend
,这取决于给元素应用的 CSS 规则。如果你使用其中任何一种,Vue 能自动识别正确的类型并设置相应的事件监听器。
但是,在一些情况下,你可能需要给同一个元素同时设置过渡和动画,比如由 Vue 触发 CSS 动画,同时在鼠标悬停时触发 CSS 过渡。在这种情况下,你可能需要通过 type
属性,来显式声明需要 Vue 监听的类型,值可以是 animation
或 transition
。
显式过渡持续时间(Explicit Transition Durations)
2.2.0+ 新增
在大多数情况下,Vue 可以自动推断出过渡完成时间。默认情况下,Vue 会过渡根元素的第一个 transitionend
或 animationend
事件触发所需的等待时间。然而,这可能并不总是我们想要的 - 例如,我们可能具有设计安排的过渡序列(transition sequence):其中一些嵌套的内部元素(在根元素过渡完成后)还具有延续的过渡效果,或比过渡根元素更长的过渡持续时间。
在这种情况下,你可以使用 <transition>
组件上的 duration
属性 ,来指定一个显式的过渡持续时间(以毫秒为单位):
<transition :duration="1000">...</transition> |
你还可以为进入式和离开式持续时间指定不同的值:
<transition :duration="{ enter: 500, leave: 800 }">...</transition> |
JavaScript 钩子函数
可以在属性中声明 JavaScript 钩子
<transition |
// ... |
这些钩子函数可以结合 CSS 过渡/动画使用,也可以单独使用。
当仅使用 JavaScript 式过渡的时候, 在 enter
和 leave
钩子函数中,必须有 done
回调函数。否则,这两个钩子函数会被同步调用,过渡会立即完成。
推荐对于仅使用 JavaScript 的过渡显式添加 v-bind:css="false"
,以便 Vue 可以跳过 CSS 侦测。这也可以防止 CSS 规则意外干涉到过渡。
现在我们深入来看一个示例。这里是一个使用 Velocity.js 的 JavaScript 式过渡:
<!-- |
new Vue({ |
Demo
在初始渲染时过渡
如果你还想在节点初始渲染时应用过渡,可以添加 appear
属性:
<transition appear> |
默认情况下,对于进入和离开,会使用特定过渡。但是,如果你有需要,也可以指定自定义 CSS 类名:
<transition |
以及指定自定义 JavaScript 钩子函数:
<transition |
多个元素之间切换过渡
我们将在下面讨论多个元素之间切换过渡,但是还是可以使用 v-if
/v-else
,来对初始元素之间进行切换过渡。最常见的是,一个列表容器和描述列表为空的消息,这两个元素间的切换过渡:
<transition> |
可以这样使用,但是有一点事项需要注意:
当在具有相同标签名称的元素之间切换时,需要通过给它们分配唯一的 key
属性,以使 Vue 感知它们是不同的元素。否则 Vue 的编译器将因为效率,只会替换元素内部的内容。即使在技术上没有必要,但是,给 <transition>
组件中的多个元素设置 key,被认为是一个最佳实践。
示例:
<transition> |
在上面这种场景中,也通过给同一元素的 key
属性,设置不同的状态来进行过渡。而无需使用 v-if
和 v-else
,所以上面的示例可以重写为:
<transition> |
实际上,使用 v-if
的多个元素之间的过渡,还可以改为在单个元素上绑定动态属性的方式,来在任意数量的元素之间进行转换。例如:
<transition> |
可以重写为:
<transition> |
// ... |
过渡模式
这里还有一个问题,试着点击下面的按钮:
在 “on” 按钮和 “off” 按钮之间过渡时,这两个按钮会同步渲染 - 当一个过渡进入时,另一个过渡离开。这是 <transition>
的默认行为 - 进入和离开同时发生。
有时这样做是非常合理的,比如,在过渡的条目都是绝对定位时:
然后,还可以将元素位移,使它们看起来具有滑动过渡效果:
同时生效的进入式和离开式过渡不能满足所有要求,所以 Vue 提供了可选的过渡模式:
in-out
:新元素先过渡进入(transition in),过渡完成之后,当前元素过渡离开(transition out)。out-in
:当前元素先过渡离开(transition out),过渡完成之后,新元素过渡进入(transition in)。
现在,让我们用 out-in
模式,更新下前面的 on/off 按钮过渡:
<transition name="fade" mode="out-in"> |
只需添加一个额外的属性,就解决了最初的过渡问题,而无需添加任何特殊样式。
in-out
模式不是经常用到,但对于一些稍微不同的过渡效果还是有用的。尝试将这种模式与我们之前滑动淡出过渡的示例相结合:
很酷吧?
多个组件之间过渡
多个组件之间的过渡甚至更简单 - 我们不需要使用 key
属性。相反,我们需要使用动态组件:
<transition name="component-fade" mode="out-in"> |
new Vue({ |
.component-fade-enter-active, .component-fade-leave-active { |
列表过渡
目前为止,关于过渡我们已经完成了:
- 单个节点
- 多个节点,其中每次只渲染一个
那么,当我们整个列表的每一项(例如使用 v-for
)都需要同时进行渲染呢?在这种情况下,我们将使用 <transition-group>
组件。在我们深入示例之前,先来了解关于这个组件的一些要点:
- 不同于
<transition>
,它会以一个真实元素渲染:默认为<span>
。你也可以通过tag
属性更换为其他渲染元素 - 它内部的元素必须具有唯一的
key
属性
进入式/离开式列表过渡
现在让我们来深入一个示例,进入式过渡和离开式过渡都使用与之前相同的 CSS 类名:
<div id="list-demo"> |
new Vue({ |
.list-item { |
这个示例有个问题,当添加和移除项目时,其周围的项目会瞬间猛地移动到新的位置,而不是平滑过渡,我们稍后会解决这个问题。
列表的位移过渡
<transition-group>
组件还有一个暗藏玄机之处。不仅可以在进入和离开时进行动画,还可以在位置改变时进行动画。使用此功能所需要知道的唯一新的概念是,在项目位置改变时添加额外的 v-move
类名。与其他类名相同,它的前缀也和设置的 name
属性的值相匹配,你也可以通过 move-class
属性来手动指定类名。
此类名对于指定过渡时间和 easing 过渡曲线非常有用,如下所示:
<script src="https://lib.baomitu.com/lodash.js/4.14.1/lodash.min.js"></script> |
new Vue({ |
.flip-list-move { |
这个看起来很神奇,内部的实现原理是,Vue 使用了一个叫 FLIP 动画技术,可以通过使用 transform 将元素从之前的位置平滑过渡到新的位置。
我们可以将此技术与我们以前的实施相结合,为我们列表所有可能的位置变更都添加动画!
<script src="https://lib.baomitu.com/lodash.js/4.14.1/lodash.min.js"></script> |
new Vue({ |
.list-complete-item { |
需要注意的是,使用 FLIP 过渡的元素,在设置为 display: inline
时,无法正常运行。作为替代方案,可以将元素设置为 display: inline-block
,或者将元素放置于 flex 上下文(flex context)中。
FLIP 动画不局限于单个轴线方向(single axis),多个维度网格(multidimensional grid)也同样可以过渡:
Keep hitting the shuffle button until you win.
列表的渐进过渡
通过 data 属性与 JavaScript 式过渡的通信,就可以实现列表的逐项渐进过渡:
<script src="https://lib.baomitu.com/velocity/1.2.3/velocity.min.js"></script> |
new Vue({ |
可复用的过渡
通过 Vue 的组件系统可以实现复用过渡。要创建一个可复用过渡,你需要做的就是将 <transition>
或者 <transition-group>
作为组件根节点,然后将全部子内容放置在 transition 组件中就可以了。
这里是使用 template 的组件的简单示例:
Vue.component('my-special-transition', { |
函数组件更适合完成这个任务:
Vue.component('my-special-transition', { |
动态过渡
其实,在 Vue 中即使是过渡也是由数据驱动的!动态过渡最基本的例子是,将 name
属性(attribute)和动态属性(dynamic property)绑定在一起。
<transition v-bind:name="transitionName"> |
当你使用多个 Vue 过渡类名约定,来定义 CSS 过渡/动画,并在不同的类名约定之间切换时,动态过渡会非常有用。
所有的过渡属性都可以动态绑定。并且不仅是属性,由于事件钩子函数都是 Vue 的方法(methods),所以可以从 this 上下文访问到所有数据。这意味着,根据组件的状态,JavaScript 式过渡的表现可能会有所不同。
<script src="https://lib.baomitu.com/velocity/1.2.3/velocity.min.js"></script> |
new Vue({ |
hello
最后,创建动态过渡的最终方案是,组件通过接受 prop 来动态修改之前的过渡。还是那句话,唯一限制你的是想象力。