前沿:
通過前面幾節(jié)的學(xué)習(xí),我們已經(jīng)對(duì)vue有了初步的了解,vue可以幫我們干什么,而接下來就介紹vue的生命周期和它常用的鉤子函數(shù),那么我們就來看看對(duì)于vue的生命周期.
1. 理解生命周期的含義
生命周期:就是一個(gè)組件從實(shí)例化創(chuàng)建并添加到DOM開始 ,一直到組件被銷毀的整個(gè)過程 。
生命周期函數(shù)(鉤子函數(shù)): 就是在Vue生命周期的整個(gè)過程的不同階段被調(diào)用的函數(shù)
2. 生命周期圖
首先來一下官網(wǎng)的對(duì)于vue生命周期的圖解, 官網(wǎng)上目前有8個(gè)生命周期函數(shù),
還有兩個(gè)我們之后再看. 先看看基本的8個(gè)鉤子函數(shù)

3. 鉤子函數(shù)的理解
通過打斷點(diǎn)的方式,讓我們好好理解聲明周期的鉤子函數(shù), 你們也可以自己復(fù)制代碼進(jìn)行測(cè)試好好理解Vue的鉤子函數(shù)
<script>
new Vue({
el: "#app",
data:{},
methods:{},
// 1. 在實(shí)例化之前被調(diào)用
beforCreate: function(){
// 這個(gè)方法的時(shí)候data還沒有加載,所以此方法用不到
// 一般不會(huì)再這里處理什么事情
alert("組件實(shí)例化之前執(zhí)行的函數(shù)");
debugger;
},
// 2. 實(shí)例化初始之后,被添加到DOM元素之前觸發(fā)
created: function(){
// 可以在這里發(fā)送ajax,初始化操作
alert("組件實(shí)例化完畢,但頁(yè)面還未顯示");
debugger;
},
// 3. 在元素(虛擬DOM)已經(jīng)準(zhǔn)備好被添加到DOM,但是還沒有添加時(shí)觸發(fā)
beforeMount: function(){
// 要保證有el,或者vm.$mount() 否則這里不會(huì)執(zhí)行
alert("組件掛載前,但頁(yè)面還未顯示,但是虛擬DOM已經(jīng)配置");
debugger;
},
// 4. 會(huì)在元素創(chuàng)建后觸發(fā)
mounted: function(){
// 如果有template屬性模板,會(huì)用模板替換外部的el,只要有此屬性,直接卸載外部el找中的內(nèi)
// 這將沒有任何意義了
// template只能有一個(gè)更元素,不能是文本節(jié)點(diǎn),
// 真實(shí)的dom渲染完了,可以操作dom了
alert("組件掛載后,此方法執(zhí)行后,頁(yè)面顯示");
debugger;
},
// 5. 在數(shù)據(jù)更新將要對(duì)DOM做一些修改時(shí)觸發(fā)
beforeUpdate: function(){
// 當(dāng)頁(yè)面依賴的數(shù)據(jù)發(fā)生變化時(shí)才執(zhí)行,一般用watch來替換,這個(gè)方法不好用
// 頁(yè)面依賴的數(shù)據(jù)發(fā)生變化,數(shù)據(jù)已變化,頁(yè)面還沒有渲染
alert("組件更新前,但頁(yè)面還未顯示,但是虛擬DOM已經(jīng)配置");
debugger;
},
// 6. 后在DOM的更新已經(jīng)完成后觸發(fā)
updated: function(){
// 重新渲染頁(yè)面后執(zhí)行, 可以操作DOM了
alert("組件更新后,此方法執(zhí)行后,頁(yè)面顯示");
debugger;
},
// 7. 在組件即將被銷毀并且從DOM上移出時(shí)觸發(fā)
beforeDestroy: function(){
//沒什么意義,死了就什么都干不了了
alert("組件銷毀前");
debugger;
}
// 8. 組件被銷毀后觸發(fā)
destroyed: function(){
alert("組件銷毀");
debugger;
}
})
</script>
實(shí)踐是檢驗(yàn)道理的唯一標(biāo)準(zhǔn),
這里只能通過注釋來介紹一下vue的鉤子函數(shù)的意義。
想要詳細(xì)了解還需要你親自測(cè)試體會(huì)
生命周期鉤子的 this 上下文指向調(diào)用它的 Vue 實(shí)例。
通過這張生命周期圖,我們發(fā)現(xiàn)我們之前還有一些內(nèi)容沒有測(cè)試到, 諸如使用$mount綁定DOM元素, 實(shí)例化時(shí)自定義template模板等,那么接下來就好好測(cè)試一些,生命周期圖所講述的內(nèi)容
4. 綁定節(jié)點(diǎn)
我們之前學(xué)到一直是使用vue配置對(duì)象里的el來綁定DOM節(jié)點(diǎn)
生命周期圖告訴我們,如果我們沒有el屬性就會(huì)查找vue實(shí)例對(duì)象有沒有通過$mount方法來綁定DOM元素
其實(shí)就算你是用el綁定了DOM元素,在Vue源碼中也是會(huì)轉(zhuǎn)為$mount處理
<div id="app">
<div v-html="msg"></div>
</div>
<div id="haha"></div>
<script>
const vm = new Vue({
el:"#app",
data: {
msg:"hello"
},
})
vm.$mount("#haha")
</script>
同時(shí)我們還會(huì)發(fā)現(xiàn),如果el和$mount都存在,綁定的元素有差異,那么以el為主,因?yàn)樯芷趫D告訴我們只有當(dāng)el屬性不存在的時(shí)候,才會(huì)查看$mount方法
5. template模板編譯
我們之前學(xué)習(xí)一直使用的都是沒有template模板的, 根據(jù)生命周期圖顯示,如果我們沒有template,模板,我們就會(huì)將el 屬性對(duì)應(yīng)的掛在點(diǎn)作為我們的模板
如果有template模板,我們就會(huì)用以后的模板替換之前的模板
<div id="app">
{{ msg }}
</div>
<script>
const vm = new Vue({
el:"#app",
template:"<div id='haha'>我是小當(dāng)家</div>",
data: {
msg:"hello"
},
})
</script>
5.1 注意template模板里只能有一個(gè)根標(biāo)簽
所以下面的寫法會(huì)報(bào)錯(cuò),是錯(cuò)誤的寫法
const vm = new Vue({
template:`
<div id='haha'>
我是小當(dāng)家
</div>
<span></span>
`,
data: {
msg:"hello"
},
})
5.2 改變數(shù)據(jù)綁定的位置
如果有template 模板,我們動(dòng)態(tài)綁定的數(shù)據(jù),就需要在模板中綁定
<div id="app">
{{ msg }}
</div>
<script>
const vm = new Vue({
el:"#app",
template:"<div id='haha'>我是小當(dāng)家{{ msg }}</div>",
data: {
msg:"hello"
},
})
</script>
6. 關(guān)于mounted鉤子函數(shù)中獲取DOM元素的問題
6.1 正常在mounted鉤子函數(shù)里獲取DOM
<div id="app">
<div v-html="msg"></div>
</div>
<script>
const vm = new Vue({
el:"#app",
data: {
msg:"<h2 id='box'>hello</h2>"
},
mounted(){
console.log("mounted:");
console.log(box);
},
})
</script>
我們會(huì)發(fā)現(xiàn)獲取DOM元素完全沒有問題,
6.2 更改DOM節(jié)點(diǎn)內(nèi)容
如果我們動(dòng)態(tài)的修改了DOM節(jié)點(diǎn),那么我們?cè)讷@取看看
<div id="app">
<div v-html="msg"></div>
</div>
<script>
const vm = new Vue({
el:"#app",
data: {
msg:"<h2 id='box'>hello</h2>"
},
mounted(){
// 動(dòng)態(tài)修改DOM 節(jié)點(diǎn)
this.msg = `<h2 id="box">你好</h2>`
// 獲取DOM 節(jié)點(diǎn)
console.log(box);
},
})
</script>
這是我們就會(huì)發(fā)現(xiàn)我們獲取的還是原先的DOM節(jié)點(diǎn), 此時(shí)去獲取節(jié)點(diǎn)內(nèi)容就會(huì)有問題,
獲取的DOM節(jié)點(diǎn)并不是更改后最新的DOM節(jié)點(diǎn)
6.3 解決動(dòng)態(tài)DOM 節(jié)點(diǎn)的問題
我們可以使用$nextTice來解決此類問題
在下次 DOM 更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)。在修改數(shù)據(jù)之后立即使用這個(gè)方法,獲取更新后的 DOM。
$nextTick(),是將回調(diào)函數(shù)延遲在下一次dom更新數(shù)據(jù)后調(diào)用,簡(jiǎn)單的理解是:數(shù)據(jù)更新后,在dom重新渲染完畢,自動(dòng)執(zhí)行該函數(shù),
通過$nextTick 方法來異步操作vue實(shí)例
示例:
<div id="app">
<div v-html="msg"></div>
</div>
<script>
const vm = new Vue({
el:"#app",
data: {
msg:"<h2 id='box'>hello</h2>"
},
mounted(){
// 動(dòng)態(tài)修改DOM 節(jié)點(diǎn)
this.msg = `<h2 id="box">你好</h2>`
// 獲取DOM 節(jié)點(diǎn)
console.log(box);
// 通過$nextTick異步處理方法來獲取就會(huì)得到最新的值
this.$nextTick(() => {
console.log(box);
})
},
})
</script>
上面的示例,我們打印了2次box ,box是DOM元素的id,可以用來獲取DOM元素, 但是此時(shí)兩次獲取的DOM元素展示的結(jié)果不一樣

第一次獲取box雖然數(shù)據(jù)已經(jīng)改變, 頁(yè)面也準(zhǔn)備重新渲染新的DOM元素, 但是此時(shí)DOM還沒有更新完成,就獲取box,獲取的就是原來的DOM元素內(nèi)容, $nextTick方法會(huì)在DOM元素更新完成以后才會(huì)觸發(fā)回調(diào)函數(shù),在回調(diào)函數(shù)中獲取的box才是更改后最新的DOM元素
建議在組件學(xué)習(xí)后在回來看:
帶有子組件的示例:
<div id="app">
<child ref="child"></child>
</div>
<template id="child">
<div>
<span v-for="a in arr">{{a}}</span>
</div>
</template>
<script>
var vm = new Vue({ // 根實(shí)例
el: '#app',
data: {
radio: 'home'
},
mounted() {
console.log(1); // 在執(zhí)行父組件的mounted
// console.log(this.$refs.child.$el.innerHTML);
// 這里打印的是 1,2,3的數(shù)組
// 這里可以選擇$nextTick方法,這個(gè)是在頁(yè)面渲染完畢后執(zhí)行
this.$nextTick(() => {
console.log(this.$refs.child.$el.innerHTML); // 這個(gè)時(shí)候才4,5,6
})
},
components: {
child: {
template: '#child',
data() {
return { arr: [1, 2, 3] }
},
mounted() {
console.log(2); // 先打印子組件的mounted
this.arr = [4, 5, 6]; // 說明這里mounted是異步的
}
}
}
});
</script>
顯示結(jié)果

通過實(shí)例發(fā)現(xiàn),是不是用$nextTick方法在組件數(shù)據(jù)更新以后獲取的DOM元素的內(nèi)容都不一樣