前言
最近在寫業務的時候,總是會遇到一些和vue的生命週期相關的問題,比如: 你用ajax請求資料,然後將資料props到子元件的時候,因為ajax是非同步的,然後會發生沒有資料。然後查詢原因還是自己對這個東西理解不夠深入。
生命週期圖
生命鉤子函式
什麼是生命週期函式?
比如:
mounted: function() {
}
// 或者
mounted() {
}
複製程式碼
- 注意點,Vue的所有生命週期函式都是自動繫結到this的上下文上。所以,你這裡使用箭頭函式的話,就會出現this指向的父級作用域,就會報錯。
錯誤的形式:
mounted:() => {
}
複製程式碼
beforeCreate
在例項初始化之後,資料觀測和暴露了一些有用的例項屬性與方法。例項初始化——new Vue()
資料觀測——在vue的響應式系統中加入data物件中所有資料,這邊涉及到vue的雙向繫結,可以看官方文件上的這篇深度響應式原理 深度響應式原理
暴露屬性和方法——就是vue例項自帶的一些屬性和方法,我們可以看一個官網的例子,例子中帶$的屬性和方法就是vue例項自帶的,可以和使用者定義的區分開來
var data = { a: 1 }
var vm = new Vue({
el: '#example',
data: data
})
vm.$data === data // => true
vm.$el === document.getElementById('example') // => true
// $watch 是一個例項方法
vm.$watch('a', function (newValue, oldValue) {
// 這個回撥將在 `vm.a` 改變後呼叫
})
複製程式碼
created
- el屬性對生命週期的影響
// 有el屬性的情況下
new Vue({
el: '#app',
beforeCreate: function() {
console.log('呼叫了beforeCreate')
},
created: function() {
console.log('呼叫了created')
},
beforeMount: function() {
console.log('呼叫了beforeMount')
},
mounted: function() {
console.log('呼叫了mounted')
}
})
// 輸出結果
// 呼叫了beforeCreate
// 呼叫了created
// 呼叫了beforeMount
// 呼叫了mounted
複製程式碼
// 在沒有el屬性的情況下,沒有vm.$mount
new Vue({
beforeCreate: function() {
console.log('呼叫了beforeCreate')
},
created: function() {
console.log('呼叫了created')
},
beforeMount: function() {
console.log('呼叫了beforeMount')
},
mounted: function() {
console.log('呼叫了mounted')
}
})
// 輸出結果
// 呼叫了beforeCreate
// 呼叫了created
複製程式碼
// 在沒有el屬性的情況下,但是有vm.$mount方法
var vm = new Vue({
beforeCreate: function() {
console.log('呼叫了beforeCreate')
},
created: function() {
console.log('呼叫了created')
},
beforeMount: function() {
console.log('呼叫了beforeMount')
},
mounted: function() {
console.log('呼叫了mounted')
}
})
vm.$mount('#app')
// 輸出結果
// 呼叫了beforeCreate
// 呼叫了created
// 呼叫了beforeMount
// 呼叫了mounted
複製程式碼
- template屬性對生命週期的影響
這裡面分三種情況:
1、在例項內部有template屬性的時候,直接用內部的,然後呼叫render函式去渲染。 2、在例項內部沒有找到template,就呼叫外部的html。例項內部的template屬性比外部的優先順序高。 3、要是前兩者都不滿足,那麼就丟擲錯誤。
我們來看以下幾個例子:
new Vue({
el: '#app',
template: '<div id="app">hello world</div>'
})
//頁面上渲染出了hello world
複製程式碼
<div id="app">hello world</div>
new Vue({
el: '#app'
})
// 頁面上渲染出了hello world
複製程式碼
//兩者都存在的時候
<div id="app">hello world2</div>
new Vue({
el: '#app',
template: '<div id="app">hello world1</div>'
})
// 頁面上渲染出了hello world1
複製程式碼
從上述的例子可以看出內部的優先外部的。
- 關於這個生命週期中的一些問題:
1、為什麼el屬性的判斷在template之前? 因為el是一個選擇器,比如上述例子中我們用到的最多的是id選擇器app,vue例項需要用這個el去template中尋找對應的。
2、實際上,vue例項中還有一種render選項,我們可以從文件上看一下他的用法:
new Vue({
el: '#app',
render() {
return (...)
}
})
複製程式碼
3、上述三者的渲染優先順序:render函式 > template屬性 > 外部html
4、vue編譯過程——把tempalte編譯成render函式的過程。
beforeMount和mounted
我們先來看一個例子:
<div id="app">
<p>{{message}}</p>
</div>
new Vue({
el: '#app',
data: {
message: 1
},
beforeMount: function() {
console.log('呼叫了beforeMount');
console.log(this.message)
console.log(this.$el)
},
mounted: function() {
console.log('呼叫了mounted');
console.log(this.message)
console.log(this.$el)
}
})
// 輸出的結果:
// 呼叫了beforeMount
// 1
// <div>
// </div>
// 呼叫了mounted
// 1
// <div id="app">
// <p>1</p>
// </div>
複製程式碼
建立vue例項的$el,然後用它替代el屬性。
beforeUpdate和updated
這個過程中,我們會發現,當一個資料發生改變時,你的檢視也將隨之改變,整個更新的過程是:資料改變——導致虛擬DOM的改變——呼叫這兩個生命鉤子去改變檢視
- 重點:這個資料只有和模版中的資料繫結了才會發生更新。
// 沒繫結的情況
var vm = new Vue({
el: '#app',
template: '<div id="app"></div>',
beforeUpdate: function() {
console.log('呼叫了beforeUpdate')
},
updated: function() {
console.log('呼叫了uodated')
},
data: {
a: 1
}
})
vm.a = 2
//這種情況在控制檯中是什麼都不會輸出的。
複製程式碼
var vm = new Vue({
el: '#app',
template: '<div id="app">{{a}}</div>',
beforeUpdate: function() {
console.log('呼叫了beforeUpdate')
},
updated: function() {
console.log('呼叫了uodated')
},
data: {
a: 1
}
})
vm.a = 2
// 輸出結果:
// 呼叫了beforeUpdate
// 呼叫了uodated
複製程式碼
beforeDestory和destoryed
在beferoDestory生命鉤子呼叫之前,所有例項都可以用,但是當呼叫後,Vue 例項指示的所有東西都會解繫結,所有的事件監聽器會被移除,所有的子例項也會被銷燬。
幾個不常用的生命鉤子
- activated:當元件啟用的時候呼叫
- deactivated:當元件停用的時候呼叫
- errorCaptured:這個生命鉤子可以看官網,2.5.0之後才有的。當捕獲一個來自子孫元件的錯誤時被呼叫。
最後我們用一個例子來過一遍生命週期
let vm = new Vue({
el: '#app',
data: {
message: 1
},
template: '<div id="app"><p>{{message}}</p></div>',
beforeCreate() {
console.log('呼叫了beforeCreate')
console.log(this.message)
console.log(this.$el)
},
created() {
console.log('呼叫了created')
console.log(this.message)
console.log(this.$el)
},
beforeMount() {
console.log('呼叫了beforeMount')
console.log(this.message)
console.log(this.$el)
},
mounted() {
console.log('呼叫了mounted')
console.log(this.message)
console.log(this.$el)
},
beforeUpdate() {
console.log('呼叫了beforeUpdate')
console.log(this.message)
console.log(this.$el)
},
updated() {
console.log('呼叫了updated')
console.log(this.message)
console.log(this.$el)
},
beforeDestory() {
console.log('呼叫了beforeDestory')
console.log(this.message)
console.log(this.$el)
},
destoryed() {
console.log('呼叫了Destoryed')
console.log(this.message)
console.log(this.$el)
}
})
vm.message = 2
複製程式碼
- 輸出的結果:
// 呼叫了beforeCreate
// undefined
// undefined
// 呼叫了created
// 1
// undefined
// 呼叫了beforeMount
// 1
// <div></div>
// 呼叫了mounted
// 1
// <div id="app"><p>1</p></div>
// 呼叫了beforeUpdate
// 2
// <div id="app"><p>2</p></div>
// 呼叫了updated
// 2
// <div id="app"><p>2</p></div>
複製程式碼