3.1、進入/離開 & 列表過渡
1. Overview
- Vue provides a variety of ways to apply transition effects when items are inserted, updated, or removed from the DOM.
- On this page, we’ll only cover **entering, leaving, **and list transitions, but you can see the next section for managing state transitions.
DOM操作時的過渡效果,讓頁面更絲滑。
2. 單元素/組件的過渡
先來個demo開開胃,完整代碼
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
</style>
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
<script>
new Vue({
el: '#demo',
data: {
show: true
}
})
</script>
2.1 過渡的類名(Transition Classes)
There are six classes applied for enter/leave transitions.
enter/leave過渡中,會有6個class切換
v-enter
v-enter-active
v-enter-to
(2.1.8+)v-leave
v-leave-active
v-leave-to
(2.1.8+)
2.2 CSS過渡
即給上面例子中的 .fade-enter-active, .fade-leave-active 這些類名應用的CSS樣式
2.3 CSS動畫
寫法差不多,就是把transition換成animation 完整代碼
<style>
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
</style>
<div id="example-2">
<button @click="show = !show">Toggle show</button>
<transition name="bounce">
<p v-if="show">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.</p>
</transition>
</div>
<script>
new Vue({
el: '#example-2',
data: {
show: true
}
})
</script>
2.4 自定義過渡的類名
我們可以通過以下 attribute 來自定義過渡類名:
enter-class
enter-active-class
enter-to-class
(2.1.8+)leave-class
leave-active-class
leave-to-class
(2.1.8+)
如下與 Animate.css的結合使用:完整代碼
<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">
<div id="example-3">
<button @click="show = !show">
Toggle render
</button>
<transition
name="custom-classes-transition"
enter-active-class="animated tada"
leave-active-class="animated bounceOutRight"
>
<p v-if="show">hello</p>
</transition>
</div>
<script>
new Vue({
el: '#example-3',
data: {
show: true
}
})
</script>
2.5 同時使用過渡和動畫
要同時使用過渡和動畫,要用type
屬性指明類型:animation
or transition
2.6 指定過渡的時間
<transition :duration="1000">...</transition>
<transition :duration="{ enter: 500, leave: 800 }">...</transition>
2.7 JavaScript鉤子(JavaScript Hooks)
用js代碼操作動畫
如下使用了Velocity.js動畫庫,完整代碼
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<div id="example-4">
<button @click="show = !show">
Toggle
</button>
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:leave="leave"
v-bind:css="false"
>
<p v-if="show">
Demo
</p>
</transition>
</div>
<script>
new Vue({
el: '#example-4',
data: {
show: false
},
methods: {
beforeEnter: function (el) {
el.style.opacity = 0
el.style.transformOrigin = 'left'
},
enter: function (el, done) {
Velocity(el, {opacity: 1, fontSize: '1.4em'}, {duration: 300})
Velocity(el, {fontSize: '1em'}, {complete: done})
},
leave: function (el, done) {
Velocity(el, {translateX: '15px', rotateZ: '50deg'}, {duration: 600})
Velocity(el, {rotateZ: '100deg'}, {loop: 2})
Velocity(el, {
rotateZ: '45deg',
translateY: '30px',
translateX: '30px',
opacity: 0
}, {complete: done})
}
}
})
</script>
3. 初始渲染的過渡(Transitions on Initial Render)
If you also want to apply a transition on the initial render of a node, you can add the
appear
attribute:
一個DOM節點初始化渲染到頁面時可以引用過渡效果
<transition appear>
<!-- ... -->
</transition>
// 【還自定義class】
<transition
appear
appear-class="custom-appear-class"
appear-to-class="custom-appear-to-class" (2.1.8+)
appear-active-class="custom-appear-active-class"
>
<!-- ... -->
</transition>
// 【也可以自定義js鉤子】
<transition
appear
v-on:before-appear="customBeforeAppearHook"
v-on:appear="customAppearHook"
v-on:after-appear="customAfterAppearHook"
v-on:appear-cancelled="customAppearCancelledHook"
>
<!-- ... -->
</transition>
4. 多個元素之間的過渡(Transitioning Between Elements)
一個常見的場景就是:渲染列表元素時,如果列表是空的,則渲染一個代表空列表的元素
<transition>
<table v-if="items.length > 0">
<!-- ... -->
</table>
<p v-else>Sorry, no items found.</p>
</transition>
需要注意:如果兩個tag名一樣的元素之間做過渡時,要加key
demo如下:
<style>
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
</style>
<div id="app">
<transition name="bounce">
<button v-bind:key="docState">
{{ buttonMessage }}
</button>
</transition>
<button @click="savebutton">切換按鈕</button>
</div>
<script>
new Vue({
el: '#app',
data: {
docState: 'saved'
},
computed:{
buttonMessage: function () {
switch (this.docState) {
case 'saved': return 'Edit'
case 'edited': return 'Save'
}
}
},
methods: {
savebutton:function () {
if(this.docState == 'edited'){
this.docState = 'saved'
}else {
this.docState = 'edited'
}
}
}
})
</script>
4.1 過渡模式
可以設置兩種過渡模式:
-
in-out
: New element transitions in first, then when complete, the current element transitions out. -
out-in
: Current element transitions out first, then when complete, the new element transitions in.
我們來對比下設置了out-in
模式和不設置的區別吧:給上面例子上的transition加上mode屬性爲out-in
<transition name="bounce" mode="out-in">
<button v-bind:key="docState">
{{ buttonMessage }}
</button>
</transition>
加之前:
加之後:效果棒棒噠
5. 多個組件之間的過渡
組件之間的過渡更加簡單,寫法和元素一樣,不需要加key
:
<style>
.component-fade-enter-active, .component-fade-leave-active {
transition: opacity .3s ease;
}
.component-fade-enter, .component-fade-leave-to
/* .component-fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
</style>
<div id="app">
<input type="radio" value="v-a" id="a" name="view" @change="view='v-a'">
<label for="a">A</label>
<input type="radio" value="v-b" id="b" name="view" @change="view='v-b'">
<label for="b">B</label>
<transition name="component-fade" mode="out-in">
<component v-bind:is="view"></component>
</transition>
</div>
<script>
new Vue({
el: '#app',
data: {
view: 'v-a'
},
components: {
'v-a': {
template: '<div>Component A</div>'
},
'v-b': {
template: '<div>Component B</div>'
}
}
})
</script>
6. 列表過渡(List Transitions)
列表的Entering/Leaving過渡、Move Transitions移動過渡,用<transition-group>
有幾個注意點:
- 渲染時會轉換爲實際元素,默認爲span,可以加
tag
標籤指定,如下例子中指定爲tag='p'
- 的內部元素上要加
key
- css過渡類是應用在內部元素上的,而不是 group/container itself.
6.1 List Entering/Leaving Transitions
<style>
.list-complete-item {
transition: all 1s;
display: inline-block;
margin-right: 10px;
}
.list-complete-enter, .list-complete-leave-to
/* .list-complete-leave-active below version 2.1.8 */ {
opacity: 0;
transform: translateY(30px);
}
.list-complete-leave-active {
position: absolute;
}
</style>
<div id="list-demo">
<button v-on:click="shuffle">Shuffle</button>
<button v-on:click="add">Add</button>
<button v-on:click="remove">Remove</button>
<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>
</div>
<script>
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)
},
shuffle: function () {
this.items = _.shuffle(this.items)
}
}
})
</script>
6.2 List Move Transitions
上面演示了列表內元素進入/離開時的過渡效果,
爲了列表中元素移動時的過渡效果,vue引入了v-move
過渡類名,如下的:.flip-list-move
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>
<style>
.flip-list-move {
transition: transform 1s;
}
</style>
<div id="flip-list-demo" class="demo">
<button v-on:click="shuffle">Shuffle</button>
<transition-group name="flip-list" tag="ul">
<li v-for="item in items" v-bind:key="item">
{{ item }}
</li>
</transition-group>
</div>
<script>
new Vue({
el: '#flip-list-demo',
data: {
items: [1,2,3,4,5,6,7,8,9]
},
methods: {
shuffle: function () {
this.items = _.shuffle(this.items)
}
}
})
</script>
6.3 列表使用Javascript鉤子函數添加過渡效果
上面講的都是列表用css進行過渡,列表也可以用js代碼進行過渡,如下:
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<div id="staggered-list-demo">
<input v-model="query">
<transition-group
name="staggered-fade"
tag="ul"
v-bind:css="false"
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:leave="leave"
>
<li
v-for="(item, index) in computedList"
v-bind:key="item.msg"
v-bind:data-index="index"
>{{ item.msg }}
</li>
</transition-group>
</div>
<script>
new Vue({
el: '#staggered-list-demo',
data: {
query: '',
list: [
{ msg: 'Bruce Lee' },
{ msg: 'Jackie Chan' },
{ msg: 'Chuck Norris' },
{ msg: 'Jet Li' },
{ msg: 'Kung Fury' }
]
},
computed: {
computedList: function () {
var vm = this
return this.list.filter(function (item) {
return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1
})
}
},
methods: {
beforeEnter: function (el) {
el.style.opacity = 0
el.style.height = 0
},
enter: function (el, done) {
var delay = el.dataset.index * 150
setTimeout(function () {
Velocity(
el,
{ opacity: 1, height: '1.6em' },
{ complete: done }
)
}, delay)
},
leave: function (el, done) {
var delay = el.dataset.index * 150
setTimeout(function () {
Velocity(
el,
{ opacity: 0, height: 0 },
{ complete: done }
)
}, delay)
}
}
})
</script>
7. 可複用的過渡
To create a reusable transition, all you have to do is place a
<transition>
or<transition-group>
組件的過渡也也可以不用,相當於一個殼子,殼子上帶着過渡效果,你可以複用到別的地方
8. 動態過渡
Yes, even transitions in Vue are data-driven! The most basic example of a dynamic transition binds the
name
attribute to a dynamic property.
由於過渡效果的實現都是在<transition>
or <transition-group>
組件上添加屬性,那麼這些屬性的屬性值根據不同條件也可以被指定不同的動態值。
這就是動態過渡的由來。讓過渡更加靈活和隨心所欲
更多Vue文檔解讀:《Vue Doc 筆記》