一、原生标签的过渡
我们讨论多个组件的过渡,对于原生标签可以使用 v-if/v-else。
<transition>
<button v-if="isEditing" key="save">
Save
</button>
<button v-else key="edit">
Edit
</button>
</transition>
当有相同标签名的元素切换时,需要通过 key
attribute 设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。即使在技术上没有必要,给在<transition>
组件中的多个元素设置 key 是一个更好的实践。
在一些场景中,也可以通过给同一个元素的 key
attribute 设置不同的状态来代替 v-if
和 v-else
,上面的例子可以重写为:
<transition>
<button v-bind:key="isEditing">
{{ isEditing ? 'Save' : 'Edit' }}
</button>
</transition>
二、过渡模式
此时的两个button标签,save淡出的同时,edit淡入。一个离开过渡的时候另一个开始进入过渡。这是 <transition>
的默认行为 - 进入和离开同时发生。
可以用绝对定位把两个按钮重合起来(轮播)
同时生效的进入和离开的过渡不能满足所有要求,所以 Vue 提供了 过渡模式
in-out
:新元素先进行过渡,完成之后当前元素过渡离开。out-in
:当前元素先进行过渡,完成之后新元素过渡进入。
三、动态组件
有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里
上述内容可以通过 Vue 的 <component> 元素加一个特殊的 is attribute来实现:
<component v-bind:is="currentTabComponent"></component>
在上述示例中,currentTabComponent
可以包括
- 已注册组件的名字
- 一个组件的选项对象
四、过渡组件
<transition name="component-fade" mode="out-in">
<component v-bind:is="view"></component>
</transition>
即可实现组件的过渡
五、列表过渡
目前为止,关于过渡我们已经讲到:
- 单个节点
- 同一时间渲染多个节点中的一个
我们现在想要渲染整个列表,该怎么办
<div id="list-demo" class="demo">
<button v-on:click="add">Add</button>
<button v-on:click="remove">Remove</button>
<transition-group name="list" tag="p">
<span v-for="item in items" v-bind:key="item" class="list-item">
{{ item }}
</span>
</transition-group>
</div>
new Vue({
el: '#list-demo',
data: {
items: [1,2,3,4,5,6,7,8,9],
nextNum: 10
},
methods: {
randomIndex: function () {
return Math.floor(Math.random() * this.items.length)
},
add: function () {
this.items.splice(this.randomIndex(), 0, this.nextNum++)
},
remove: function () {
this.items.splice(this.randomIndex(), 1)
},
}
})
.list-item {
display: inline-block;
margin-right: 10px;
}
.list-enter-active, .list-leave-active {
transition: all 1s;
}
.list-enter, .list-leave-to
/* .list-leave-active for below version 2.1.8 */ {
opacity: 0;
transform: translateY(30px);
}
1. 不同于 <transition>
,它会以一个真实元素呈现:默认为一个 <span>
。你也可以通过 tag
attribute 更换为其他元素。
3. 内部元素总是需要 提供唯一的 key 属性值。
4. CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。
tag:
由于transition-group标签默认需要子组件是v-for,但是又需要一个对象来吧列表包起来,所以需要tag这个属性
两个类
- transition-group的类是为了添加列表项目的动画
- 列表的类是为了添加列表加进来后的样式,以及已经存在列表的样式
这个例子有个问题,当添加和移除元素的时候,周围的元素会瞬间移动到他们的新布局的位置,而不是平滑的过渡,我们下面会解决这个问题。
六、列表的排序过渡
<transition-group>
组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需了解新增的 v-move
attribute,它会在元素的改变定位的过程中应用。像之前的类名一样,可以通过 name
属性来自定义前缀,也可以通过 move-class
属性手动设置。
.flip-list-move {
transition: transform 1s;
}
这样即可
<transition-group name="list-complete" tag="p">
<span
v-for="item in items"
v-bind:key="item"
class="list-complete-item"
>
{{ item }}
</span>
</transition-group>
.list-complete-item {
transition: all 1s;
display: inline-block;
margin-right: 10px;
}
列表的一切变动都会有动画过渡
需要注意的是使用 FLIP 过渡的元素不能设置为 display: inline
。作为替代方案,可以设置为 display: inline-block
或者放置于 flex 中