實例生命周期:
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
請求的區別:前者頁面視圖未出現,如果請求信息過多,頁面會長時間處于白屏狀態。
單個組件的生命周期
- 初始化組件時,僅執行了
beforeCreate/Created/beforeMount/mounted
四個鉤子函數 - 當改變data中定義的變量(響應式變量)時,會執行
beforeUpdate/updated
鉤子函數 - 當切換組件(當前組件未緩存)時,會執行
beforeDestory/destroyed
鉤子函數 - 初始化和銷毀時的生命鉤子函數均只會執行一次,
beforeUpdate/updated
可多次執行
Vue.nextTick():
在下次
DOM
更新循環結束之后執行延遲回調。在修改數據之后立即使用這個方法,獲取更新后的DOM
。
獲取更新后的DOM
言外之意就是什么操作需要用到了更新后的DOM
而不能使用之前的DOM
或者使用更新前的DOM
會出問題,所以就衍生出了這個獲取更新后的 DOM
的Vue
方法。所以放在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