2.2.3 多个元素的过渡
优质
小牛编辑
133浏览
2023-12-01
我们之后讨论多个组件的过渡,对于原生标签可以使用v-if
/v-else
。最常见的多标签过渡是一个列表和描述这个列表为空消息的元素:
<transition> <table v-if="items.length > 0"> <!-- ... --> </table> <p v-else>Sorry, no items found.</p> </transition>
可以这样使用,但是有一点需要注意:
当有相同标签名的元素切换时,需要通过key
特性设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。即使在技术上没有必要,给在<transition>
组件中的多个元素设置 key 是一个更好的实践。
示例:
<transition> <button v-if="isEditing" key="save"> Save </button> <button v-else key="edit"> Edit </button> </transition>
在一些场景中,也可以通过给同一个元素的key
特性设置不同的状态来代替v-if
和v-else
,上面的例子可以重写为:
<transition> <button v-bind:key="isEditing"> {{ isEditing ? 'Save' : 'Edit' }} </button> </transition>
使用多个v-if
的多个元素的过渡可以重写为绑定了动态属性的单个元素过渡。例如:
<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' } } }
过渡模式
这里还有一个问题,试着点击下面的按钮:
在 “on” 按钮和 “off” 按钮的过渡中,两个按钮都被重绘了,一个离开过渡的时候另一个开始进入过渡。这是<transition>
的默认行为 - 进入和离开同时发生。
在元素绝对定位在彼此之上的时候运行正常:
然后,我们加上 translate 让它们运动像滑动过渡:
.no-mode-absolute-demo-wrapper { position: relative; height: 18px; } .no-mode-absolute-demo-wrapper button { position: absolute; } .no-mode-absolute-fade-enter-active, .no-mode-absolute-fade-leave-active { transition: opacity .5s; } .no-mode-absolute-fade-enter, .no-mode-absolute-fade-leave-active { opacity: 0; }同时生效的进入和离开的过渡不能满足所有要求,所以 Vue 提供了过渡模式
in-out
:新元素先进行过渡,完成之后当前元素过渡离开。out-in
:当前元素先进行过渡,完成之后新元素过渡进入。
用out-in
重写之前的开关按钮过渡:
<transition name="fade" mode="out-in"> <!-- ... the buttons ... --> </transition>
只用添加一个简单的特性,就解决了之前的过渡问题而无需任何额外的代码。
in-out
模式不是经常用到,但对于一些稍微不同的过渡效果还是有用的。
将之前滑动淡出的例子结合:
.with-mode-fade-enter-active, .with-mode-fade-leave-active { transition: opacity .5s } .with-mode-fade-enter, .with-mode-fade-leave-active { opacity: 0 }