作者:Chimezie Enyinnaya
譯者:前端小智
來源:blog
有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。
本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。
一個前端開發人員(小智)走進了一個Vue酒吧。小智點了他最喜歡的雞尾酒:Nuxt。酒保正在努力製作中。然後他自己就嘮叨了起來。
小智講述了他是如何在Vue 3的例項方法下發現$nextTick
的,並大吃一驚。小智
使用Vue已經有一段時間了,他已經習慣了把$watch
和$emit
寫成例項方法。那麼,$nextTick是用來做什麼的?Vue文件說,它"[defers]回撥,在下一個DOM更新週期後執行"。
但是小智並不相信。
他繼續講述他是如何嘗試這樣做的:
this.loadingAnimation = true
this.startVeryLongCalculation()
this.completeVeryLongCalculation()
this.loadingAnimation = false
有用。 為什麼?
nextTick做什麼?
nextTick
接受一個延遲到下一個DOM更新週期的回撥函式。這只是Vue的一種說法,"嘿,如果你想在DOM更新後執行一個函式(這種情況很少發生),我希望你使用nextTick
而不是setTimeout
"。
Vue.nextTick(() => {}) // syntax
下面很快就會講到setTimeout
和nextTick
引數。我們用這個例子來視覺化nextTick
的行為:
<template>
<div>
{{ currentTime }}
</div>
</template>
<script>
export default {
name: 'getCurrentTime',
data() {
return {
currentTime: ''
}
},
mounted() {
this.currentTime = 3;
this.$nextTick(() => {
let date = new Date()
this.currentTime = date.getFullYear()
});
}
}
</script>
在J電腦上執行這個程式碼片段。它將顯示2021
年。並不是說如果你去掉nextTick
,就不會得到同樣的結果。然而,你應該明白,Vue會根據資料中的內容對DOM進行修改。
在上面的程式碼片段中,Vue將DOM更新為3
,然後呼叫回撥,將DOM更新為2021
,最後將控制權交給瀏覽器,瀏覽器將顯示2021
。
到目前為止,我們已經研究了nextTick在回撥佇列中插入回撥函式並在適當的時候執行該函式。
這個你可能會感興趣,nextTick
中的回撥是作為事件迴圈中的一個微任務使用的。nextTick
的原始碼明確指出,"nextTick
行為利用了微任務佇列,可以通過本地的Promise.then
或MutationObserver
來訪問。"
setTimeout vs nextTick
在DOM更新後執行函式的另一種方法是使用JavaScript的setTimeout()
函式。
我們將上面的程式碼用setTimeout
替換nextTick
:
<template>
<div>
{{ currentTime }}
</div>
</template>
<script>
export default {
name: 'getCurrentTime',
data() {
return {
currentTime: ''
}
},
mounted() {
this.currentTime = 3;
setTimeout(() => {
let date = new Date()
this.currentTime = date.getFullYear()
}, 0);
}
}
</script>
執行此程式碼片段。 首先看到3
然後2021
。它發生得很快,因此如果沒有看到此行為,需要重新整理瀏覽器。
在上面的程式碼片段中,Vue將DOM更新為3
,並提供瀏覽器控制。然後瀏覽器顯示3
,呼叫回撥函式,將DOM更新到2021
,最後將控制權交給瀏覽器,現在瀏覽器顯示2021
。
nextTick
的實現在不支援Promise
和MutationObserver
的瀏覽器(IE 6-10和Opera Mini瀏覽器)上,使用setTimeout
作為後備方法,對於不支援Promise
和MutationObserver
的瀏覽器(IE 10),它更傾向於setImmediate
。
何時使用 nexttick
- 當你想使用
setTimeout
時 - 當你想確定DOM能反映你的資料時
- 在嘗試執行非同步操作時,遇到
Uncaught (in promise) DOMException
等錯誤。記住,Vue是非同步更新DOM的
最後來個示例:
<div id="app">
<div ref="listScroll" class="scrolledList">
<ul ref="scrolledHeight">
<li v-for="month in months">
{{month}}
</li>
</ul>
</div>
<input type="text" placeholder="Add Month" v-model="month">
<button @click="addMessage" @keyup.enter="addMessage"> Add Month</button>
</div>
<script src="https://unpkg.com/vue@next">
Vue.createApp({
data() {
return {
month: '',
months: ['Jan', 'Feb', 'Apr', 'May', 'June', 'July', 'Aug']
}
},
mounted() {
this.updateScrollNextTick()
},
methods: {
addMessage() {
if(this.month == ''){
return
}
this.months.push(this.month)
this.month = ''
this.updateScrollNextTick()
},
updateScrollNextTick () {
let scrolledHeight = this.$refs.scrolledHeight.clientHeight
this.$nextTick(() => {
this.$refs.listScroll.scrollTo({
behavior: 'smooth',
top: scrolledHeight
})
})
}
},
})
.mount("#app")
</script>
示例地址:https://codepen.io/ammezie/pe...
主要部分:
執行結果:
在上面的程式碼片斷中,我們想在一個新專案被新增到列表中時獲得平滑的向下滾動效果。瀏覽一下程式碼,嘗試修改一下,去掉nextTick
,你就會失去那種平滑的滾動效果。你也可以嘗試用setTimeout
來代替nextTick
。
總結
在本文中,我們探索了nextTick是如何工作的。我們進一步瞭解了它與普通的JavaScript setTimeout的不同之處,並介紹了實際的用例。
~完,我是小智,準備去教育一個前端小妹。
編輯中可能存在的bug沒法實時知道,事後為了解決這些bug,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug。
原文:https://blog.logrocket.com/un...
交流
文章每週持續更新,可以微信搜尋【大遷世界 】第一時間閱讀,回覆【福利】有多份前端視訊等著你,本文 GitHub https://github.com/qq449245884/xiaozhi 已經收錄,歡迎Star。