異步更新隊列:
首先我們要對vue的數據更新有一定理解: vue是依靠數據驅動視圖更新的,該更新的過程是異步的。
即:當偵聽到你的數據發生變化時, Vue將開啟一個隊列(該隊列被Vue官方稱為異步更新隊列)。
視圖需要等隊列中所有數據變化完成之后,再統一進行更新。示例:
<div id="App"> <input type="button" value="改變文本" @click="change"> <p ref="myP">{{str}}</p> </div> <script> new Vue({ el:"#App", data:{ str:"我之前很瘦的。" }, methods:{ change(){ this.str = "現在超胖了!"; // 輸出結果:我之前很瘦的。 console.log(this.$refs.myP.innerText) } } }) </script>
通過以上示例的輸出結果可以有力證明:Vue 實現的響應式並不是數據發生變化之后視圖立即變化。
獲取更新之后的DOM
Vue官方為了避免開發者直接接觸視圖,鼓勵大家以"數據驅動"的方式進行思考。但,現在的我們想基於更新后的視圖來搞點事情,該如何下手?
我們可以使用$nextTick(callback)
。這里的回調函數(callback
)將在數據更新完成,視圖更新完畢之后被調用。
更改上個示例中的change方法如下:
change () { this.str = '隱形的翅膀!' this.str = '鋼鐵的翅膀!!' this.$nextTick(() => { // 輸出結果:鋼鐵的翅膀!! console.log(this.$refs.myP.innerText) }) }
從輸出的結果可以看出:我們可以通過$nextTick()
獲取到更新之后的DOM
。
因為 $nextTick()
返回一個 Promise
對象,所以我們也可以使用async/await語法完成相同的事情:
async change () { this.str = '隱形的世邦' this.str = '肖邦的翅膀' await this.$nextTick() console.log(this.$ref.myP.innerText) }
或者
change(){ this.str = "隱形的翅膀"; this.$nextTick().then(()=>{ // 輸出結果:騰格爾的翅膀 console.log(this.$refs.myP.innerText); }); this.str = "騰格爾的翅膀" }
應用場景
1、如果要在created()
鈎子函數中進行的DOM
操作,由於created()
鈎子函數中還未對DOM進行任何渲染,所以無法直接操作,需要通過$nextTick()
來完成。
created () { this.$nextTick(()=>{ this.$refs.myP.innerText = "鋼鐵的翅膀" }) }
注:在created()
鈎子函數中進行的DOM
操作,不使用$nextTick()
會報錯:
// Error in created hook: "TypeError: Cannot set property 'innerText' of undefined" created(){ this.$refs.myP.innerText = "鋼鐵的翅膀" }