Vue生命周期與Vue.nextTick()

實例生命周期:

https://segmentfault.com/a/1190000008570622.jpg

image.png

  • beforeCreate:在實例初始化之后,數據觀測data observer(props、data、computed) 和 event/watcher 事件配置之前被調用。
  • created:實例已經創建完成之后被調用。在這一步,實例已完成以下的配置:數據觀測(data observer),屬性和方法的運算, watch/event 事件回調。然而,掛載階段還沒開始,$el 屬性目前不可見。
  • beforeMount:在掛載開始之前被調用:相關的 render 函數首次被調用。
  • mounted: el 被新創建的 vm.$el 替換,并掛載到實例上去之后調用該鉤子。
  • beforeUpdate:數據更新時調用,發生在虛擬 DOM 重新渲染和打補丁之前。 你可以在這個鉤子中進一步地更改狀態,這不會觸發附加的重渲染過程。
  • updated:無論是組件本身的數據變更,還是從父組件接收到的 props 或者從vuex里面拿到的數據有變更,都會觸發虛擬 DOM 重新渲染和打補丁,并在之后調用 updated
  • beforeDestroy:實例銷毀之前調用。在這一步,實例仍然完全可用。
  • destroyed:Vue 實例銷毀后調用。調用后,Vue 實例指示的所有東西都會解綁定,所有的事件監聽器會被移除,所有的子實例也會被銷毀。 該鉤子在服務器端渲染期間不被調用。

注意:
created階段的ajax請求與mounted請求的區別:前者頁面視圖未出現,如果請求信息過多,頁面會長時間處于白屏狀態。

單個組件的生命周期

  1. 初始化組件時,僅執行了beforeCreate/Created/beforeMount/mounted四個鉤子函數
  2. 當改變data中定義的變量(響應式變量)時,會執行beforeUpdate/updated鉤子函數
  3. 當切換組件(當前組件未緩存)時,會執行beforeDestory/destroyed鉤子函數
  4. 初始化和銷毀時的生命鉤子函數均只會執行一次,beforeUpdate/updated可多次執行

Vue.nextTick():

在下次 DOM 更新循環結束之后執行延遲回調。在修改數據之后立即使用這個方法,獲取更新后的 DOM

獲取更新后的DOM言外之意就是什么操作需要用到了更新后的DOM而不能使用之前的DOM或者使用更新前的DOM會出問題,所以就衍生出了這個獲取更新后的 DOMVue方法。所以放在Vue.nextTick()回調函數中的執行的應該是會對DOM進行操作的 js代碼,比如Swiper擴展包的:

var swiper = new Swiper('.swiper-container', {
                    pagination: '.swiper-pagination',
                    nextButton: '.swiper-button-next',
                    prevButton: '.swiper-button-prev',
                    paginationClickable: true,
                    spaceBetween: 30,
                    centeredSlides: true,
                    autoplay: 2500,
                    autoplayDisableOnInteraction: false
});

什么時候需要用Vue.nextTick():

  • 你在Vue生命周期的created()鉤子函數進行的DOM操作一定要放在Vue.nextTick()的回調函數中。原因是什么呢,原因是在created()鉤子函數執行的時候DOM 其實并未進行任何渲染,而此時進行DOM操作無異于徒勞,所以此處一定要將DOM操作的js代碼放進Vue.nextTick()的回調函數中。與之對應的就是mounted鉤子函數,因為該鉤子函數執行時所有的DOM掛載和渲染都已完成,此時在該鉤子函數中進行任何DOM操作都不會有問題 。
  • 在數據變化后要執行的某個操作,當你設置 vm.someData = 'new value'DOM并不會馬上更新,而是在異步隊列被清除,也就是下一個事件循環開始時執行更新時才會進行必要的DOM更新。如果此時你想要根據更新的 DOM 狀態去做某些事情,就會出現問題。。為了在數據變化之后等待 Vue 完成更新 DOM ,可以在數據變化之后立即使用 Vue.nextTick(callback) 。這樣回調函數在 DOM 更新完成后就會調用。
  • mounted 不會承諾所有的子組件也都一起被掛載。如果你希望等到整個視圖都渲染完畢,可以用 vm.$nextTick 替換掉 mounted
mounted: function () {
this.$nextTick(function () {

// Code that will run only after the
// entire view has been rendered
})
}

2021.9.7補充:為什么nextTick里的代碼會在DOM更新后執行
先看一段代碼:

this.$nextTick(() => {
  console.log('獲取最新dom1:', this.$refs.con) // 1
  // debugger
})
this.value++  // 2 這里實際上會執行 watcher.run()
this.$nextTick(() => {
  console.log('獲取最新dom2:', this.$refs.con)  // 3
  // debugger
})

打印結果如下:


但是如果把this.value++和第一個nextTick調換位置,兩個nextTick都能獲取到最新的dom了。是什么原因,我們來從vue的源碼分析一下:
this.value++ -> 觸發set函數 -> 通知依賴更新: dep.notify() -> 調用 watcher.update() -> watcher.run()放在vue的nextTick函數中執行 -> flushCallbacks調用隊列中的所有cb,執行順序為1、2、3 -> 執行到2的時候調用_render 、_update、patch更新dom
所以執行到1的時候dom是沒有進行更新的,因此打印的也是沒有更新的dom,執行到2的時候已經完成了patch,dom更新了,因此拿到的是新的dom。
這個流程走完后,vue替換掉了老的dom節點,這時候dom樹已經是新的了,所以在JS中獲取dom數據也是新的,但是視圖不一定更新了,因為不一定完成了繪制(這個正確性還有待考證)。

參考文章:
https://mp.weixin.qq.com/s/4ukhHAcMQN07y0ssYqUeuA
https://segmentfault.com/a/1190000008570622
https://segmentfault.com/a/1190000008570874

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容