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

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

第一次獲取box雖然數(shù)據(jù)已經(jīng)改變, 頁面也準備重新渲染新的DOM元素, 但是此時DOM還沒有更新完成,就獲取box,獲取的就是原來的DOM元素內(nèi)容, $nextTick方法會在DOM元素更新完成以后才會觸發(fā)回調(diào)函數(shù),在回調(diào)函數(shù)中獲取的box才是更改后最新的DOM元素
建議在組件學習后在回來看:
帶有子組件的示例:
<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({ // 根實例
el: '#app',
data: {
radio: 'home'
},
mounted() {
console.log(1); // 在執(zhí)行父組件的mounted
// console.log(this.$refs.child.$el.innerHTML);
// 這里打印的是 1,2,3的數(shù)組
// 這里可以選擇$nextTick方法,這個是在頁面渲染完畢后執(zhí)行
this.$nextTick(() => {
console.log(this.$refs.child.$el.innerHTML); // 這個時候才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é)果

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