1 生命周期

1) 什么是生命周期

一个Vue实例从创建到销毁的整个过程. Vue组件也可看成一个Vue实例

image.png

2) 生命周期函数(钩子)

在生命周期中, 特定的时间点会被自动执行的函数

  • beforeCreate()
  • created()
  • beforeMount()
  • mounted()
  • beforeUpdate()
  • updated()
  • beforeDestroy()
  • destroyed()

3) Vue实例到底做了一件什么事

Vue实例的最主要的工作是

将模板内容编译, 替换掉原有的html节点

  1. 模板内容: 由template选项确定
  2. 编译: 由render()方法, 将模板编译成在真实的DOM, 渲染在html文件中
  3. 原有的html节点: 由el选项确定

示例

  1. <div id="app"></div>
  2. <script>
  3. const vm = new Vue({
  4. el: '#app',
  5. template: '<div>hello</div>',
  6. })
  7. </script>

vue实例最终就是将<div>hello</div>替换掉了原有的html中<div id="app"></div>节点

示例

  1. const vm = new Vue({
  2. el: '#app',
  3. data: {
  4. msg: 'hello',
  5. },
  6. template: '<div>{{msg}}</div>',
  7. })

这里, 会难一点点, 流程是:

  1. 先解析template中的内容, 将{{msg}}替换成hello(这个过程叫作编译)
  2. 将编译的结果<div>hello</div>替换掉了原有的html中<div id="app"></div>节点

在这个过程中, 会有一些时间点, 在这些时间点会自动调用一些函数. 这些就是生命周期函数

示例

  1. const vm = new Vue({
  2. el: '#app',
  3. data: {
  4. msg: 'hello',
  5. },
  6. template: '<div>{{msg}}</div>',
  7. beforeCreate() {
  8. console.log(this, 'beforeCreate')
  9. },
  10. created() {
  11. console.log(this, 'created')
  12. },
  13. beforeMount() {
  14. console.log(this, 'beforeMount')
  15. },
  16. mounted() {
  17. console.log(this, 'mounted')
  18. },
  19. beforeUpdate() {
  20. console.log(this, 'beforUpdate')
  21. },
  22. updated() {
  23. console.log(this, 'updated')
  24. },
  25. beforeDestroy() {
  26. console.log(this, 'beforeDestroy')
  27. },
  28. destroyed() {
  29. console.log(this, 'destroyed')
  30. },
  31. })

我们发现, 有4个函数被执行了

  • beforeCreate()
  • created()
  • beforeMount()
  • mounted()

这四个函数在整个生命周期中只执行一次

4) 生命周期函数

create相关函数

create相关的生命周期函数有两个:

  • beforeCreate()
  • created()

beforeCreate和created的相同点

都是在Vue实例创建时被调用, 只执行一次

beforeCreate和created的不同点

要搞清楚这个问题, 我们需要知道在beforeCreate和created之间, 做了什么事

示例

  1. beforeCreate() {
  2. console.dir(this.$data) // undefined
  3. console.log(this, 'beforeCreate')
  4. },
  5. created() {
  6. console.dir(this.$data) // object
  7. // 跟数据相关, 放在created中
  8. console.log(this, 'created')
  9. }

我们发现, 在beforeCreate中$data是undefined, 而created中$data是有值的

因此, 我们得出一个重要结论

重要结论

如果要处理跟数据相关的逻辑, 最早在created函数中处理

一句话总结

在beforeCreate和created之间, 完成$data的代理

场景

  1. 如果发送ajax请求从后台拿数据, 建议放到created里
  2. 如果要完成data数据的初始化, 建议放到created里

mount相关函数

mount相关的生命周期函数有两个:

  • beforeMount()
  • mounted()

create和mount的不同

created结束时还不能操作DOM, mounted结束时才可以操作DOM

示例

  1. created() {
  2. console.dir(this.$data)
  3. // 跟数据相关, 放在created中
  4. console.log(this.$el, 'created') // undefined
  5. },
  6. beforeMount() {
  7. console.log(this.$el, 'beforeMount') // <div id="app"></div>
  8. },
  9. mounted() {
  10. // 跟DOM操作相关, 放在mounted中
  11. console.log(this.$el, 'mounted') // <div>hello</div>
  12. },

created表示实例创建完成, 而mounted表示挂载完成, 是new Vue时的两个步骤

怎么将这两个步骤分开呢

示例

  1. const vm = new Vue({
  2. // 第一步: 注释掉el
  3. // el: '#app',
  4. data: {
  5. msg: 'hello',
  6. },
  7. template: '<div>{{msg}}</div>',
  8. beforeCreate() {
  9. console.dir(this.$data)
  10. console.log(this.$el, 'beforeCreate')
  11. },
  12. created() {
  13. console.dir(this.$data)
  14. // 跟数据相关, 放在created中
  15. console.log(this.$el, 'created')
  16. },
  17. beforeMount() {
  18. console.log(this.$el, 'beforeMount')
  19. },
  20. mounted() {
  21. // 跟dom操作相关, 放在mounted中
  22. console.log(this.$el, 'mounted')
  23. },
  24. beforeUpdate() {
  25. console.log(this, 'beforUpdate')
  26. },
  27. updated() {
  28. console.log(this, 'updated')
  29. },
  30. beforeDestroy() {
  31. console.log(this, 'beforeDestroy')
  32. },
  33. destroyed() {
  34. console.log(this, 'destroyed')
  35. },
  36. })
  37. // 第二步: 调用$mount方法, 手动挂载
  38. vm.$mount('#app')

如果不指定el选项: 不会执行mount相关的生命周期

手动调用$mount方法挂载时, 发现mount相关的生命周期被调用了

mount是把什么挂载到什么上

mounted结束时, 将编译之后的模板挂载到了html上, 替换原有的节点.

通过上面的分析, 我们知道了:

Vue实例化过程中最主要两步是

  • 编译
  • 挂载

beforeMount和mounted的不同点

要搞清楚这个问题, 我们需要知道在beforeMount和mounted之间, 做了什么事

示例

  1. beforeMount() {
  2. console.log(this.$el, 'beforeMount') // <div id="app"></div>
  3. },
  4. render(h) {
  5. console.log('render in invoked')
  6. return h('div', {}, this.msg)
  7. },
  8. mounted() {
  9. // 跟dom操作相关, 放在mounted中
  10. console.log(this.$el, 'mounted') // <div>hello</div>
  11. },

在beforeMount和mounted之间, 调用了render方法, 将模板编译成了html

update相关函数

update相关的生命周期函数有两个:

  • beforeUpdate()
  • updated()

beforeUpdate和updated的相同点

都是在Vue的data中的数据发生改变时调用, 可以执行N次(N>=1)

beforeUpdate和updated的不同点

  • beforeUpdate中: 数据是新的, 页面还是旧的, 还没有更新页面, 此时页面和数据是不同步的
  • updated中: 数据是新的, 页面也是新的. 此时已经完成了re-render(页面的重新渲染)

destroy相关的函数

在destroy相关的函数有两个:

  • beforeDestroy(): 临死前
  • desstroyed(): 死透了

比较常用的是beforeDestroy, 在这个函数中, 释放不属于vue的一些资源(定时器)和解绑一些事件

5) 常用的生命周期函数

  1. created: 完成data的初始化
  2. mounted: 操作DOM
  3. beforeDestory: 回收资源, 解绑事件