vue生命週期詳解

小吳3發表於2021-09-07

前言

最近在寫業務的時候,總是會遇到一些和vue的生命週期相關的問題,比如: 你用ajax請求資料,然後將資料props到子元件的時候,因為ajax是非同步的,然後會發生沒有資料。然後查詢原因還是自己對這個東西理解不夠深入。

生命週期圖

vue生命週期詳解

生命鉤子函式

什麼是生命週期函式?

比如:

mounted: function() {
}

// 或者

mounted() {
}
複製程式碼
  • 注意點,Vue的所有生命週期函式都是自動繫結到this的上下文上。所以,你這裡使用箭頭函式的話,就會出現this指向的父級作用域,就會報錯。

錯誤的形式:

mounted:() => {
}
複製程式碼

beforeCreate

vue生命週期詳解
在例項初始化之後,資料觀測和暴露了一些有用的例項屬性與方法。

例項初始化——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屬性對生命週期的影響

vue生命週期詳解

// 有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屬性對生命週期的影響

vue生命週期詳解

這裡面分三種情況:

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

life-mounted.png

我們先來看一個例子:

<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

vue生命週期詳解

這個過程中,我們會發現,當一個資料發生改變時,你的檢視也將隨之改變,整個更新的過程是:資料改變——導致虛擬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

vue生命週期詳解

在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>
複製程式碼

相關文章