Vue父子組件生命周期執行順序及鉤子函數的個人理解

来源:https://www.cnblogs.com/yuliangbin/archive/2018/08/11/9348156.html
-Advertisement-
Play Games

先附一張官網上的vue實例的生命周期圖,每個Vue實例在被創建的時候都需要經過一系列的初始化過程,例如需要設置數據監聽,編譯模板,將實例掛載到DOM併在數據變化時更新DOM等。同時在這個過程中也會運行一些叫做生命周期鉤子的函數(回調函數),這給了用戶在不同階段添加自己代碼的機會。 1、vue的生命周 ...


先附一張官網上的vue實例的生命周期圖,每個Vue實例在被創建的時候都需要經過一系列的初始化過程,例如需要設置數據監聽,編譯模板,將實例掛載到DOM併在數據變化時更新DOM等。同時在這個過程中也會運行一些叫做生命周期鉤子的函數(回調函數),這給了用戶在不同階段添加自己代碼的機會。

1、vue的生命周期圖

 

在vue實例的整個生命周期的各個階段,會提供不同的鉤子函數以供我們進行不同的操作。先列出vue官網上對各個鉤子函數的詳細解析。

生命周期鉤子    

詳細
beforeCreate 在實例初始化之後,數據觀測(data observer) 和 event/watcher 事件配置之前被調用。
created 實例已經創建完成之後被調用。在這一步,實例已完成以下的配置:數據觀測(data observer),屬性和方法的運算, watch/event 事件回調。然而,掛載階段還沒開始,$el 屬性目前不可見。
beforeMount 在掛載開始之前被調用:相關的 render 函數首次被調用。
mounted el 被新創建的 vm.$el 替換,並掛載到實例上去之後調用該鉤子。如果 root 實例掛載了一個文檔內元素,當 mounted 被調用時 vm.$el 也在文檔內。
beforeUpdate 數據更新時調用,發生在虛擬 DOM 重新渲染和打補丁之前。你可以在這個鉤子中進一步地更改狀態,這不會觸發附加的重渲染過程。
updated 由於數據更改導致的虛擬 DOM 重新渲染和打補丁,在這之後會調用該鉤子。當這個鉤子被調用時,組件 DOM 已經更新,所以你現在可以執行依賴於 DOM 的操作。
activated keep-alive 組件激活時調用。
deactivated keep-alive 組件停用時調用。
beforeDestroy 實例銷毀之前調用。在這一步,實例仍然完全可用。
destroyed Vue 實例銷毀後調用。調用後,Vue 實例指示的所有東西都會解綁定,所有的事件監聽器會被移除,所有的子實例也會被銷毀。

2、實際操作 

下麵我們在實際的代碼執行過程中理解父子組件生命周期創建過程以及鉤子函數執行的實時狀態變化。

測試基於下麵的代碼,引入vue.js文件後即可執行。(打開頁面後,再按一次刷新會自動進入debugger狀態)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        
    </style>
</head>   
<body>
<div id="app">
    <p>{{message}}</p>
    <keep-alive>
        <my-components :msg="msg1" v-if="show"></my-components>
    </keep-alive>
</div>
</body>
<script src="../../node_modules/vue/dist/vue.js"></script>
<script>
    var child = {
        template: '<div>from child: {{childMsg}}</div>',
        props: ['msg'],
        data: function() {
            return {
                childMsg: 'child'
            }   
        },
        beforeCreate: function () {
            debugger;
        },
        created: function () {
            debugger;
        },
        beforeMount: function () {
            debugger;
        },
        mounted: function () {
            debugger;
        },
        deactivated: function(){
            alert("keepAlive停用");
        },
        activated: function () {
            console.log('component activated');
        },
        beforeDestroy: function () {
            console.group('beforeDestroy 銷毀前狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(this.$el);
            console.log(state);
        },
        destroyed: function () {
            console.group('destroyed 銷毀完成狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(this.$el);
            console.log(state);
        },
    };
    var vm = new Vue({
        el: '#app',
        data: {
                message: 'father',
                msg1: "hello",
                show: true
            },
        beforeCreate: function () {
            debugger;
        },
        created: function () {
            debugger;
        },
        beforeMount: function () {
            debugger;
        },
        mounted: function () {
            debugger;    
        },
        beforeUpdate: function () {
            alert("頁面視圖更新前");
            
        },
        updated: function () {
            alert("頁面視圖更新後");
        },
        beforeDestroy: function () {
            console.group('beforeDestroy 銷毀前狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(this.$el);
            console.log(state);
        },
        destroyed: function () {
            console.group('destroyed 銷毀完成狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(this.$el);
            console.log(state);
        },
        components: {
            'my-components': child
        }
    });
</script>
</html>

3.1、生命周期調試

首先我們創建了一個Vue實例vm,將其掛載到頁面中id為“app”的元素上。

3.1.1、根組件的beforeCreate階段

可以看出,在調用beforeCreate()函數時,只進行了一些必要的初始化操作(例如一些全局的配置和根實例的一些屬性初始化),此時data屬性為undefined,沒有可供操作的數據。

3.1.2、根組件的Created階段

調用Created()函數,在這一步,實例已完成以下的配置:數據代理和動態數據綁定(data observer),屬性和方法的運算, watch/event 事件回調。然而,掛載階段還沒開始,$el 屬性目前不可見。

3.1.3、根組件的beforeMount階段

在調用boforeMount()函數前首先會判斷對象是否有el選項。如果有的話就繼續向下編譯,如果沒有el選項,則停止編譯,也就意味著停止了生命周期,直到在該vue實例上調用vm.$mount(el)

在這個例子中,我們有el元素,因此會調用boforeMount()函數,此時已經開始執行模板解析函數,但還沒有將$el元素掛載頁面,頁面視圖因此也未更新。在標紅處,還是 {{message}},這裡就是應用的 Virtual DOM(虛擬Dom)技術,先把坑占住了。到後面mounted掛載的時候再把值渲染進去。

3.1.4、子組件的beforeCreate、Created、beforeMount、Mounted階段

在父組件執行beforeMount階段後,進入子組件的beforeCreate、Created、beforeMount階段,這些階段和父組件類似,按下不表。beforeMount階段後,執行的是Mounted階段,該階段時子組件已經掛載到父組件上,並且父組件隨之掛載到頁面中。

由下圖可以知道,在beforeMount階段之後、Mounted階段之前,數據已經被載入到視圖上了,即$el元素被掛載到頁面時觸發了視圖的更新

3.1.5、子組件的activated階段

 我們發現在子父組件全部掛載到頁面之後被觸發。這是因為子組件my-components被<keep-alive> 包裹,隨$el的掛載被觸發。如果子組件沒有被<keep-alive>包裹,那麼該階段將不會被觸發。

3.1.6、父組件的mounted階段

mounted執行時:此時el已經渲染完成並掛載到實例上。

至此,從Vue實例的初始化到將新的模板掛載到頁面上的階段已經完成,退出debugger。下麵我們來看一下deactivated、beforeUpdate、updated、beforeDestroy、destroyed鉤子函數。

3.2、deactivated、beforeUpdate、updated階段

由生命周期函數可知:當數據變化後、虛擬DOM渲染重新渲染頁面前會觸發beforeUpdate()函數,此時視圖還未改變。當虛擬DOM渲染頁面視圖更新後會觸發updated()函數。

 

我們不妨改變vm.show = false,當修改這個屬性時,不僅會觸發beforeUpdate、updated函數,還會觸發deactivated函數(因為keep-alive 組件停用時調用)。我們不妨想一下deactivated函數會在beforeUpdate後還是updated後調用。

我們在控制台輸入vm.show = false。得到三者的調用順序分別為beforeUpdate、deactivated、updated。我們可以知道的是deactivated函數的觸發時間是在視圖更新時觸發。因為當視圖更新時才能知道keep-alive組件被停用了。

3.3、beforeDestroy和destroyed鉤子函數間的生命周期

現在我們對Vue實例進行銷毀,調用app.$destroy()方法即可將其銷毀,控制台測試如下:

 

我們發現實例依然存在,但是此時變化已經發生在了其他地方。

beforeDestroy鉤子函數在實例銷毀之前調用。在這一步,實例仍然完全可用。

destroyed鉤子函數在Vue 實例銷毀後調用。調用後,Vue 實例指示的所有東西都會解綁定,所有的事件監聽器會被移除,所有的子實例也會被銷毀(也就是說子組件也會觸發相應的函數)。這裡的銷毀並不指代'抹去',而是表示'解綁'。

銷毀時beforeDestory函數的傳遞順序為由父到子,destory的傳遞順序為由子到父。

4、一些應用鉤子函數的想法

  • 在created鉤子中可以對data數據進行操作,這個時候可以進行ajax請求將返回的數據賦給data。
  • 雖然updated函數會在數據變化時被觸發,但卻不能準確的判斷是那個屬性值被改變,所以在實際情況中用computed或match函數來監聽屬性的變化,並做一些其他的操作。
  • 在mounted鉤子對掛載的dom進行操作,此時,DOM已經被渲染到頁面上。
  • 在使用vue-router時有時需要使用<keep-alive></keep-alive>來緩存組件狀態,這個時候created鉤子就不會被重覆調用了,如果我們的子組件需要在每次載入或切換狀態的時候進行某些操作,可以使用activated鉤子觸發。
  • 所有的生命周期鉤子自動綁定 this 上下文到實例中,所以不能使用箭頭函數來定義一個生命周期方法 (例如 created: () => this.fetchTodos())。這是導致this指向父級。

5、 小結

  • 載入渲染過程

  父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

  • 子組件更新過程

  父beforeUpdate->子beforeUpdate->子updated->父updated

  • 父組件更新過程

  父beforeUpdate->父updated

  • 銷毀過程

  父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

6、參考文章

關於Vue.js2.0生命周期的研究與理解

Vue2.0 探索之路——生命周期和鉤子函數的一些理解

 

PS:如果文章對您有一些幫助,歡迎點擊推薦,您的推薦是我不斷輸出的動力!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.js的數據類型: Number、Boolean、String、Undefined、Null、Symbol(es6新定義的)和Object(ps:Array是特殊的Object) typeof返回6種類型:number boolean string object undefined functio ...
  • 眾所周知,可以通過設置background-repeat的值來改變背景圖片的重覆次數。但有一個問題,background-repeat的值不是讓圖片只有1個,就是讓圖片鋪滿。如果只想設置給定數量的圖片該怎麼辦?以2個為例,請看代碼: 這樣,就實現了<h1>元素的最左邊有一個logo.jpg、最右邊也 ...
  • 一.不可改變的原始值(棧數據)(五個) 數字(number),字元串(string),布爾值(boolean),undefined,null 其中;undefined是未定義的意思,而null是空的意思,他們倆的區別在於,null有值,不過這個值是空值,而undefined是未定義,完全沒有值的意思 ...
  • 遞歸演算法: 優點:代碼簡潔、清晰,並且容易驗證正確性。 缺點: 1、它的運行需要較多次數的函數調用,如果調用層數比較深,每次都要創建新的變數,需要增加額外的堆棧處理,會對執行效率有一定影響,占用過多的記憶體資源。 2、遞歸演算法解題的運行效率較低。在遞歸調用的過程中系統為每一層的返回點、局部變數等開闢了 ...
  • 1、DOM0級事件和DOM2級事件 DOM 0級事件是元素內的一個私有屬性:div.onclick = function () {},對一個私有屬性賦值(在該事件上綁定一個方法)。由此可知DOM 0級事件只能給元素的某一個行為綁定一次方法,第二次綁定會把前面的覆蓋掉。 DOM 2級事件是讓DOM元素 ...
  • 一.Yeoman是什麼 是現代化前端項目的腳手架工具,用於生成包含指定框架結構的工程化目錄結構。它是整個前端自動化工廠的第一站。 從個人使用者的角度來看, 的地位有些雞肋,因為流行框架自帶的 工具都能夠自動生成官方推薦的目錄結構,而且一個項目持續少則幾個月多則幾年,而項目的初始化結構目錄在此期間只需 ...
  • CSS選擇器總結: (這些表是一張圖片^_^) 看底部 完整思維導圖圖片和表格的下載地址:https://download.csdn.net/download/denlnyyr/10597820 (我不想選擇要積分幣下載的,但那裡最低必須選擇1個積分……) 參考文獻: https://baike.b ...
  • 看到一個知識點,比如說給一個 url參數,讓其解析裡面的各個參數,以前我都是通過字元串分割來實現的。但是通過這樣的方式比較麻煩,而且操作字元串容易出錯。今天看到了一個更有效更快速的方式,就是通過對象來解析的。 比如我們的url是:https://www.baidu.com:8080/aaa/1.ht ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...