生命周期
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
:用于监听响应式数据的变化onMounted
、onUpdated
和onUnmounted
:用于监听生命周期钩子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的生命周期钩子为开发者提供了细粒度的控制,使得我们可以在组件的不同阶段进行特定的操作。从组件的创建到挂载,再到更新和卸载,每个阶段都有相应的钩子函数来响应。
- onBeforeMount() 组件挂载之前
- onMounted() 组件挂载之后 -- 获取 dom 结构
- onBeforeUpdate() 某个变量值改变导致 组件更新之前
- onUpdated() 某个变量值改变导致 组件更新之后
- onBeforeunmount() 组件卸载之前
- onUnmounted() 组件卸载之后
好了,关于生命周期函数就介绍到这里了,觉得文章对你有所帮助可以点点赞哦🤗。