Vue2生命周期

216 阅读4分钟

生命周期简介

  • 生命周期(Life Cycle)是指一个组件创建→运行→销毁的整个阶段,强调的是一个时间段Vue 所有功能的实现都是围绕生命周期进行的

  • 作用: 实现组件数据管理DOM 渲染两大重要功能

  • Vue 完整的生命周期大致可分成三个阶段:

    • 挂载阶段: beforeCreatecreatedbeforeMountmounted
    • 更新阶段: beforeUpdateupdated
    • 销毁阶段: beforeDestroydestroyed

生命周期钩子

  • 生命周期钩子是由 Vue 提供的内置函数,会伴随着组件的生命周期自动按次序执行
  • new Vue() 实例后会自动执行初始化函数初始化事件生成 Vue 实例的生命周期

注意:生命周期强调的是时间段生命周期钩子强调的是时间点

挂载阶段

  • Vue 实例初始化一些事件、属性和响应式数据等
  • <template> 模板编译成渲染函数 render,并渲染到真实的 DOM 节点上,以及数据变更时执行更新操作

数据初始化

1667642449145.png

beforeCreate

  • 执行初始化前, beforeCreate 函数无法进行任何操作,在当前阶段 datamethodscomputedwatch上的数据和方法都不能被访问
  • 实例初始化后,进行数据侦听和事件/侦听器的配置之前同步调用
 <div id="app" >
   <h1>{{message}}</h1>
 </div>
 data(){
   return { 
     message:'javaScript'
   }
 },
   
 methods:{
   run(){console.log('执行');}
 },
   
 beforeCreate(){
   console.group("------beforeCreate创建前状态------");
   console.log("el     : " + this.$el); // $el是vue实例的根元素
   console.log("data   : " + this.$data);
   console.log("message: " + this.message);
   console.log("props: " + this.$props);
   console.log("methods: " + this.run);
 }

1667640499788.png

created

  • 实例创建完成后立即同步调用,进行初始化数据
  • 至此,实例已完成处理 datacomputedmethodswatch可以访问到 data 中的数据和**methods 中的方法**,已经为 Vue 实例开辟了内存空间
  • 但是挂载还没开始,Dom 元素依旧拿不到,且 $el property目前尚不可用
 created(){
   console.group("------created创建前状态------");
   console.log("el     : " + this.$el); // $el是vue实例的根元素
   console.log("data   : " + this.$data);
   console.log("message: " + this.message);
   console.log("props: " + this.$props);
   console.log("methods: " + this.run);
   debugger
 }

1667641493906.png

  • 打个断点在开发者工具中查看,发现模板中仅有 app 根标签

1667644165285.png

模板编译

1667642834424.png

  • 在执行下一个生命周期钩子之前,首先会判断对象是否有el选项

    • el选项就继续向下编译模板
    • 没有则停止编译,停止了生命周期,直到该 Vue 实例上调用vm.$mount(el)

beforeMount

  • 挂载前状态,此时页面中还没有当前组件的 DOM 结构,只是把 HTML 结构渲染到浏览器
  • el 仍然无法获取,所有对DOM的操作不会奏效
 beforeMount(){
   console.group("------beforeMount创建前状态------");
   const h1 = document.querySelector("h1");
   console.log(h1);
   console.log("el     : " + this.$el); // $el是vue实例的根元素
   console.log("data   : " + this.$data);
   console.log("message: " + this.message);
   console.log("props: " + this.$props);
   console.log("methods: " + this.run);
   debugger
 }

1667645617167.png

  • 在进入下个生命周期前,Vue 会用内存中生成的虚拟 DOM 转化为真实 DOM
  • 并将虚拟 DOM 保存一份到 $el

1667645466387.png

mounted

  • 挂载结束,虚拟 DOM已经挂载在了真实的元素上,至此可以拿到el
  • DOM 元素也加载到浏览器中,对 DOM 操作奏效
 mounted(){
   console.group("------mounted创建前状态------");
   const h1 = document.querySelector("h1");
   console.log("h1     : "+ h1)
   console.log("el     : " + this.$el); // $el是vue实例的根元素
   console.log("data   : " + this.$data);
   console.log("message: " + this.message);
   console.log("props: " + this.$props);
   console.log("methods: " + this.run);
   debugger
 }
  • 此时可以看到,app 根元素下已经有了 DOM 元素

1667648703068.png

更新阶段

  • 当数据发生改变时,触发对应组件的重新渲染

1667648822078.png

beforeUpdate

  • 此时数据是新的,但页面是旧的,即页面未和数据保持同步
  • mounted 钩子中修改数据,没有立即重新渲染页面,此时可看到 DOM 元素中的数据未重新渲染
 mounted(){
   this.message = 'python'
 },
 ​
 beforeUpdate(){
   console.group("------beforeUpdate创建前状态------");
   const h1 = document.querySelector("h1");
   console.log("h1     : "+ h1)
   console.log("el     : " + this.$el); // $el是vue实例的根元素
   console.log("data   : " + this.$data);
   console.log("message: " + this.message);
   console.log("props: " + this.$props);
   console.log("methods: " + this.run);
   debugger
 }

1667650068251.png

updated

  • 在这个钩子之前Vue 根据最新的数据重新渲染组件的DOM结构
  • 当数据变化之后,为了能够操作到最新的 DOM 结构,必须把代码写到 updated 生命周期函数中
  • 该钩子函数最少被触发0次,因为只有当数据发生变化时才会被触发
 updated(){
   console.group("------updated创建前状态------");
   const h1 = document.querySelector("h1");
   console.log("h1     : "+ h1)
   console.log("message: " + this.message);
   debugger
 }

1667658278854.png

销毁阶段

  • 把组件实例从父组件中删除,取消依赖监听和事件监听,并解绑所有指令

1667658373094.png

beforeDestroy

  • 实例销毁之前调用
  • 此时实例仍然完全可用,组件仍然处于工作状态
  • 注意: 该钩子在服务器端渲染期间不被调用
  • updated 钩子函数销毁实例,触发 beforeDestroy 钩子函数,但是仍然可以输出该组件的数据,事件监听,方法
 updated(){
   this.$destroy()
 },
 ​
 beforeDestroy(){
   console.group("------beforeDestroy创建前状态------");
   const h1 = document.querySelector("h1");
   console.log("h1     : "+ h1)
   console.log("el     : " + this.$el); // $el是vue实例的根元素
   console.log("data   : " + this.$data);
   console.log("message: " + this.message);
   console.log("props: " + this.$props);
   console.log("methods: " + this.run);
   debugger
 }

1667658875300.png

destroyed

  • Vue 实例销毁后调用
  • 实例所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁
  • 注意: 在此函数内的代码仍会执行,所有东西都可以输出
 mounted(){
   this.$destroy()
 },
 ​
 destroyed(){
   console.group("------destroyed创建前状态------");
   this.message = 'java'
   const h1 = document.querySelector("h1");
   console.log("h1     : "+ h1)
   console.log("el     : " + this.$el); // $el是vue实例的根元素
   console.log("data   : " + this.$data);
   console.log("message: " + this.message);
   console.log("props: " + this.$props);
   console.log("methods: " + this.run);
 }

1667659365317.png

其他阶段

  • 除了以上的8个钩子函数以外,还有以下三个钩子

    • activated
    • deactivated
    • errorCaptured

activated

  • keep-alive 缓存的组件激活时调用
  • 当组件被激活时,会自动触发组件的 activated 生命周期钩子

deactivated

  • 当组件被缓存时,会自动触发组件的 deactivated 生命周期钩子

    • 父组件App
     <!-- App.vue -->
     <keep-alive> <Count v-if="btn"/> </keep-alive>
     <keep-alive> <Child v-if="!btn"/> </keep-alive>
     <button @click="btn=!btn">隐藏/激活</button>
    
    • 子组件Count
     <!-- Count.vue -->
     <h1>Count</h1>
    
     // Count.vue
     activated(){
         console.log('Count被激活');
     },
     deactivated(){
       console.log('Count被缓存');
     }
    
    • 子组件Child
     <!-- Child.vue -->
     <h1>Child</h1>
    
     // Child.vue
     activated(){
       console.log('Child被激活');
     },
     deactivated(){
       console.log('Child被缓存');
     }
    
  • 此时一进入页面,首先看到的是Child组件

    • 当点击按钮时,Child组件会被缓存,Count 组件会激活
    • 再次点击按钮,Count组件会被缓存,Child 组件会激活

1667660967992.png

errorCaptured

  • 捕获一个来自后代组件的错误时被调用

  • 此钩子会收到三个参数

    • 错误对象
    • 发生错误的组件实例
    • 包含错误来源信息的字符串
  • 此钩子可以返回 false 以阻止该错误继续向上传播

 // 子组件
 mounted(){
   a  // 会报错
 }
 // 父组件
 errorCaptured(err,el,str){
   console.log(err);
   console.log(el);
   console.log(str);
 }

1667662256773.png

在不同的生命周期钩子中适合做什么?

  • created: 可以发起 Ajax 请求,并可以对数据进行初始化之类的操作
  • mounted: 可以获取 DOM 并进行操作,例如初始化 echart 图表,也可以做 Ajax 请求
  • beforeupdate: 访问现有的 DOM,手动移除一些添加的监听事件
  • updated: 可以获取最新的 DOM,但不建议进行数据操作,避免进入死循环
  • beforeDestroy: 销毁定时器,解绑全局事件,销毁插件对象
  • activated、deactivated: tab切换组件时可以使用