Vue 组件生命周期钩子函数

生命周期

Vue 3的生命周期钩子相比Vue 2有所调整,提供了更清晰和灵活的选项。它们包括:onBeforeMount、onMounted、onBeforeUpdate、onUpdated、onBeforeUnmount、onUnmounted,以及新增的setup()函数,它发生在所有生命周期钩子之前。生命周期就是一个页面从无到有再到无的一个过程

vue中的页面从无到有经历了一个什么过程呢?在Vue中,页面从无到有的过程涉及将.vue单文件组件编译成JavaScript渲染函数,然后通过构建工具(如Webpack)打包成浏览器可执行的代码。这些代码在浏览器中加载后,Vue实例被创建,使用实例的$mount方法将Vue应用挂载到指定的DOM元素上,最后通过Vue的响应式系统来渲染和更新页面内容,大致如下。

setup()

基本结构:

xml 复制代码
<script>
export default {
  setup(){ // 入口函数
    const message ='hello world'

    return{
      message
    }
  }
}
</script>

setup 中,我们可以使用 Vue 3 提供的多个工具函数来定义响应式数据、监听生命周期钩子、处理计算属性、声明事件处理函数等。这些函数包括:

  • reactive:用于创建响应式对象
  • ref:用于创建一个单一的响应式值
  • computed:用于创建计算属性
  • watch:用于监听响应式数据的变化
  • onMountedonUpdatedonUnmounted:用于监听生命周期钩子
  • toRefs:用于将响应式对象转换为普通对象

onBeforeMount/onMounted

onBeforeMount/onMounted分别表示组件挂载之前和之后执行,onbeforeMount会在组件挂载到DOM结构前执行,onMounted会在组件挂载后执行,所以如果说想获取 dom 结构的话,就需要在组件挂载到html上才能获取到。如下获取dom结构;

xml 复制代码
<template>
  <div if="box" ref="boxRef"></div>
</template>

<script>
import { onBeforeMount, onMounted, ref } from 'vue';

export default {
  setup() { // 入口函数
    const boxRef = ref(null)

    onMounted(() => {
      console.log('onMounted', boxRef.value)   // 挂载后执行
    })
    onBeforeMount(() => {
      console.log('onBeforeMounted', boxRef.value)  // 挂载前执行
    })

    return {
      boxRef
    }
  }
}
</script>

因为获取dom结构是document.xxx去获取,只有出现在html中的代码才算是document文档,vue中的代码在挂载前还没有还没有生成html文档,所以不能获取dom结构,即 onBeforeMount 是在组件挂载到DOM结构前执行。

但是如果一打开页面就发送一个http请求,那这个http请求应该放在挂载前还是挂载后,由于js引擎线程和http线程是可以同时工作,所以放在挂载前或挂载后都可以。

但是理论上是不能放在挂载前的,但实际上可以。如果放在挂载前,且在挂载前的函数中有操作dom结构的代码,如下。

xml 复制代码
<script>
import { onBeforeMount, onMounted, ref } from 'vue';
import axios from 'axios';

export default {
  setup() { // 入口函数
    const boxRef = ref(null)

    onBeforeMount(() => {
      axios.get('https://mock.mengxuegu.com/mock/66585c4db462b81cb3916d3e/songer/songer#!method=get')
        .then((res) => {
          console.log(res);
        })
    })

    return {
      boxRef
    }
  }
}

如示,为什么又可以拿到dom结构了呢?这是因为http请求需要耗时,实际上浏览器的挂载速度都比http请求快,在http请求完后组件早就挂载完了,这时候就可以获取到dom结构了,但是假设一种极端情况,http请求更快,浏览器还没挂载完成就获取dom结构,那么访问或操作dom就会出问题了,所以一般是将http请求放在onMounted里面。

onBeforeUpdate/onUpdated

onBeforeUpdate/onUpdated分别表示组件更新之前和组件更新之后。

xml 复制代码
<template>
   <button @click="add">Add - {{ count }}</button>
</template>

<script>
import { onBeforeUpdate, onUpdated } from 'vue'

export default {
  setup() { // 入口函数
    let count = ref(0)
    onBeforeUpdate(() => {
      console.log('onBeforeUpdate')
    })
    onUpdated(() => {
      console.log('onUpdated')
    })

    const add = () => {
      count.value++
    }

    return {
      add,
      count
    }
  }
}
</script>

即组件更新了就会触发onBeforeUpdate/onUpdated函数执行。

但是如果count没有放在组件上,也就是没有导致组件更新,只是count这个值在变化,onBeforeUpdate/onUpdated就不会触发,如下所示。

xml 复制代码
<template>
   <button @click="add"> Add </button>
</template>

<script>
import { onMounted, onBeforeMount, ref, onBeforeUpdate, onUpdated } from 'vue'

export default {
  setup() { // 入口函数
    let count = ref(0)
    onBeforeUpdate(() => {
      console.log('onBeforeUpdate')
    })
    onUpdated(() => {
      console.log('onUpdated')
    })

    const add = () => {
      count.value++
    }

    return {
      add,
      count
    }
  }
}

所以 onBeforeUpdate/onUpdated 是在因某个变量值改变导致组件更新才执行。

onBeforeUnmount/onUnmounted

onBeforeUnmount/onUnmounted 指在组件卸载前前或卸载后执行。

所以我们再创建一个子组件Child.vue,然后将它引入到App.vue中,再对这个子组件进行卸载操作,如下。

xml 复制代码
// Child.vue文件中

<template>
  <div>
    <h1>child</h1>
  </div>
</template>

<script setup>
import { onBeforeMount, onMounted, onBeforeUnmount, onUnmounted } from 'vue'

onBeforeUnmount(() => {
  console.log('onBeforeUnmount --- 卸载前')
})

onUnmounted(() => {
  console.log('onUnmounted --- 卸载后')
})
</script>
xml 复制代码
// App.vue文件中

<template>
  <Child v-if="showChild"></Child>
  <button @click="showChild = !showChild">hide child</button>
</template>

<script>
import Child from './components/Child.vue'
import { ref } from 'vue'

export default {

  components: {
    Child // 注册 Child 组件
  },
  setup() { // 入口函数

    let showChild = ref(true)
    return {
      showChild
    }
  }
}
</script>

需要注意如果不使用封装好的setup,如上引入组件时就需要components: {Child}注册组件,然后给子组件v-if绑定showChild值控制其存在或删除。打印如下;

但是如果将v-if改成v-show的话,就不会执行onBeforeUnmount/onUnmounted,如下;

这是因为v-show并没有将组件卸载,而是将组件上面的样式改为display:block,不显示在页面上,但是其dom结构还在,就不会触发onBeforeUnmount/onUnmounted函数。

最后如果父组件和子组件中都有挂载函数,那么执行顺序为父挂载前,子挂载前,子挂载后,父挂载后。

这个就非常好理解了,比如要装一个快递,准备大箱子(父组件 onBeforeMount),然后准备小箱子(子组件 onBeforeMount),接着将物品放入小箱子(子组件 onMounted),最后关闭并完成大箱子的打包(父组件 onMounted

总结

总结来说,Vue 3的生命周期钩子为开发者提供了细粒度的控制,使得我们可以在组件的不同阶段进行特定的操作。从组件的创建到挂载,再到更新和卸载,每个阶段都有相应的钩子函数来响应。

  1. onBeforeMount() 组件挂载之前
  2. onMounted() 组件挂载之后 -- 获取 dom 结构
  3. onBeforeUpdate() 某个变量值改变导致 组件更新之前
  4. onUpdated() 某个变量值改变导致 组件更新之后
  5. onBeforeunmount() 组件卸载之前
  6. onUnmounted() 组件卸载之后

好了,关于生命周期函数就介绍到这里了,觉得文章对你有所帮助可以点点赞哦🤗。

相关推荐
明月看潮生4 分钟前
青少年编程与数学 02-005 移动Web编程基础 14课题、性能优化
前端·青少年编程·性能优化·编程与数学·移动web
2401_8532757335 分钟前
vue请求后端需要哪些问题
前端·javascript·vue.js
AH_HH1 小时前
node-sass安装报错,换成sass
前端·rust·sass·node-sass
懒人Ethan1 小时前
SASS 简化代码开发的基本方法
前端·rust·sass
幽兰的天空2 小时前
在C#中,如何使用委托实现事件处理?
前端·数据库·c#
小满zs2 小时前
React第二十一章(useCallback)
前端·javascript·react.js
Mebius19162 小时前
不只是mini-react第一节:实现最简单mini-react
前端·javascript·react.js
alden_ygq2 小时前
Shell脚本编程的实用技巧和最佳实践
前端·chrome
有心还是可以做到的嘛2 小时前
跨层组件通信Vue3【传递数据和方法】
前端·javascript·vue.js
请叫我飞哥@2 小时前
HTML5 手风琴(Accordion)详解
前端·html·html5