Vue nextTick獲取更新後的DOM的實現
前兩天在開發時遇到一個需求:打開對話框的時候自動聚焦其中的輸入框。由於原生的 autofocus 屬性不起作用,需要使用組件庫提供的 focus 方法手動手動獲取焦點。於是有如下代碼:
<el-button @click="openDialog">點擊打開 Dialog</el-button> <el-dialog :visible.sync="dialogVisible"> <el-input v-model="input" ref="input"></el-input> </el-dialog>
methods: { openDialog() { this.dialogVisible = true; const input = this.$refs.input; input.focus(); }, },
結果報錯瞭,原因是沒有獲取到 input 組件;通過 log,也驗證瞭 this.$refs.input 的值確實是 undefined。但是經過測試,如果對話框默認狀態是打開的,就不會報錯;明明組件就在那,為什麼獲取不到呢?
生命周期 update
經過分析,這種現象是由於 Vue 實例的更新機制造成的。從下方的生命周期圖(局部)中可以看出,組件裝載好之後,遇到數據變化時將重新渲染虛擬 DOM(可以理解為 HTML 中的組件節點)。在本例中,隱藏的 Dialog 組件(以及其中的 input 組件)本來並沒有渲染在 DOM 中,是在觀察到 dialogVisible 屬性變為 true 後再進行更新渲染的。
而網頁渲染通常是一個異步任務,因此在 visible 屬性剛剛更改時(一個函數中是同步過程),DOM 渲染還沒有進行,因此自然獲取不到此時還不存在的 input 組件瞭。
關於異步、JS任務隊列、宏任務與微任務等概念的更多介紹,可參考博文JS多線程:任務隊列
為瞭更直觀地展示這個過程,可以在更新前後的鉤子函數中試圖獲取組件並進行打印:
beforeUpdate() { console.log("beforeUpdate"); const input = this.$refs.input; console.log(input); }, updated() { console.log("updated"); const input = this.$refs.input; console.log(input); }, methods: { openDialog() { this.dialogVisible = true; console.log("click open"); }, },
結果如下,可以驗證之前的分析和猜想:
click open
beforeUpdate
undefined
updated
VueComponent {…}
Vue.nextTick
為瞭解決這個問題,Vue 提供瞭全局 api Vue.nextTick(),它的作用是提供下次 DOM 更新之後的回調。也就是說,在更新數據後調用 api,就能夠獲取到重新渲染後的 DOM 並進行相關操作。
nextTick 方法可以廣泛適用於各種需要在數據更新後對相關 DOM 進行操作的情景,例如 v-if 、watch 等。
在上文的例子中再加入 nextTick:
openDialog() { this.dialogVisible = true; console.log("click open"); this.$nextTick(function () { console.log("next tick"); const input = this.$refs.input; console.log(input); input.focus(); }); },
可以看到,回調確實是在 DOM 更新之後,也就是 updated 執行之後才執行的。獲取組件與手動獲得焦點的操作也能夠正確執行瞭。
click open
beforeUpdate
undefined
updated
VueComponent {…}
next tick
VueComponent {…}
Promise
如果沒有提供回調參數,並且瀏覽器支持 Promise,調用 nextTick 將返回一個 Promise。也就是說下面幾種寫法是等價的(環境支持的情況下):
Vue.nextTick(function () {...}) Vue.nextTick(() => {...}) Vue.nextTick().then(function () {...}) Vue.nextTick().then(() => {...})
關於 Promise 的介紹和用法,可以參考博文 JS Promise。
結語&參考資料
以上是個人對 Vue 中 nextTick api 的一些理解與思考,希望能給你提供幫助。如果有問題或疏漏之處,歡迎在評論中討論與指正。
參考資料:
Vue 文檔 – api
Vue 文檔 – 實例
到此這篇關於Vue nextTick獲取更新後的DOM的實現的文章就介紹到這瞭,更多相關Vue nextTick獲取更新後的DOM內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Vue2 Dialog彈窗函數式調用實踐示例
- Vue中的nextTick作用和幾個簡單的使用場景
- Vue常用API、高級API的相關總結
- 一篇文章教你實現VUE多個DIV,button綁定回車事件
- vue+el-element中根據文件名動態創建dialog的方法實踐