聊一聊Vue.js過渡效果

聊一聊Vue.js過渡效果
1 Star2 Stars3 Stars4 Stars5 Stars 給文章打分!
Loading...

通過 Vue.js 的過渡系統,你可以輕鬆的為 DOM 節點被插入/移除的過程新增過渡動畫效果。Vue 將會在適當的時機新增/移除 CSS 類名來觸發 CSS3 過渡/動畫效果,你也可以提供相應的 JavaScript 鉤子函式在過渡過程中執行自定義的 DOM 操作。

以 v-transition=”my-transition” 這個指令為例,當帶有這個指令的 DOM 節點被插入或移除時,Vue 將會:

用 my-transition 這個 ID 去查詢是否有註冊過的 JavaScript 鉤子物件。這個物件可以是由 Vue.transition(id, hooks) 全域性註冊,或是通過 transitions 選項定義在當前的元件內部。如果找到此物件,則會在過渡動畫不同的階段呼叫相應的鉤子。

自動探測目標元素是否應用了 CSS 過渡效果或者動畫效果,並在適當的時機新增/移除 CSS 類名。

如果沒有提供 JavaScript 鉤子函式,也沒有檢測到相應的 CSS 過渡/動畫效果,DOM 的插入/移除會在下一幀立即執行。
所有的 Vue.js 過渡效果只有在該 DOM 操作是通過 Vue.js 觸發時才會生效。觸發的方式可以是通過內建指令,比如 v-if,或是通過 Vue 例項的方法,比如 vm.$appendTo()。

CSS 過渡效果
一個典型的 CSS 過渡效果定義如下:

<div v-if=”show” v-transition=”expand”>hello</div>

你還需要定義 .expand-transition, .expand-enter 和.expand-leave 三個 CSS 類:


.expand-transition {
transition: all .3s ease;
height: 30px;
padding: 10px;
background-color: #eee;
overflow: hidden;
}
.expand-enter, .expand-leave {
height: 0;
padding: 0 10px;
opacity: 0;
}

同時,你也可以提供 JavaScript 鉤子:


Vue.transition('expand', {
beforeEnter: function (el) {
el.textContent = 'beforeEnter'
},
enter: function (el) {
el.textContent = 'enter'
},
afterEnter: function (el) {
el.textContent = 'afterEnter'
},
enterCancelled: function (el) {
// handle cancellation
},
`
beforeLeave: function (el) {
el.textContent = 'beforeLeave'
},
leave: function (el) {
el.textContent = 'leave'
},
afterLeave: function (el) {
el.textContent = 'afterLeave'
},
leaveCancelled: function (el) {
// handle cancellation
}
})

結果

這裡使用的 CSS 類名由 v-transition 指令的值所決定。以 v-transition=”fade” 為例,CSS 類 .fade-transition 將會一直存在,而 .fade-enter 和 .fade-leave 將會在合適的時機自動被新增或移除。當 v-transition 指令沒有提供值的時候,所使用的 CSS 類名將會是預設的 .v-transition, .v-enter 和 .v-leave。

當 show 屬性變化時,Vue 會依據其當前的值來插入/移除 <div> 元素,並在合適的時機新增/移除對應的 CSS 類,具體如下:

當 show 變為 false 時,Vue 將會:

1.呼叫 beforeLeave 鉤子;
2.在元素上應用 CSS 類 .v-leave 來觸發過渡效果;
3.呼叫 leave 鉤子;
4.等待過渡效果執行完畢; (監聽 transitionend 事件)
5.從 DOM 中移除元素並且移除 CSS 類 .v-leave。
6.呼叫 afterLeave 鉤子。

當 show 為 true 時,Vue 將會:

1.呼叫 beforeEnter 鉤子;
2.在元素上應用 CSS 類 .v-enter;
3.將元素插入 DOM;
4.呼叫 enter 鉤子;
5.應用 .v-enter 類, 然後強制 CSS 佈局以保證 .v-enter 生效;最後移除 .v-enter 來觸發元素過渡到原本的狀態。
6.等待過渡效果執行完畢;
7.呼叫 afterEnter 鉤子。

此外,如果一個正在執行進入的過渡效果的元素在過渡還未完成之前就被移除,則 enterCancelled 鉤子將會被執行。這個鉤子可以用於清理工作,比如移除在 enter 時建立的計時器。對於正在離開過渡中又被重新插入的元素同理。

上述所有的鉤子函式執行時,其 this 都指向相應的 Vue 例項。如果一個元素本身是一個 Vue 例項的根節點,則此例項將被應用為 this;否則 this 指向該過渡指令所屬的例項。

最後,enter 與 leave 鉤子函式可以接受可選的第二個引數:一個回撥函式。當你的函式簽名中含有第二個引數時,即表示你期望使用此回撥來顯式地完成整個過渡過程,而不是依賴 Vue 去自動檢測 CSS 過渡的 transitionend 事件。比如:


enter: function (el) {
// 無第二個引數
// 過渡效果的結束由 CSS 過渡結束事件來決定
}

VS


enter: function (el, done) {
// 有第二個引數
// 過渡效果結束必須由手動呼叫 `done` 來決定
}

當多個元素同時執行過渡效果時,Vue.js 會進行批量處理以保證只觸發一次強制佈局。

CSS 動畫
CSS 動畫通過與 CSS 過渡效果一樣的方式進行呼叫,區別就是動畫中 .v-enter 類並不會在節點插入 DOM 後馬上移除,而是在 animationend 事件觸發時移除。

示例: (省略了相容性字首)

<span v-show=”show” v-transition=”bounce”>Look at me!</span>


.bounce-enter {
animation: bounce-in .5s;
}
.bounce-leave {
animation: bounce-out .5s;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
@keyframes bounce-out {
0% {
transform: scale(1);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(0);
}
}

結果

純 JavaScript 過渡效果
你也可以只使用 JavaScript 鉤子,不定義任何 CSS 過渡規則。當只使用 JavaScript 鉤子時,enter 和 leave 鉤子必須使用 done 回撥,否則它們將會被同步呼叫,過渡將立即結束。下面的示例中我們使用 jQuery 來註冊一個自定義的 JavaScript 過渡效果:


Vue.transition('fade', {
enter: function (el, done) {
// 此時元素已被插入 DOM
// 動畫完成時呼叫 done 回撥
$(el)
.css('opacity', 0)
.animate({ opacity: 1 }, 1000, done)
},
enterCancelled: function (el) {
$(el).stop()
},
leave: function (el, done) {
// 與 enter 鉤子同理
$(el).animate({ opacity: 0 }, 1000, done)
},
leaveCancelled: function (el) {
$(el).stop()
}
})

定義此過渡之後,你就可以通過給 v-transition 指定對應的 ID 來呼叫它:

<p v-transition=”fade”></p>

如果一個只使用 JavaScript 過渡效果的元素恰巧也受到其它 CSS 過渡/動畫規則的影響,這可能會對 Vue 的 CSS 過渡檢測機制產生干擾。碰到這樣的狀況時,你可以通過給你的鉤子物件新增 css: false 來禁止 CSS 檢測。

漸進過渡效果
當同時使用 v-transition 和 v-repeat 時,我們可以為列表元素新增漸進的過渡效果,你只需要為你的過渡元素加上 stagger, enter-stagger 或者 leave-stagger 特性(以毫秒為單位):

<div v-repeat=”list” v-transition stagger=”100″></div>

或者你也可以提供 stagger, enterStagger 或 eaveStagger 鉤子來進行更細粒度的控制:


Vue.transition('stagger', {
stagger: function (index) {
// 為每個過渡元素增加 50ms 的延遲,
// 但是最大延遲為 300ms
return Math.min(300, index * 50)
}
})

示例:

相關文章

前端開發 最新文章