首页
Javascript
Html
Css
Node.js
Electron
移动开发
小程序
工具类
服务端
浏览器相关
前端收藏
其他
关于
公司注册

Vue的生命周期及相关问题

2019年01月29日 发布 阅读(3444) 作者:Jerman

vue的生命周期函数,官网上都有,记录下便于自己查找

概述

1、大致分为8个阶段
(1)、创建前/后(beforeCreate、created)
(2)、载入前/后(beforeMount、mounted)
(3)、更新前/后(beforeUpdate、updated)
(4)、销毁前/销毁后(beforeDestroy、destroyed)

2、各阶段执行的钩子函数
(1)、初始化组件时,仅执行了beforeCreate/Created/beforeMount/mounted四个钩子函数
(2)、当改变data中定义的变量(响应式变量)时,会执行beforeUpdate/updated钩子函数
(3)、当切换组件(当前组件未缓存)时,会执行beforeDestory/destroyed钩子函数
(4)、初始化和销毁时的生命钩子函数均只会执行一次,beforeUpdate/updated可多次执行

3、父子组件生命周期
(1)、仅当子组件完成挂载后,父组件才会挂载
(2)、当子组件完成挂载后,父组件会主动执行一次beforeUpdate/updated钩子函数(仅首次)
(3)、父子组件在data变化中是分别监控的,但是在更新props中的数据是关联的(可实践)
(4)、销毁父组件时,先将子组件销毁后才会销毁父组件

4、兄弟组件生命周期
(1)、组件的初始化(mounted之前)分开进行,挂载是从上到下依次进行
(2)、当没有数据关联时,兄弟组件之间的更新和销毁是互不关联的

宏mixin的生命周期
(1)、mixin中的生命周期与引入该组件的生命周期是仅仅关联的,且mixin的生命周期优先执行

生命周期函数及图示

  • beforeCreate 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。

  • created 在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。

  • beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。

    该钩子在服务器端渲染期间不被调用。

  • mounted el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。

    注意 mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted:

    1. mounted: function () {
    2. this.$nextTick(function () {
    3. // Code that will run only after the
    4. // entire view has been rendered
    5. })
    6. }
  • beforeUpdate 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。

    该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。

  • updated 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。

    注意 updated 不会承诺所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以用 vm.$nextTick 替换掉 updated:

    1. updated: function () {
    2. this.$nextTick(function () {
    3. // Code that will run only after the
    4. // entire view has been re-rendered
    5. })
    6. }

    该钩子在服务器端渲染期间不被调用。

  • activated keep-alive 组件激活时调用。

    该钩子在服务器端渲染期间不被调用。

  • deactivated keep-alive 组件停用时调用。

    该钩子在服务器端渲染期间不被调用。

  • beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。

    该钩子在服务器端渲染期间不被调用。

  • destroyed Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

    该钩子在服务器端渲染期间不被调用。

  • errorCaptured 2.5.0+ 新增
    类型:(err: Error, vm: Component, info: string) => ?boolean
    详细
    当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

    你可以在此钩子中修改组件的状态。因此在模板或渲染函数中设置其它内容的短路条件非常重要,它可以防止当一个错误被捕获时该组件进入一个无限的渲染循环。

    错误传播规则
    默认情况下,如果全局的 config.errorHandler 被定义,所有的错误仍会发送它,因此这些错误仍然会向单一的分析服务的地方进行汇报。

    如果一个组件的继承或父级从属链路中存在多个 errorCaptured 钩子,则它们将会被相同的错误逐个唤起。

    如果此 errorCaptured 钩子自身抛出了一个错误,则这个新错误和原本被捕获的错误都会发送给全局的 config.errorHandler。

    一个 errorCaptured 钩子能够返回 false 以阻止错误继续向上传播。本质上是说“这个错误已经被搞定了且应该被忽略”。它会阻止其它任何会被这个错误唤起的 errorCaptured 钩子和全局的 config.errorHandler。

什么是vue的生命周期?

Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、销毁等一系列过程,我们称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程,就是生命周期。

每一个组件或者实例都会经历一个完整的生命周期,总共分为三个阶段:初始化、运行中、销毁。

1、实例、组件通过new Vue() 创建出来之后会初始化事件和生命周期,然后就会执行beforeCreate钩子函数,这个时候,数据还没有挂载呢,只是一个空壳,无法访问到数据和真实的dom,一般不做操作

2、挂载数据,绑定事件等等,然后执行created函数,这个时候已经可以使用到数据,也可以更改数据,在这里更改数据不会触发updated函数,在这里可以在渲染前倒数第二次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取

3、接下来开始找实例或者组件对应的模板,编译模板为虚拟dom放入到render函数中准备渲染,然后执行beforeMount钩子函数,在这个函数中虚拟dom已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发updated,在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取

4、接下来开始render,渲染出真实dom,然后执行mounted钩子函数,此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了,可以在这里操作真实dom等事情…

5、当组件或实例的数据更改之后,会立即执行beforeUpdate,然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染,一般不做什么事儿

6、当更新完成后,执行updated,数据已经更改完成,dom也重新render完成,可以操作更新后的虚拟dom

7、当经过某种途径调用$destroy方法后,立即执行beforeDestroy,一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件等等

8、组件的数据绑定、监听…去掉后只剩下dom空壳,这个时候,执行destroyed,在这里做善后工作也可以

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <div id="app">
  11. <aaa></aaa>
  12. </div>
  13. <template id="aaa">
  14. <div>
  15. <p class="myp">A组件</p>
  16. <button @click="destroy">destroy</button>
  17. <input type="text" v-model="msg">
  18. <p>msg:{{msg}}</p>
  19. </div>
  20. </template>
  21. </body>
  22. <script src="./vue.js"></script>
  23. <script>
  24. //生命周期:初始化阶段 运行中阶段 销毁阶段
  25. Vue.component("aaa",{
  26. template:"#aaa",
  27. data:function(){
  28. return {msg:'hello'}
  29. },
  30. timer:null,
  31. methods:{
  32. destroy:function(){
  33. this.$destroy()//
  34. }
  35. },
  36. beforeCreate:function(){
  37. console.log('beforeCreate:刚刚new Vue()之后,这个时候,数据还没有挂载呢,只是一个空壳')
  38. console.log(this.msg)//undefined
  39. console.log(document.getElementsByClassName("myp")[0])//undefined
  40. },
  41. created:function(){
  42. console.log('created:这个时候已经可以使用到数据,也可以更改数据,在这里更改数据不会触发updated函数')
  43. this.msg+='!!!'
  44. console.log('在这里可以在渲染前倒数第二次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取')
  45. console.log('接下来开始找实例或者组件对应的模板,编译模板为虚拟dom放入到render函数中准备渲染')
  46. },
  47. beforeMount:function(){
  48. console.log('beforeMount:虚拟dom已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发updated')
  49. this.msg+='@@@@'
  50. console.log('在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取')
  51. console.log(document.getElementsByClassName("myp")[0])//undefined
  52. console.log('接下来开始render,渲染出真实dom')
  53. },
  54. // render:function(createElement){
  55. // console.log('render')
  56. // return createElement('div','hahaha')
  57. // },
  58. mounted:function(){
  59. console.log('mounted:此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了')
  60. console.log(document.getElementsByClassName("myp")[0])
  61. console.log('可以在这里操作真实dom等事情...')
  62. // this.$options.timer = setInterval(function () {
  63. // console.log('setInterval')
  64. // this.msg+='!'
  65. // }.bind(this),500)
  66. },
  67. beforeUpdate:function(){
  68. //这里不能更改数据,否则会陷入死循环
  69. console.log('beforeUpdate:重新渲染之前触发')
  70. console.log('然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染')
  71. },
  72. updated:function(){
  73. //这里不能更改数据,否则会陷入死循环
  74. console.log('updated:数据已经更改完成,dom也重新render完成')
  75. },
  76. beforeDestroy:function(){
  77. console.log('beforeDestory:销毁前执行($destroy方法被调用的时候就会执行),一般在这里善后:清除计时器、清除非指令绑定的事件等等...')
  78. // clearInterval(this.$options.timer)
  79. },
  80. destroyed:function(){
  81. console.log('destroyed:组件的数据绑定、监听...都去掉了,只剩下dom空壳,这里也可以善后')
  82. }
  83. })
  84. new Vue({
  85. }).$mount('#app')
  86. </script>
  87. </html>

参考

官网: https://cn.vuejs.org/v2/api/#%E9%80%89%E9%A1%B9-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90

https://www.cnblogs.com/happ0/p/8075562.html

https://juejin.im/entry/5aee8fbb518825671952308c

版权声明:本站文章除特别声明外,均采用署名-非商业性使用-禁止演绎 4.0 国际 许可协议,如需转载,请注明出处