Vue 3 生命周期完整指南

做者:Michael Thiessen
译者:前端小智
来源:news
点赞再看,微信搜索 大迁世界,B站关注 前端小智这个没有大厂背景,但有着一股向上积极心态人。本文 GitHub https://github.com/qq44924588... 上已经收录,文章的已分类,也整理了不少个人文档,和教程资料。

最近开源了一个 Vue 组件,还不够完善,欢迎你们来一块儿完善它,也但愿你们能给个 star 支持一下,谢谢各位了。html

github 地址:https://github.com/qq44924588...前端

image.png

Vue2 和 Vue3 中的生命周期钩子的工做方式很是类似,咱们仍然能够访问相同的钩子,也但愿将它们能用于相同的场景。vue

若是项目使用 选项 API,就没必要更改任何代码了,由于 Vue3 兼容之前的版本。git

固然,咱们用 Vue3 就是要用它的 组合 API组合 API中访问这些钩子的方式略有不一样,组合API在较大的Vue项目中特别有用。github

本文主要内容:面试

  1. Vue生命周期钩子有哪些
  2. 选项API中使用 Vue 生命周期钩子
  3. 组合API中使用Vue 3生命周期钩子
  4. 将 Vue2 的生命周期钩子代码更新到 Vue3
  5. 看看Vue 2和Vue 3中的每一个生命周期钩子vue-cli

    1. 建立
    2. 挂载
    3. 更新
    4. 卸载
    5. 激活
  6. Vue 3中的新调试钩子

Vue生命周期钩子有哪些

首先,来看一下 选项API 和 组合 API中 Vue 3生命周期钩子的图表。在深刻细节以前,这能加深咱们的理解。api

image.png

本质上,每一个主要Vue生命周期事件被分红两个钩子,分别在事件以前和以后调用。Vue应用程序中有4个主要事件(8个主要钩子)。缓存

  • 建立 — 在组件建立时执行
  • 挂载 — DOM 被挂载时执行
  • 更新 — 当响应数据被修改时执行
  • 销毁 — 在元素被销毁以前当即运行

选项API中使用 Vue 生命周期钩子

使用 选项API,生命周期钩子是被暴露 Vue实例上的选项。咱们不须要导入任何东西,只须要调用这个方法并为这个生命周期钩子编写代码。微信

例如,假设咱们想访问mounted()updated()生命周期钩子,能够这么写:

// 选项 API
<script>     
   export default {         
      mounted() {             
         console.log('mounted!')         
      },         
      updated() {             
         console.log('updated!')         
      }     
   }
</script>

组合API中使用Vue 3生命周期钩子

在组合API中,咱们须要将生命周期钩子导入到项目中,才能使用,这有助于保持项目的轻量性。

// 组合 API
import { onMounted } from 'vue'

除了beforecatecreated(它们被setup方法自己所取代),咱们能够在setup方法中访问的API生命周期钩子有9个选项:

  • onBeforeMount – 在挂载开始以前被调用:相关的 render 函数首次被调用。
  • onMounted – 组件挂载时调用
  • onBeforeUpdate – 数据更新时调用,发生在虚拟 DOM 打补丁以前。这里适合在更新以前访问现有的 DOM,好比手动移除已添加的事件监听器。
  • onUpdated – 因为数据更改致使的虚拟 DOM 从新渲染和打补丁,在这以后会调用该钩子。
  • onBeforeUnmount – 在卸载组件实例以前调用。在这个阶段,实例仍然是彻底正常的。
  • onUnmounted – 卸载组件实例后调用。调用此钩子时,组件实例的全部指令都被解除绑定,全部事件侦听器都被移除,全部子组件实例被卸载。
  • onActivated – 被 keep-alive 缓存的组件激活时调用。
  • onDeactivated – 被 keep-alive 缓存的组件停用时调用。
  • onErrorCaptured – 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子能够返回 false 以阻止该错误继续向上传播。

使用事例:

// 组合 API
<script>
import { onMounted } from 'vue'

export default {
   setup () {
     onMounted(() => {
       console.log('mounted in the composition api!')
     })
   }
}
</script>

将 Vue2 的生命周期钩子代码更新到 Vue3

这个从Vue2 到Vue3的生命周期映射是直接从Vue 3 Composition API文档中得到的:

  • beforeCreate -> 使用 setup()
  • created -> 使用 setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

深刻了解每一个生命周期钩子

咱们如今了解了两件重要的事情:

  • 咱们可使用的不一样的生命周期钩子
  • 如何在选项API和组合API中使用它们

咱们深刻一下每一个生命周期钩子,看看它们是如何被使用的,咱们能够在每一个钩子中编写特定代码,来测试在Options API和Composition API中的各自的区别。

beforeCreate() – 选项 API

因为建立的挂钩是用于初始化全部响应数据和事件的事物,所以beforeCreate没法访问组件的任何响应数据和事件。

如下面的代码块为例:

// 选项 API
export default {
   data() { 
     return { 
       val: 'hello'    
     }
   },
   beforeCreate() {     
     console.log('Value of val is: ' + this.val)   
   }
}

val的输出值是 undefined,由于还没有初始化数据,咱们也不能在这调用组件方法。

若是你想查看可用内容的完整列表,建议只运行console.log(this)来查看已初始化的内容。当使用选项API时,这作法在其余钩子中也颇有用。

created() – 选项 API

若是咱们要在组件建立时访问组件的数据和事件,能够把上面的 beforeCreatecreated代替。

// 选项API
export default {
   data() { 
     return { 
       val: 'hello'    
     }
   },
   created() {     
     console.log('Value of val is: ' + this.val)   
   }
}

其输出为Value of val is: hello,由于咱们已经初始化了数据。

在处理读/写反应数据时,使用created 的方法颇有用。 例如,要进行API调用而后存储该值,则能够在此处进行此操做。

最好在这里执行此操做,而不是在mounted 中执行此操做,由于它发生在Vue的同步初始化过程当中,而且咱们须要执行全部数据读取/写入操做。

那么组合API的建立钩子呢?

对于使用 组合API 的 Vue3 生命周期钩子,使用setup()方法替换beforecatecreated。这意味着,在这些方法中放入的任何代码如今都只在setup方法中。

// 组合AP
import { ref } from 'vue'

export default {
   setup() {    
     const val = ref('hello') 
     console.log('Value of val is: ' + val.value)       
     return {         
       val
     }
   }
}

beforeMount() and onBeforeMount()

在组件DOM实际渲染安装以前调用。在这一步中,根元素还不存在。在选项API中,可使用this.$els来访问。在组合API中,为了作到这一点,必须在根元素上使用ref

// 选项 API
export default {
   beforeMount() {
     console.log(this.$el)
   }
 }

组合API中使用 ref:

// 组合 API
<template>
   <div ref='root'>
     Hello World
   </div>
</template> 

import { ref, onBeforeMount } from 'vue'

export default {
   setup() {
      const root = ref(null) 
      onBeforeMount(() => {   
         console.log(root.value) 
      }) 
      return { 
         root
      }
    },
    beforeMount() {
      console.log(this.$el)
    }
 }

由于app.$el尚未建立,因此输出将是undefined

mounted() and onMounted()

在组件的第一次渲染后调用,该元素如今可用,容许直接DOM访问

一样,在 选项API中,咱们可使用this.$el来访问咱们的DOM,在组合API中,咱们须要使用refs来访问Vue生命周期钩子中的DOM。

import { ref, onMounted } from 'vue'
 

 export default {
   setup() {    /* 组合 API */
 
     const root = ref(null)
 
     onMounted(() => {
       console.log(root.value)
     })
 

     return {
       root
     }
   },
   mounted() { /* 选项 API */
     console.log(this.$el)
   }
 }

beforeUpdate() and onBeforeUpdate()

数据更新时调用,发生在虚拟 DOM 打补丁以前。这里适合在更新以前访问现有的 DOM,好比手动移除已添加的事件监听器。

beforeUpdate对于跟踪对组件的编辑次数,甚至跟踪建立“撤消”功能的操做颇有用。

updated() and onUpdated()

DOM更新后,updated的方法即会调用。

<template>
    <div>
      <p>{{val}} | edited {{ count }} times</p>
      <button @click='val = Math.random(0, 100)'>Click to Change</button>
    </div>
 </template>

选项 API 方式:

export default {
   data() {
      return {
        val: 0
      }
   },
   beforeUpdate() {
      console.log("beforeUpdate() val: " + this.val)
   },
   updated() {
      console.log("updated() val: " + this.val
   }
 }

组合API的方式:

import { ref, onBeforeUpdate, onUpdated } from 'vue'
 
 export default {
   setup () {
     const count = ref(0)
     const val = ref(0)
 
     onBeforeUpdate(() => {
       count.value++;
       console.log("beforeUpdate");
     })
 
     onUpdated(() => {
       console.log("updated() val: " + val.value)
     })
 
     return {
       count, val
     }
   }
 }

这些方法颇有用,可是对于更多场景,咱们须要使用的watch方法检测这些数据更改。 watch 之因此好用,是由于它给出了更改后的数据的旧值和新值。

另外一种选择是使用计算属性来基于元素更改状态。

beforeUnmount() 和 onBeforeUnmounted()

在卸载组件实例以前调用。在这个阶段,实例仍然是彻底正常的。

在 选项 API中,删除事件侦听器的示例以下所示。

// 选项 API
export default {
   mounted() {
     console.log('mount')
     window.addEventListener('resize', this.someMethod);
   },
   beforeUnmount() {
     console.log('unmount')
     window.removeEventListener('resize', this.someMethod);
   },
   methods: {
      someMethod() {
         // do smth
      }
   }
}
// 组合API
import { onMounted, onBeforeUnmount } from 'vue' 

 export default {
   setup () {
 
     const someMethod = () => {
       // do smth
     }
 
     onMounted(() => {
       console.log('mount')
       window.addEventListener('resize', someMethod);
     })
 
     onBeforeUnmount(() => {
       console.log('unmount')
       window.removeEventListener('resize', someMethod);
     })
 
   }
 }

实际操做的一种方法是在Vite,vue-cli或任何支持热重载的开发环境中,更新代码时,某些组件将自行卸载并安装。

unmounted() 和 onUnmounted()

卸载组件实例后调用。调用此钩子时,组件实例的全部指令都被解除绑定,全部事件侦听器都被移除,全部子组件实例被卸载。

import { onUnmounted } from 'vue'

export default {
  setup () { /* 组合 API */

    onUnmounted(() => {
      console.log('unmounted')
    })

  },
  unmounted() { /* 选项 API */
    console.log('unmounted')
  }
}

activated() and onActivated()

keep-alive 缓存的组件激活时调用。

例如,若是咱们使用keep-alive组件来管理不一样的选项卡视图,每次在选项卡之间切换时,当前选项卡将运行这个 activated 钩子。

假设咱们使用keep-alive包装器进行如下动态组件。

<template>
   <div>
     <span @click='tabName = "Tab1"'>Tab 1 </span>
     <span @click='tabName = "Tab2"'>Tab 2</span>
     <keep-alive>
       <component :is='tabName' class='tab-area'/>
     </keep-alive>
   </div>
</template>

<script>
import Tab1 from './Tab1.vue'
import Tab2 from './Tab2.vue'

import { ref } from 'vue'

export default {
  components: {
    Tab1,
    Tab2
  },
  setup () { /* 组合 API */
    const tabName = ref('Tab1')

    return {
      tabName
    }
  }
}
</script>

Tab1.vue组件内部,咱们能够像这样访问activated钩子。

<template>
 <div>
 <h2>Tab 1</h2>
 <input type='text' placeholder='this content will persist!'/>
 </div>
</template>

<script>
import { onActivated } from 'vue'

export default {
 setup() {
    onActivated(() => {
       console.log('Tab 1 Activated')
    })
 }
} 
</script>

deactivated() 和 onDeactivated()

keep-alive 缓存的组件停用时调用。

这个钩子在一些用例中颇有用,好比当一个特定视图失去焦点时保存用户数据和触发动画。

import { onActivated, onDeactivated } from 'vue'

export default {
  setup() {
    onActivated(() => {
       console.log('Tab 1 Activated')
    })

    onDeactivated(() => {
       console.log('Tab 1 Deactivated')
    })
  }
}

如今,当咱们在选项卡之间切换时,每一个动态组件的状态都将被缓存和保存。

image

Vue3 调试钩子

Vue3 为咱们提供了两个可用于调试目的的钩子。

  1. onRenderTracked
  2. onRenderTriggered

这两个事件都带有一个debugger event,此事件告诉你哪一个操做跟踪了组件以及该操做的目标对象和键。

onRenderTracked

跟踪虚拟 DOM 从新渲染时调用。钩子接收 debugger event 做为参数。此事件告诉你哪一个操做跟踪了组件以及该操做的目标对象和键。

<div id="app">
  <button v-on:click="addToCart">Add to cart</button>
  <p>Cart({{ cart }})</p>
</div>
const app = Vue.createApp({
  data() {
    return {
      cart: 0
    }
  },
  renderTracked({ key, target, type }) {
    console.log({ key, target, type })
    /* 当组件第一次渲染时,这将被记录下来:
    {
      key: "cart",
      target: {
        cart: 0
      },
      type: "get"
    }
    */
  },
  methods: {
    addToCart() {
      this.cart += 1
    }
  }
})

app.mount('#app')

renderTracked

当虚拟 DOM 从新渲染为 triggered.Similarly 为renderTracked,接收 debugger event 做为参数。此事件告诉你是什么操做触发了从新渲染,以及该操做的目标对象和键。

用法:

<div id="app">
  <button v-on:click="addToCart">Add to cart</button>
  <p>Cart({{ cart }})</p>
</div>
const app = Vue.createApp({
  data() {
    return {
      cart: 0
    }
  },
  renderTriggered({ key, target, type }) {
    console.log({ key, target, type })
  },
  methods: {
    addToCart() {
      this.cart += 1
      /* 这将致使renderTriggered调用
        {
          key: "cart",
          target: {
            cart: 1
          },
          type: "set"
        }
      */
    }
  }
})

app.mount('#app')

总结

不管你选择使用选项API仍是 组合API,不只要知道要使用哪一个生命周期挂钩,并且要知道为何要使用它,这一点很重要。

对于许多问题,可使用多个生命周期钩子。可是最好知道哪一个是最适合你用例的。不管如何,你都应该好好考虑一下,并有充分的理由去选择一个特定的生命周期钩子。

我但愿这能帮助你们更多地理解生命周期钩子以及如何在你们的项目中实现它们。

~完,我是刷碗智,我要去刷碗了,骨的白。


代码部署后可能存在的BUG无法实时知道,过后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给你们推荐一个好用的BUG监控工具 Fundebug

原文:https://learnvue.co/2020/12/h...

交流

文章每周持续更新,能够微信搜索「 大迁世界 」第一时间阅读和催更(比博客早一到两篇哟),本文 GitHub https://github.com/qq449245884/xiaozhi 已经收录,整理了不少个人文档,欢迎Star和完善,你们面试能够参照考点复习,另外关注公众号,后台回复福利,便可看到福利,你懂的。

相关文章
相关标签/搜索