Vue <Transition> 元件
示例
使用內建的 <Transition>
元件為 <p>
元素新增動畫,該元素會隨著 v-if
的移除而消失
<Transition>
<p v-if="exists">Hello World!</p>
</Transition>
執行示例 »
更多示例請參見下方。
定義和用法
內建的 <Transition>
元件用於在元素與 v-if
、v-show
或動態元件一起新增或移除時為它們新增動畫。
元素的動畫規則寫在自動生成的類或 JavaScript 過渡鉤子中。參見下表。
<Transition>
元件的根元素只能有一個。
Props
Prop | 描述 | |
---|---|---|
none | 預設。 | 執行示例 » |
appear | 如果設定為 true ,元素在首次掛載時也會進行動畫。預設值為 false 。 |
執行示例 » |
mode | mode="out-in" 確保當前元素離開後下一個元素再進入。 mode="in-out" 確保新元素進入後舊元素再離開。預設情況下,舊元素和新元素同時離開和進入。 |
執行示例 » |
name | 指定過渡的名稱。如果我們有多個過渡,需要給它們唯一的名稱以區分。 name="swirl" 確保 CSS 過渡類以 swirl- 開頭,而不是預設字首 v- 。 |
執行示例 » |
css | 布林值。 :css="false" 告訴 Vue 編譯器不使用 CSS 過渡類,僅使用 JavaScript 鉤子。設定此 prop 後,必須在 enter 和 leave 鉤子中使用 done() 回撥。 |
執行示例 » |
type | 指定是等待 'animation' 還是 'transition' 完成過渡。如果同時設定了 CSS 動畫和 CSS 過渡,並且沒有設定此 *type* prop,Vue 將檢測兩者的最長持續時間並將其用作過渡時間。 | |
duration | 指定 'enter' 和 'leave' 過渡的長度。預設是在 CSS 動畫或 CSS 過渡結束時結束。可以透過 :duration="{enter:2000, leave:1000 }" 或 duration="1000" 來定義特定的時間。 |
|
enterFromClass enterActiveClass enterToClass appearFromClass appearActiveClass appearToClass leaveFromClass leaveActiveClass leaveToClass |
使用這些 props 重新命名過渡類。 使用其中一個 prop,例如 |
執行示例 » |
CSS 過渡類
當使用 <Transition>
元件時,我們會自動獲得六個不同的 CSS 類,可以在元素新增或移除時使用它們來進行動畫。
這些類在元素新增(enter)或移除(leave)的不同階段處於活動狀態。
Transition Class | 描述 | |
---|---|---|
v-enter-from | 進入階段開始時元素的初始樣式 | 執行示例 » |
v-enter-active | 進入階段期間元素的樣式 | 執行示例 » |
v-enter-to | 進入階段結束時的元素樣式 | 執行示例 » |
v-leave-from | 離開階段開始時元素的初始樣式 | 執行示例 » |
v-leave-active | 離開階段期間元素的樣式 | 執行示例 » |
v-leave-to | 離開階段結束時的元素樣式 | 執行示例 » |
JavaScript 過渡鉤子
上面的過渡類對應於我們可以用來執行 JavaScript 程式碼的事件。
JavaScript Event | 描述 | |
---|---|---|
before-enter | 在進入階段開始時呼叫 | |
enter | 在 'before-enter' 鉤子之後,進入階段期間呼叫 | 執行示例 » |
after-enter | 在進入過渡結束時呼叫 | 執行示例 » |
enter-cancelled | 如果進入過渡被取消,則呼叫 | 執行示例 » |
before-leave | 在離開階段開始時呼叫 | 執行示例 » |
leave | 在 'before-leave' 鉤子之後,離開階段期間呼叫 | 執行示例 » |
after-leave | 在離開過渡結束時呼叫 | |
leave-cancelled | 僅當使用 v-show 且離開階段被取消時呼叫 |
更多示例
示例 1
一個 <p>
元素在切換時會滑動進出。
<template>
<h1>Add/Remove <p> Tag</h1>
<button @click="this.exists = !this.exists">{{btnText}}</button><br>
<Transition>
<p v-if="exists">Hello World!</p>
</Transition>
</template>
<script>
export default {
data() {
return {
exists: false
}
},
computed: {
btnText() {
if(this.exists) {
return 'Remove';
}
else {
return 'Add';
}
}
}
}
</script>
<style>
.v-enter-from {
opacity: 0;
translate: -100px 0;
}
.v-enter-to {
opacity: 1;
translate: 0 0;
}
.v-leave-from {
opacity: 1;
translate: 0 0;
}
.v-leave-to {
opacity: 0;
translate: 100px 0;
}
p {
background-color: lightgreen;
display: inline-block;
padding: 10px;
transition: all 0.5s;
}
</style>
執行示例 »
示例 2
一個 <p>
元素在 'enter' 和 'leave' 期間有不同的背景顏色。
<template>
<h1>Add/Remove <p> Tag</h1>
<button @click="this.exists = !this.exists">{{btnText}}</button><br>
<Transition>
<p v-if="exists">Hello World!</p>
</Transition>
</template>
<script>
export default {
data() {
return {
exists: false
}
},
computed: {
btnText() {
if(this.exists) {
return 'Remove';
}
else {
return 'Add';
}
}
}
}
</script>
<style>
.v-enter-active {
background-color: lightgreen;
animation: added 1s;
}
.v-leave-active {
background-color: lightcoral;
animation: added 1s reverse;
}
@keyframes added {
from {
opacity: 0;
translate: -100px 0;
}
to {
opacity: 1;
translate: 0 0;
}
}
p {
display: inline-block;
padding: 10px;
border: dashed black 1px;
}
</style>
執行示例 »
示例 3
元素以不同的方式進行動畫,使用 name
prop 來區分 <Transition>
元件。
<template>
<h1>Add/Remove <p> Tag</h1>
<p>The second transition in this example has the name prop "swirl", so that we can keep the transitions apart with different class names.</p>
<hr>
<button @click="this.p1Exists = !this.p1Exists">{{btn1Text}}</button><br>
<Transition>
<p v-if="p1Exists" id="p1">Hello World!</p>
</Transition>
<hr>
<button @click="this.p2Exists = !this.p2Exists">{{btn2Text}}</button><br>
<Transition name="swirl">
<p v-if="p2Exists" id="p2">Hello World!</p>
</Transition>
</template>
<script>
export default {
data() {
return {
p1Exists: false,
p2Exists: false
}
},
computed: {
btn1Text() {
if(this.p1Exists) {
return 'Remove';
}
else {
return 'Add';
}
},
btn2Text() {
if(this.p2Exists) {
return 'Remove';
}
else {
return 'Add';
}
}
}
}
</script>
<style>
.v-enter-active {
background-color: lightgreen;
animation: added 1s;
}
.v-leave-active {
background-color: lightcoral;
animation: added 1s reverse;
}
@keyframes added {
from {
opacity: 0;
translate: -100px 0;
}
to {
opacity: 1;
translate: 0 0;
}
}
.swirl-enter-active {
animation: swirlAdded 1s;
}
.swirl-leave-active {
animation: swirlAdded 1s reverse;
}
@keyframes swirlAdded {
from {
opacity: 0;
rotate: 0;
scale: 0.1;
}
to {
opacity: 1;
rotate: 360deg;
scale: 1;
}
}
#p1, #p2 {
display: inline-block;
padding: 10px;
border: dashed black 1px;
}
#p2 {
background-color: lightcoral;
}
</style>
執行示例 »
示例 4
after-enter
事件觸發一個 <div>
元素的顯示。
<template>
<h1>JavaScript Transition Hooks</h1>
<p>This code hooks into "after-enter" so that after the initial animation is done, a method runs that displays a red div.</p>
<button @click="pVisible=true">Create p-tag!</button><br>
<Transition @after-enter="onAfterEnter">
<p v-show="pVisible" id="p1">Hello World!</p>
</Transition>
<br>
<div v-show="divVisible">This appears after the "enter-active" phase of the transition.</div>
</template>
<script>
export default {
data() {
return {
pVisible: false,
divVisible: false
}
},
methods: {
onAfterEnter() {
this.divVisible = true;
}
}
}
</script>
<style>
.v-enter-active {
animation: swirlAdded 1s;
}
@keyframes swirlAdded {
from {
opacity: 0;
rotate: 0;
scale: 0.1;
}
to {
opacity: 1;
rotate: 360deg;
scale: 1;
}
}
#p1, div {
display: inline-block;
padding: 10px;
border: dashed black 1px;
}
#p1 {
background-color: lightgreen;
}
div {
background-color: lightcoral;
}
</style>
執行示例 »
示例 5
一個切換按鈕觸發 enter-cancelled
事件。
<template>
<h1>The 'enter-cancelled' Event</h1>
<p>Click the toggle button again before the enter animation is finished to trigger the 'enter-cancelled' event.</p>
<button @click="pVisible=!pVisible">Toggle</button><br>
<Transition @enter-cancelled="onEnterCancelled">
<p v-if="pVisible" id="p1">Hello World!</p>
</Transition>
<br>
<div v-if="divVisible">You interrupted the "enter-active" transition.</div>
</template>
<script>
export default {
data() {
return {
pVisible: false,
divVisible: false
}
},
methods: {
onEnterCancelled() {
this.divVisible = true;
}
}
}
</script>
<style>
.v-enter-active {
animation: swirlAdded 2s;
}
@keyframes swirlAdded {
from {
opacity: 0;
rotate: 0;
scale: 0.1;
}
to {
opacity: 1;
rotate: 720deg;
scale: 1;
}
}
#p1, div {
display: inline-block;
padding: 10px;
border: dashed black 1px;
}
#p1 {
background-color: lightgreen;
}
div {
background-color: lightcoral;
}
</style>
執行示例 »
示例 6
appear
prop 會在頁面載入後立即開始 <p>
元素的動畫。
<template>
<h1>The 'appear' Prop</h1>
<p>The 'appear' prop starts the animation when the p tag below is rendered for the first time as the page opens. Without the 'appear' prop, this example would have had no animation.</p>
<Transition appear>
<p id="p1">Hello World!</p>
</Transition>
</template>
<style>
.v-enter-active {
animation: swirlAdded 1s;
}
@keyframes swirlAdded {
from {
opacity: 0;
rotate: 0;
scale: 0.1;
}
to {
opacity: 1;
rotate: 360deg;
scale: 1;
}
}
#p1 {
display: inline-block;
padding: 10px;
border: dashed black 1px;
background-color: lightgreen;
}
</style>
執行示例 »
示例 7
透過 'enter' 和 'leave' 的動畫來翻閱影像。在舊影像移除之前新增新影像。
<template>
<h1>Transition Between Elements</h1>
<p>Click the button to get a new image.</p>
<p>The new image is added before the previous is removed. We will fix this in the next example with mode="out-in".</p>
<button @click="newImg">Next image</button><br>
<Transition>
<img src="/img_pizza.svg" v-if="imgActive === 'pizza'">
<img src="/img_apple.svg" v-else-if="imgActive === 'apple'">
<img src="/img_cake.svg" v-else-if="imgActive === 'cake'">
<img src="/img_fish.svg" v-else-if="imgActive === 'fish'">
<img src="/img_rice.svg" v-else-if="imgActive === 'rice'">
</Transition>
</template>
<script>
export default {
data() {
return {
imgActive: 'pizza',
imgs: ['pizza', 'apple', 'cake', 'fish', 'rice'],
indexNbr: 0
}
},
methods: {
newImg() {
this.indexNbr++;
if(this.indexNbr >= this.imgs.length) {
this.indexNbr = 0;
}
this.imgActive = this.imgs[this.indexNbr];
}
}
}
</script>
<style>
.v-enter-active {
animation: swirlAdded 1s;
}
.v-leave-active {
animation: swirlAdded 1s reverse;
}
@keyframes swirlAdded {
from {
opacity: 0;
rotate: 0;
scale: 0.1;
}
to {
opacity: 1;
rotate: 360deg;
scale: 1;
}
}
img {
width: 100px;
margin: 20px;
}
img:hover {
cursor: pointer;
}
</style>
執行示例 »
示例 8
透過 'enter' 和 'leave' 的動畫來翻閱影像。 mode="out-in"
防止在新影像新增之前移除舊影像。
<template>
<h1>mode="out-in"</h1>
<p>Click the button to get a new image.</p>
<p>With mode="out-in", the next image is not added until the current image is removed. Another difference from the previous example, is that here we use computed prop instead of a method.</p>
<button @click="indexNbr++">Next image</button><br>
<Transition mode="out-in">
<img src="/img_pizza.svg" v-if="imgActive === 'pizza'">
<img src="/img_apple.svg" v-else-if="imgActive === 'apple'">
<img src="/img_cake.svg" v-else-if="imgActive === 'cake'">
<img src="/img_fish.svg" v-else-if="imgActive === 'fish'">
<img src="/img_rice.svg" v-else-if="imgActive === 'rice'">
</Transition>
</template>
<script>
export default {
data() {
return {
imgs: ['pizza', 'apple', 'cake', 'fish', 'rice'],
indexNbr: 0
}
},
computed: {
imgActive() {
if(this.indexNbr >= this.imgs.length) {
this.indexNbr = 0;
}
return this.imgs[this.indexNbr];
}
}
}
</script>
<style>
.v-enter-active {
animation: swirlAdded 0.7s;
}
.v-leave-active {
animation: swirlAdded 0.7s reverse;
}
@keyframes swirlAdded {
from {
opacity: 0;
rotate: 0;
scale: 0.1;
}
to {
opacity: 1;
rotate: 360deg;
scale: 1;
}
}
img {
width: 100px;
margin: 20px;
}
img:hover {
cursor: pointer;
}
</style>
執行示例 »
示例 9
元件之間的切換被動畫化。
<template>
<h1>Transition with Dynamic Components</h1>
<p>The Transition component wraps around the dynamic component so that the switching can be animated.</p>
<button @click="toggleValue = !toggleValue">Switch component</button>
<Transition mode="out-in">
<component :is="activeComp"></component>
</Transition>
</template>
<script>
export default {
data () {
return {
toggleValue: true
}
},
computed: {
activeComp() {
if(this.toggleValue) {
return 'comp-one'
}
else {
return 'comp-two'
}
}
}
}
</script>
<style>
.v-enter-active {
animation: slideIn 0.5s;
}
@keyframes slideIn {
from {
translate: -200px 0;
opacity: 0;
}
to {
translate: 0 0;
opacity: 1;
}
}
.v-leave-active {
animation: slideOut 0.5s;
}
@keyframes slideOut {
from {
translate: 0 0;
opacity: 1;
}
to {
translate: 200px 0;
opacity: 0;
}
}
#app {
width: 350px;
margin: 10px;
}
#app > div {
border: solid black 2px;
padding: 10px;
margin-top: 10px;
}
</style>
執行示例 »
示例 10
元件之間的切換被動畫化。
<template>
<h1>The :css="false" Prop</h1>
<p>With the 'css' prop set to 'false', we tell the compiler that JavaScript hooks are used instead of CSS transition classes.</p>
<p>When we use :css="false", we must call done() inside the 'enter' and the 'leave' hooks, to tell the browser when those transitions are finished.</p>
<button @click="pVisible=!pVisible">Toggle</button>
<div>
<Transition
:css="false"
@enter="onEnter"
@after-enter="onAfterEnter"
@before-leave="onBeforeLeave"
@leave="onLeave"
>
<p
v-if="pVisible"
id="p1">
Hello World!
</p>
</Transition>
</div>
</template>
<script>
export default {
data() {
return {
pVisible: false
}
},
methods: {
onEnter(el,done) {
let pos = 0;
window.requestAnimationFrame(frame);
function frame() {
if (pos > 150) {
done();
} else {
pos++;
el.style.left = pos + "px";
window.requestAnimationFrame(frame);
}
}
},
onAfterEnter(el) {
el.style.backgroundColor = "yellow";
},
onBeforeLeave(el) {
el.style.backgroundColor = "lightgreen";
},
onLeave(el,done) {
let pos = 150;
window.requestAnimationFrame(frame);
function frame() {
if (pos < 0) {
done();
}
else {
pos--;
el.style.left = pos + "px";
window.requestAnimationFrame(frame);
}
}
}
}
}
</script>
<style>
#p1 {
position: absolute;
padding: 10px;
border: dashed black 1px;
background-color: lightgreen;
}
#app > div {
position: relative;
background-color: coral;
width: 300px;
height: 300px;
border: dashed black 1px;
margin-top: 20px;
}
</style>
執行示例 »
示例 11
使用 enterActiveClass
prop 將 'v-enter-active' CSS 類重新命名為 'entering'。
<template>
<h1>The 'enterActiveClass' Prop</h1>
<button @click="this.exists = !this.exists">{{btnText}}</button><br>
<Transition enter-active-class="entering">
<p v-if="exists">Hello World!</p>
</Transition>
</template>
<script>
export default {
data() {
return {
exists: false
}
},
computed: {
btnText() {
if(this.exists) {
return 'Remove';
}
else {
return 'Add';
}
}
}
}
</script>
<style>
.entering {
background-color: lightgreen;
animation: added 1s;
}
.v-leave-active {
background-color: lightcoral;
animation: added 1s reverse;
}
@keyframes added {
from {
opacity: 0;
translate: -100px 0;
}
to {
opacity: 1;
translate: 0 0;
}
}
p {
display: inline-block;
padding: 10px;
border: dashed black 1px;
}
</style>
執行示例 »
相關頁面
Vue 教程: Vue 動畫
Vue 教程: Vue v-for 動畫
Vue 參考: Vue <TransitionGroup> 元件