Vue 生命週期
Vue 實例有一個完整的生命週期,包含從創建、初始化數據、編譯模板、掛載 DOM 至渲染、更新至渲染、移除等整個過程,稱之為 Vue 的生命週期。
beforeCreate
- 初始化實例與非響應式變數。
- this 指向創建的實例。
- data、computed、watch、methods 上的方法和數據均不得訪問。
created
- 實例創建完成。
- 可訪問 data、computed、watch、methods 上的方法和數據。
- 尚未掛載 DOM,不得訪問 el,ref 為空陣列。
- 若在此階段操作 DOM 需於 Vue.nextTick() 函數中動作。
beforeMount
- 編譯模板或掛載至 HTML 之前。
- 此階段會檢查有無 element,如果有就往下一步,如果沒有可以事後透過 vm.$mount(el) 指定給某個 element,如果兩者都沒有就會被瀏覽器回收。
- 再來會檢查有無 template,如果有就會編譯至 render function,如果沒有就會把 HTML 當作 template 編譯。
mounted
- 完成創建 vm。
- 可對 DOM 進行操作。
- 編譯模板或掛載至 HTML 之後。
- 此階段會創建 vm.$el 並且把編譯好的內容跟指定的 DOM 做結合。
- 此階段可以透過 vm.$destory() 銷毀元件。
brforeUpdate
- 元件被更新之前。
- 此階段拿到的 DOM 是編譯前的結果,呈現的是原始碼的樣子。
- 以下面的範例為例,beforeUpdate 觸發時所抓取的是網頁上 h1 原始的值,與 Vue 實體內的值是不同步的。
updated
- 元件被更新之後。
- 此階段拿到的 DOM 是編譯後的結果,資料與事件等等在 element 上的呈現是編譯後的樣子。
- 以下面的範例為例,同步完成後會觸發 updated ,此時網頁上 h1 的值就會與 Vue 實體內的值同步。
beforeDestroy
- 移除 Vue 實例之前。
destroyed
- 移除 Vue 實例之後。
- 此階段會移除 watchers 以及子元件與監聽的事件,完成後此元件也就此消失。
- 這邊要注意 destoryed 執行完成後並不一定是把網頁上的 DOM 元素移除,而代表的是 Vue 的實體與所綁定的 element 從此脫鉤,意思就是說原本所綁定的事件已經無法再控制 element。
以下面的範例為例,如果按下 Del 再按 Update 的話,count 並不會被 ++,也就是 Vue 的實體已經被銷毀無法再控制原先所綁定的 element。
測試代碼
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h1>{{ count }}</h1>
<button @click="updateHandler">加 1</button>
<button @click="delInstance">刪除實例</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
count: 0,
},
methods: {
updateHandler() {
this.count += 1;
},
delInstance() {
this.$destroy();
},
},
beforeCreate() {
console.log('beforeCreate --- this.count: ', this.count);
console.log('beforeCreate --- this.$el: ', this.$el);
},
created() {
console.log('created -------- this.count: ', this.count);
console.log('created -------- this.$el: ', this.$el);
},
beforeMount() {
console.log('beforeMount ---- this.count: ', this.count);
console.log('beforeMount ---- this.$el: ', this.$el);
},
mounted() {
console.log('mounted -------- this.count: ', this.count);
console.log('mounted -------- this.$el: ', this.$el);
},
beforeUpdate() {
console.log(
'beforeUpdate: ',
this.$el.querySelector('h1').innerText,
this.count
);
},
updated() {
console.log(
'updated: ',
this.$el.querySelector('h1').innerText,
this.count
);
},
beforeDestroy() {
console.log('beforeDestroy');
},
destroyed() {
console.log('destroyed');
},
});
</script>
</body>
</html>