一、前言
在之前的 Vue 學習中,我們在使用 Vue 時,都會創建一個 Vue 的實例,而每個 Vue 實例在被創建時都要經過一系列的初始化過程。例如,需要設置數據監聽、編譯模板、將實例掛載到 DOM 並在數據變化時更新 DOM 等。在這個過程中,Vue 會運行一些生命周期鈎子函數,而我們則可以在鈎子函數中編寫一些自定義方法,用以在 Vue 的整個生命周期中某些階段實現我們特殊需求。那么,本章,我們就來了解 Vue 實例的生命周期鈎子函數。
學習系列目錄地址:https://www.cnblogs.com/danvic712/p/9549100.html
倉儲地址:https://github.com/Lanesra712/VueTrial/blob/master/Chapter01-Rookie/hocks.html
二、干貨合集
在我們使用 Vue 的時候,都會先創建一個 Vue 實例,這個實例不僅是我們掛載 Vue 框架的入口,也是 MVVM 思想中的 VM(ViewModel)。在我們使用 Vue 的整個過程中,歸根結底都是在對這個 Vue 實例進行操作。因此,只有當我們了解 Vue 實例的生命周期之后,才可以更好的實現我們的業務邏輯。
在 Vue 官網的這張生命周期圖示中,我們可以看到整個生命周期中包含了8個鈎子函數:beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed。從字面意思我們就可以清楚的看出來,這8個鈎子函數兩個一組,分別對應於 Vue 實例的創建、掛載、更新、銷毀,接下來,我們就根據這四個階段,解釋 Vue 實例各個階段中的鈎子函數的作用。
1、beforeCreate & created
在我們通過 new Vue() 創建了一個 Vue 實例之后,會執行 init 方法,此時只會初始化 Vue 實例所包含的一些默認的事件與生命周期函數,在這個實例還未被完全創建之前,則會執行我們的 beforeCreate 鈎子函數。
在下面的例子中,我們在實例化 Vue 對象時,自定義了一個 message 屬性,同時設定了一個 show 方法,現在我們來看看當實例並沒有完全被創建之前,是否能夠獲取到我們自定義的屬性與方法。
<div id="app"> {{message}} </div> <script> var vm = new Vue({ el: '#app', data: { message: 'Hello World!' }, methods: { show() { console.log('執行了 show 方法'); } }, beforeCreate() { console.log(`Vue 實例掛載對象 el:${this.$el}`) console.log(`Vue 實例的 data 對象:${this.$data}`) console.log(`Vue 實例的 message 屬性值:${this.message}`) console.log(`Vue 實例的 methods 對象:${this.$options.methods}`) this.show(); } }) </script>
從瀏覽器的控制台中我們可以看到,此時,Vue 實例中的 data、methods 對象,或是我們定義的 Vue 實例的掛載點元素,在 beforeCreated 生命周期鈎子函數執行時,都沒有進行了初始化。
當 beforeCreated 鈎子函數執行完成后,Vue 實例已經初始化完成,此時將要執行生命周期中的 created 鈎子函數來監聽我們對於數據的更改或是監聽事件。
<div id="app"> {{message}} </div> <script> var vm = new Vue({ el: '#app', data: { message: 'Hello World!' }, methods: { show() { console.log('執行了 show 方法'); } }, created() { console.log(`Vue 實例掛載對象 el:${this.$el}`) console.log(`Vue 實例的 data 對象:${this.$data}`) console.log(`Vue 實例的 message 屬性值:${this.message}`) console.log(`Vue 實例的 methods 對象:${this.$options.methods}`) this.show(); } }) </script>
從瀏覽器控制台打印出的信息可以看出,在執行 created 鈎子函數的過程中,對於自定義的屬性 message、自定義的方法 show 已經初始化完成,此時,整個 Vue 實例已經初始化完成。但是,對於我們的 Vue 實例的掛載點元素還沒有進行初始化。也就是說,當執行完 created 之后,Vue 實例與 View(視圖層)之間依舊是處於隔離的狀態,初始化完成的 Vue 實例也依舊沒有與 DOM 進行綁定。
2、beforeMount & mounted
當 Vue 實例執行完 beforeCreated、created 鈎子函數之后,Vue 實例已經初始化完成,而 Vue 實例並沒有掛載到頁面的 DOM 上。在掛載到頁面 DOM 元素之前,則需要執行 beforeMount 鈎子函數將我們的實例綁定到模板上進行編譯渲染。
<div id="app"> <h3 id="h3">{{message}}</h3> </div> <script> var vm = new Vue({ el: '#app', data: { message: 'Hello World!' }, methods: { show() { console.log('執行了 show 方法'); } }, beforeMount() { console.log(document.getElementById('h3').innerText) } }) </script>
從控制台輸出的信息可以看到,當執行到 beforeMount 鈎子函數時,已經將模板編譯完成,但是尚未掛載到頁面上去。
當把編譯完成的模板掛載到頁面上時,則需要執行 mounted 鈎子函數,在這個階段,用戶就可以看到已經渲染好的頁面。
<div id="app"> <h3 id="h3">{{message}}</h3> </div> <script> var vm = new Vue({ el: '#app', data: { message: 'Hello World!' }, methods: { show() { console.log('執行了 show 方法'); } }, mounted() { console.log(document.getElementById('h3').innerText) } }) </script>
這里我們可以看到,已經可以獲取到差值表達式的值,即當執行到 mounted 鈎子函數時,頁面已經渲染完成了。
從上面的例子中可以看出,mounted 是創建 Vue 實例過程中的最后一個生命周期鈎子函數,當執行完 mounted 鈎子函數之后,實例已經被完成創建好,並已經渲染到頁面中,此時,如果我們不對實例進行任何的操作的話,Vue 實例則不會執行 新的生命周期鈎子函數。
3、beforeUpdate & updated
在執行完了 mounted 鈎子函數之后,Vue 實例實際已經脫離了實例的創建階段,進入實例的運行階段。此時,當我們對實例的 data 進行修改時,則會觸發 beforeUpdate、updated 這兩個鈎子函數。
<div id="app"> <h3 id="h3">{{message}}</h3> </div> <script> var vm = new Vue({ el: '#app', data: { message: 'Hello World!' }, methods: { show() { console.log('執行了 show 方法'); } }, beforeUpdate() { console.log(`頁面上的數據:${document.getElementById('h3').innerText}`) console.log(`data 中的 message 數據:${this.message}`) } }) </script>
我們可以看到,當我們對 data 中的 message 屬性進行修改時,在執行 beforeUpdate 鈎子函數時,頁面上的數據還是舊的數據,而 data 中 message 屬性已經將值修改成了最新的值(這里頁面上顯示的為修改后的數據則是因為執行了后面的鈎子函數,將修改后的數據同步渲染到了頁面上)。
Vue 作為一個具有數據雙向綁定特性的框架,當我們實時修改了頁面元素的值之后,肯定希望頁面可以同步變更數據。而在執行 beforeUpdate 鈎子函數之后,我們已經在實例中修改了數據,現在只需要重新渲染到頁面就可以了,這時候,則會執行 updated 鈎子函數。
<div id="app"> <h3 id="h3">{{message}}</h3> </div> <script> var vm = new Vue({ el: '#app', data: { message: 'Hello World!' }, methods: { show() { console.log('執行了 show 方法'); } }, updated() { console.log(`頁面上的數據:${document.getElementById('h3').innerText}`) console.log(`data 中的 message 數據:${this.message}`) } }) </script>
從控制台可以看到,當 updated 鈎子函數執行的時候,頁面和 data 中的數據已經完成了同步,都顯示的是最新的數據。此時,整個頁面數據實時變更的操作也已經完成了。
4、beforeDestroy & destroyed
既然有 Vue 實例的創建,那么在我們不需要 Vue 實例的時候就需要將這個實例進行銷毀。而 beforeDestroy 以及 destroyed 鈎子函數則會幫我們實現這一目的。
<div id="app"> {{message}} </div> <script> var vm = new Vue({ el: '#app', data: { message: 'Hello World!' }, methods: { show() { console.log('執行了 show 方法'); } }, beforeDestroy() { console.log(`Vue 實例掛載對象 el:${this.$el}`) console.log(`Vue 實例的 data 對象:${this.$data}`) console.log(`Vue 實例的 message 屬性值:${this.message}`) console.log(`Vue 實例的 methods 對象:${this.$options.methods}`) this.show(); }, destroyed() { console.log(`Vue 實例掛載對象 el:${this.$el}`) console.log(`Vue 實例的 data 對象:${this.$data}`) console.log(`Vue 實例的 message 屬性值:${this.message}`) console.log(`Vue 實例的 methods 對象:${this.$options.methods}`) this.show(); } }) </script>
這里,我們手動銷毀 Vue 實例,從控制台的輸出內容可以看到,在 beforeDestroy 和 destroyed 鈎子函數執行中,我們依舊可以獲取到 Vue 實例的相關內容,可是,當我們選擇更新 message 屬性的值時會發現,此時,頁面上顯示的值並沒有發生改變。原來,這里的銷毀並不指代'抹去'這個 Vue 實例,而是表示將 Vue 實例與頁面的 DOM 元素進行'解綁'。
三、總結
鈎子函數 | 描述 |
---|---|
beforeCreate | Vue 實例進行初始化,此時實例的各個組件還沒有進行初始化完成,因此不能訪問到 data、computed、watch、methods 上的方法和數據,同時,Vue 實例的掛載點也沒有進行初始化 |
created | Vue 實例初始化完成,此時可以訪問 data、computed、watch、methods 上的方法和數據,但是依舊沒有進行 Vue 實例的掛載點初始化 |
beforeMount | 將實例綁定到模板並進行渲染,但並不會將實例掛載到頁面上 |
mounted | 將渲染好的模板綁定到頁面上,此時,Vue 實例已完全創建好 |
beforeUpdate | 數據變更時調用,在實例數據更改之前執行任何應該發生的自定義邏輯或操作 |
updated | 將 Vue 實例更新完成的數據重新渲染到內存中的虛擬 DOM 上,再將虛擬 DOM 應用到頁面上 |
beforeDestroy | Vue 實例進入銷毀階段,此時實例上的 data、methods、過濾器、指令等等還是處於可用的狀態,還沒有真正執行銷毀的過程(解除與頁面 DOM 元素的綁定) |
destroyed | 實例被銷毀(解除與頁面 DOM 元素的綁定) |