vue生命周期(lifecycle)以及對nextTick的理解


  每個Vue實例在被創建的時候,都會經歷一系列初始化的過程。比如說需要設置數據監聽、模板編譯、將實例掛載到DOM結構上並且在數據變化時對DOM結構進行更新等等。Vue允許開發者在不同的生命周期運行一些鈎子函數(hook),給開發者在不同的生命周期中添加自己代碼的機會。所有的生命周期鈎子自動綁定 this 上下文到實例中,因此你可以訪問數據,對屬性和方法進行運算,這也意味着我們不能夠用箭頭函數來定義生命周期函數。ok,生命周期的定義就到這里,下面看一下vue具體有哪些生命周期,以及再不同的生命周期里面會發生什么事情。

  官方給的生命周期鈎子函數如下:

  #beforeCreate

  #created

  #beforeMount

  #mounted

  #beforeUpdate

  #updated

  #beforeDestroy

  #destroyed

  #errorCaptured

  #activated

  #deactivated

  在這里鈎子函數里面,着重看前八個,后面三個在實際開發中基本涉及不到,如果有興趣了解可移步到官方文檔https://cn.vuejs.org/v2/api/#%E9%80%89%E9%A1%B9-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90

 1 var vm = {
 2     el: '#app',
 3     data: {
 4         message: 'hello world.'
 5     },
 6     beforeCreate: function() {
 7         // 在實例初始化之后,數據觀測 (data observer) 和 event/watcher 事件配置之前被調用。
 8         // 在這個生命周期里,vue實例還只是空殼,數據和dom結構都還沒有加載
 9         console.log(this.message);  // undefined
10     },
11     created: function() {
12         // 在實例創建完成后被立即調用。在這一步,實例已完成以下的配置:數據觀測 (data observer),屬性和方法的運算,watch/event 事件回調。然而,掛載階段還沒開始,$el 目前不可見。
13         // 在這個生命周期里,數據已經加載完成,並且在這里面修改數據並不會出發update函數。
14         // 一般情況下會在這里面做一些異步數據的獲取,比如說從服務器獲取數據到本地。
15         console.log(this.message);  // 'hello world'
16     },
17     beforeMount: function() {
18         // 在掛載開始之前被調用:相關的 render 函數首次被調用。
19         // 在這里面,虛擬DOM已經加載完畢,但是對應的真實DOM還未加載,在這里面是獲取不到真實DOM結點的。
20         // 接下來執行render,加載真實DOM。
21         // 在這里面進行數據修改依舊不會觸發update函數。
22     },
23     mounted: function() {
24         // 在這里面,真實DOM、數據、事件處理已經加載完畢,可以進行對應的修改。
25         // 從這里開始進行數據修改都會觸發update函數。
26     },
27     beforeUpdate: function() {
28         // 數據更新時調用,發生在虛擬 DOM 打補丁之前。這里適合在更新之前訪問現有的 DOM,比如手動移除已添加的事件監聽器。
29         // 這個沒啥好說的,在數據修改(或者說要重新進行渲染)的時候會觸發的鈎子函數。
30         // 值得注意的是,千萬不要在這里面進行數據修改,否則會陷入死循環!道理你自己思考一下就知道為什么了!
31 
32     },
33     updated: function() {
34         // 由於數據更改導致的虛擬 DOM 重新渲染和打補丁,在這之后會調用該鈎子。
35         // 當這個鈎子被調用時,組件 DOM 已經更新,所以你現在可以執行依賴於 DOM 的操作。然而在大多數情況下,你應該避免在此期間更改狀態。如果要相應狀態改變,通常最好使用計算屬性或 watcher 取而代之。
36         // 同樣的,在數據修改完畢之后會調用的鈎子函數。
37         // 在這里面一樣不能進行數據修改!!!謹記!!!
38         
39     },
40     beforeDestroy: function() {
41         // 實例銷毀之前調用。在這一步,實例仍然完全可用。
42         // 銷毀前執行(手動使用$destroy方法被調用的時候就會執行),一般在這里善后:清除計時器、清除非指令綁定的事件等等。
43     },
44     destroyed: function() {
45         // Vue 實例銷毀后調用。調用后,Vue 實例指示的所有東西都會解綁定,所有的事件監聽器會被移除,所有的子實例也會被銷毀。
46         // 組件的數據綁定、監聽...都去掉了,只剩下dom空殼,這里也可以善后。
47     }
48 }

  上面我們說到,在發生數據修改的時候都會觸發beforeUpdate和updated這兩個鈎子函數,但是如果要對特定的修改執行update函數就會變得很麻煩。官方為此提供了另外一種解決辦法,那就是$nextTick。$nextTick()是在下次 DOM 更新循環結束之后執行延遲回調,可以在修改數據之后立即使用這個方法,獲取更新后的 DOM。簡單的理解是:當數據更新了,在dom中渲染后,自動執行該函數。下面舉個簡單的例子:

 1 <template>
 2   <div>
 3     <span ref="span">{{ message }}</span>
 4   </div>
 5 </template>
 6  
 7 <script>
 8 export default {
 9   name: 'test',
10   data () {
11     return {
12       message: "初始值"
13     }
14   },
15   methods:{
16     changeMsg: function(){
17       this.message =  "修改后的值";
18       console.log(this.$refs.span.innerText);   //原始值
19     }
20   },
21   created() {
22       this.changeMsg();
23   }
24 }
25 </script>

  這是因為在修改完message之后,尚未執行update函數,對應的DOM結構還未發生改變。使用nextTick稍作修改:

 1 <template>
 2   <div>
 3     <span ref="span">{{ message }}</span>
 4   </div>
 5 </template>
 6  
 7 <script>
 8 export default {
 9   name: 'test',
10   data () {
11     return {
12       message: "初始值"
13     }
14   },
15   methods:{
16     changeMsg: function(){
17       this.message =  "修改后的值";
18       this.$nextTick(function(){
19         console.log(that.$refs.span.innerText);  //修改后的值
20       });
21 
22     }
23   },
24   created() {
25       this.changeMsg();
26   }
27 }
28 </script>
29  

  因此,在某些有特殊需求的情況下,是可以使用nextTick來代替update進行使用的。那么什么情況下需要使用到nextTick()呢?

  一、需要在created()鈎子函數進行的DOM操作。因為在created()鈎子函數執行時,真實DOM 並未進行任何渲染,而此時進行DOM操作無異於徒勞,所以此處一定要將DOM操作的js代碼放進nextTick()的回調函數中。與之對應的就是mounted鈎子函數,因為該鈎子函數執行時所有的DOM掛載已完成。

  二、需要在改變DOM之后基於新的DOM做點什么,對新DOM一系列的js操作都需要放進nextTick()的回調函數中。

Vue.nextTick(callback)的原理:

  Vue是異步執行dom更新的,一旦觀察到數據變化,Vue就會開啟一個隊列,然后把在同一個事件循環 (event loop) 當中觀察到數據變化的 watcher 推送進這個隊列。如果這個watcher被觸發多次,只會被推送到隊列一次。這種緩沖行為可以有效的去掉重復數據造成的不必要的計算和DOM操作。而在下一個事件循環時,Vue會清空隊列,並進行必要的DOM更新。
  當你設置 vm.data = 'new value',DOM 並不會馬上更新,而是在異步隊列被清除,也就是下一個事件循環開始時執行更新時才會進行必要的DOM更新。如果此時你想要根據更新的 DOM 狀態去做某些事情,就會出現問題。為了在數據變化之后等待 Vue 完成更新 DOM ,可以在數據變化之后立即使用 Vue.nextTick(callback) 。這樣回調函數在 DOM 更新完成后就會調用。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM