内置的<TransitionGroup>
Vue 中的组件帮助我们对添加到页面的元素进行动画处理v-for
。
这个<TransitionGroup>
组件用于创建的元素周围v-for
,在添加或删除这些元素时为其提供单独的动画。
创建的标签v-for
在 - 的里面<TransitionGroup>
组件必须定义为key
属性。
这个<TransitionGroup>
如果我们使用以下方法将组件定义为特定标签,则该组件仅呈现为 HTML 标签:tag
道具,像这样:
<TransitionGroup tag="ol">
<li v-for="x in products" :key="x">
{{ x }}
</li>
</TransitionGroup>
这是上面代码经过 Vue 渲染后的结果:
<ol>
<li>Apple</li>
<li>Pizza</li>
<li>Rice</li>
</ol>
现在,我们可以添加 CSS 代码,以便在将新项目添加到列表时为其添加动画效果:
<style>
.v-enter-from {
opacity: 0;
rotate: 180deg;
}
.v-enter-to {
opacity: 1;
rotate: 0deg;
}
.v-enter-active {
transition: all 0.7s;
}
</style>
在此示例中,只需将新项目添加到“products”数组即可对其进行动画处理:
App.vue
:
<template>
<h3>The <TransitionGroup> Component</h3>
<p>New products are given animations using the <TransitionGroup> component.</p>
<input type="text" v-model="inpName">
<button @click="addEl">Add</button>
<TransitionGroup tag="ol">
<li v-for="x in products" :key="x">
{{ x }}
</li>
</TransitionGroup>
</template>
<script>
export default {
data() {
return {
products: ['Apple','Pizza','Rice'],
inpName: ''
}
},
methods: {
addEl() {
const el = this.inpName;
this.products.push(el);
this.inpName = null;
}
}
}
</script>
<style>
.v-enter-from {
opacity: 0;
rotate: 180deg;
}
.v-enter-to {
opacity: 1;
rotate: 0deg;
}
.v-enter-active {
transition: all 0.7s;
}
</style>
运行示例 »
当删除其他元素之间的元素时,其他元素将落入删除元素所在的位置。为了动画显示当删除元素时其余列表项如何就位,我们将使用自动生成的v-move
类。
但首先,让我们看一个例子不是当一个元素被移除时,其他项目如何归位的动画:
App.vue
:
<template>
<h3>The <TransitionGroup> Component</h3>
<p>New products are given animations using the <TransitionGroup> component.</p>
<button @click="addDie">Roll</button>
<button @click="removeDie">Remove random</button><br>
<TransitionGroup>
<div v-for="x in dice" :key="x" class="diceDiv" :style="{ backgroundColor: 'hsl('+x*40+',85%,85%)' }">
{{ x }}
</div>
</TransitionGroup>
</template>
<script>
export default {
data() {
return {
dice: [],
inpName: ''
}
},
methods: {
addDie() {
const newDie = Math.ceil(Math.random()*6);
this.dice.push(newDie);
},
removeDie() {
if(this.dice.length>0){
this.dice.splice(Math.floor(Math.random()*this.dice.length), 1);
}
}
},
mounted() {
this.addDie();
this.addDie();
this.addDie();
}
}
</script>
<style>
.v-enter-from {
opacity: 0;
translate: 200px 0;
rotate: 360deg;
}
.v-enter-to {
opacity: 1;
translate: 0 0;
rotate: 0deg;
}
.v-enter-active,
.v-leave-active {
transition: all 0.7s;
}
.v-leave-from { opacity: 1; }
.v-leave-to { opacity: 0; }
.diceDiv {
margin: 10px;
width: 30px;
height: 30px;
line-height: 30px;
vertical-align: middle;
text-align: center;
border: solid black 1px;
border-radius: 5px;
display: inline-block;
}
</style>
运行示例 »
正如您在上面的示例中所看到的,当删除某个项目时,删除的项目后面的项目会突然跳到新位置。要在删除某个项目时为其余项目设置动画,我们使用自动生成的v-move
类。
这个v-move
当被移除的项目离开时,类对其他元素进行动画处理,但存在一个问题:被移除的项目仍然存在并占据位置,直到被移除,因此v-move
类不会有任何影响。给v-move
类一些我们可以设置的动画position: absolute;
到v-leave-active
类。什么时候position: absolute;
在删除期间设置,删除的项目仍然可见,但不占用空间。
在此示例中,与上一个示例的唯一区别是第 14 行和第 17 行添加了两个新的 CSS 类:
App.vue
:
<style>
.v-enter-from {
opacity: 0;
translate: 200px 0;
rotate: 360deg;
}
.v-enter-to {
opacity: 1;
translate: 0 0;
rotate: 0deg;
}
.v-enter-active,
.v-leave-active,
.v-move {
transition: all 0.7s;
}
.v-leave-active { position: absolute; }
.v-leave-from { opacity: 1; }
.v-leave-to { opacity: 0; }
.diceDiv {
margin: 10px;
width: 30px;
height: 30px;
line-height: 30px;
vertical-align: middle;
text-align: center;
border: solid black 1px;
border-radius: 5px;
display: inline-block;
}
</style>
运行示例 »
让我们使用上面的示例作为新示例的基础。
在此示例中,当添加或删除新项目或对整个数组进行排序时,整个列表的动画效果变得更加清晰。
在这个例子中我们可以:
App.vue
:
<template>
<h3>The <TransitionGroup> Component</h3>
<p>Items inside the <TransitionGroup> component are animated when they are created or removed.</p>
<button @click="addDie">Roll</button>
<button @click="addDie10">Roll 10 dice</button>
<button @click="dice.sort(compareFunc)">Sort</button>
<button @click="dice.sort(shuffleFunc)">Shuffle</button><br>
<TransitionGroup>
<div
v-for="x in dice"
:key="x.keyNmbr"
class="diceDiv"
:style="{ backgroundColor: 'hsl('+x.dieNmbr*60+',85%,85%)' }"
@click="removeDie(x.keyNmbr)">
{{ x.dieNmbr }}
</div>
</TransitionGroup>
</template>
<script>
export default {
data() {
return {
dice: [],
keyNumber: 0
}
},
methods: {
addDie() {
const newDie = {
dieNmbr: Math.ceil(Math.random()*6),
keyNmbr: this.keyNumber
};
this.dice.splice(Math.floor(Math.random()*this.dice.length),0,newDie);
this.keyNumber++;
},
addDie10() {
for(let i=0; i<10; i++) {
this.addDie();
}
},
compareFunc(a,b){
return a.dieNmbr - b.dieNmbr;
},
shuffleFunc(a,b){
return Math.random()-0.5;
},
removeDie(key) {
const pos = this.dice.map(e => e.keyNmbr).indexOf(key);
this.dice.splice(pos, 1);
}
},
mounted() {
this.addDie10();
}
}
</script>
<style>
.v-enter-from {
opacity: 0;
scale: 0;
rotate: 360deg;
}
.v-enter-to {
opacity: 1;
scale: 1;
rotate: 0deg;
}
.v-enter-active,
.v-leave-active,
.v-move {
transition: all 0.7s;
}
.v-leave-active { position: absolute; }
.v-leave-from { opacity: 1; }
.v-leave-to { opacity: 0; }
.diceDiv {
margin: 10px;
width: 30px;
height: 30px;
line-height: 30px;
vertical-align: middle;
text-align: center;
border: solid black 1px;
border-radius: 5px;
display: inline-block;
}
.diceDiv:hover {
cursor: pointer;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
#app {
position: relative;
}
</style>
运行示例 »
截取页面反馈部分,让我们更快修复内容!也可以直接跳过填写反馈内容!