我們在使用Vue的過程中把注意力都放在了數據操作上,而忽略了關於DOM的一些東西。
場景1:在created生命周期從后端獲取數據后想要對DOM進行操作,發生報錯,當然這時候DOM元素還沒渲染完成怎么會操作成功,但是我就要操作DOM怎么辦?
場景2:使用 swiper 插件通過 ajax 請求圖片后的滑動問題。
首先我們要對vue的數據更新有一定理解: vue是依靠數據驅動視圖更新的,該更新的過程是異步的。即:當偵聽到你的數據發生變化時, Vue將開啟一個隊列(該隊列被Vue官方稱為異步更新隊列)。視圖需要等隊列中所有數據變化完成之后,再統一進行更新。
例如,當你設置 vm.someData = 'new value'
,該組件不會立即重新渲染。當刷新隊列時,組件會在下一個事件循環“tick”中更新。多數情況我們不需要關心這個過程,但是如果你想基於更新后的 DOM 狀態來做點什么,這就可能會有些棘手。雖然 Vue.js 通常鼓勵開發人員使用“數據驅動”的方式思考,避免直接接觸 DOM,但是有時我們必須要這么做。為了在數據變化之后等待 Vue 完成更新 DOM,可以在數據變化之后立即使用 Vue.nextTick(callback)
。
1 <div id="App"> 2 <input type="button" value="改變文本" @click="change"> 3 <p ref="myP">{{str}}</p> 4 </div> 5 <script> 6 new Vue({ 7 el:"#App", 8 data:{ 9 str:"我之前很瘦的。" 10 }, 11 methods:{ 12 change(){ 13 this.str = "現在超胖了!"; 14 //此時DOM 並沒有更新 15 console.log(this.$refs.myP.innerText)// 輸出結果:我之前很瘦的。 16 this.$nextTick(() => { 17 //此時DOM更新了 18 console.log(this.$refs.myP.innerText) // 輸出結果:現在超胖了! 19 }) 20 } 21 } 22 }) 23 </script>
因為 $nextTick()
返回一個 Promise
對象,所以你可以使用新的 ES2017 async/await 語法完成相同的事情:
1 methods:{ 2 change(){ 3 this.str = "現在超胖了!"; 4 console.log(this.$refs.myP.innerText)// 我之前很瘦的。 5 await this.$nextTick() 6 console.log(this.$el.textContent) // 現在超胖了! 7 } 8 } 9
nextTick原理
1、異步說明
Vue 實現響應式並不是數據發生變化之后 DOM 立即變化,而是按一定的策略進行 DOM 的更新
2、事件循環說明
簡單來說,Vue 在修改數據后,視圖不會立刻更新,而是等同一事件循環中的所有數據變化完成之后,再統一進行視圖更新。