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 编译器,此过渡不使用过渡类,只使用 JavaScript 钩子。有了这个 prop 集,done() 回调必须在 enter 和 leaf 钩子内部使用。 |
| type | 指定是等待 'animation' 还是 'transition' 来完成过渡。如果同时设置了 CSS 动画和 CSS 过渡,并且没有设置该类型 prop,Vue 将检测到这两个动画和过渡的最长持续时间,并将其用作过渡时间 |
| duration | 指定 'enter' 和 'leave' 的过渡时间长度。默认值是在 CSS 动画或 CSS 过渡结束时结束。具体时间可以这样定义::duration="{enter:2000, leave:1000 }", 或者像这样 duration="1000"。 |
| enterFromClass enterActiveClass enterToClass appearFromClass appearActiveClass appearToClass leaveFromClass leaveActiveClass leaveToClass | 使用这些 prop 可以重命名过渡类。 使用像这样的 prop,比如 |
CSS Transition 过渡类
当我们使用 <Transition> 组件时,我们会自动获得 6 个不同的 CSS 类,当添加或删除元素时,我们可以使用它们来设置动画。
当添加(进入)或删除(离开)元素时,这些类在不同阶段处于活动状态:
| Transition 类 | 描述 |
|---|---|
| v-enter-from | 进入阶段开始时元素的初始样式 |
| v-enter-active | 元素在进入阶段的样式 |
| v-enter-to | 元素的样式位于进入阶段的末尾 |
| v-leave-from | 离开阶段开始时元素的初始样式 |
| v-leave-active | 元素在离开阶段的样式 |
| v-leave-to | 元素的样式位于离开阶段的末尾 |
JavaScript Transition 钩子
上面的过渡类对应于我们可以挂接以运行 JavaScript 代码的事件。
| JavaScript 事件 | 描述 |
|---|---|
| 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> 元素在进入和离开期间具有不同的背景色:
<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
<p> 元素以不同的方式设置动画,使用命名 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
页面加载后,显示 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"><pv-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>