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() 组件卸载之后

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

相关推荐
星空寻流年12 分钟前
css3响应式布局
前端·css·css3
Anesthesia丶33 分钟前
Vue3 + naive-ui + fastapi使用心得
vue.js·ui·fastapi
Rverdoser1 小时前
代理服务器运行速度慢是什么原因
开发语言·前端·php
陌尘(MoCheeen)1 小时前
技术书籍推荐(002)
java·javascript·c++·python·go
航Hang*1 小时前
前端项目2-01:个人简介页面
前端·经验分享·html·css3·html5·webstorm
油丶酸萝卜别吃1 小时前
openlayers利用已知的三个经纬度的坐标点 , 绘制一个贝塞尔曲线
javascript
MaisieKim_1 小时前
python与nodejs哪个性能高
前端·python·node.js
Spider Cat 蜘蛛猫1 小时前
【一】浏览器的copy as fetch和copy as bash的区别
javascript·ajax·bash·逆向·fetch
Frankabcdefgh2 小时前
前端进化论·JavaScript 篇 · 数据类型
javascript·安全·面试·数据类型·操作符·初学者·原理解析
水煮白菜王2 小时前
深入理解 Webpack 核心机制与编译流程
前端·webpack·node.js