Vue中的生命周期详细解读
作者:飘飘~
前言
每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。
说明:Vue生命周期是学习Vue非常重要的知识点,其中生命周期钩子在程序开发中有着十分重要的地位。
在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码。
一、生命周期图解
二、八个重要阶段
1.beforeCreate( 创建前 )
在组件实例初始化完成之后立即调用。
interface ComponentOptions { beforeCreate?(this: ComponentPublicInstance): void }
会在实例初始化完成、props 解析之后、 data()
和 computed
等选项处理之前立即调用。
注意,组合式 API 中的 setup()
钩子会在所有选项式 API 钩子之前调用, beforeCreate()
也不例外。
2.created ( 创建后 )
在组件实例处理完所有与状态相关的选项后调用。
interface ComponentOptions { created?(this: ComponentPublicInstance): void }
当这个钩子被调用时,以下内容已经设置完成:响应式数据、计算属性、方法和侦听器。然而,此时挂载阶段还未开始,因此 $el
属性仍不可用。
3.beforeMount(挂载前)
在组件被挂载之前调用。
interface ComponentOptions { beforeMount?(this: ComponentPublicInstance): void }
当这个钩子被调用时,组件已经完成了其响应式状态的设置,但还没有创建 DOM 节点。它即将首次执行 DOM 渲染过程。
这个钩子在服务端渲染时不会被调用。
4.mounted(挂载完成)
在组件被挂载之后调用。
interface ComponentOptions { mounted?(this: ComponentPublicInstance): void }
组件在以下情况下被视为已挂载:
- 所有同步子组件都已经被挂载。(不包含异步组件或 <Suspense> 树内的组件)
- 其自身的 DOM 树已经创建完成并插入了父容器中。注意仅当根容器在文档中时,才可以保证组件 DOM 树也在文档中。
这个钩子通常用于执行需要访问组件所渲染的 DOM 树相关的副作用,或是在服务端渲染应用中用于确保 DOM 相关代码仅在客户端被调用。
5.beforeUpdate(修改前)
在组件即将因为一个响应式状态变更而更新其 DOM 树之前调用。
interface ComponentOptions { beforeUpdate?(this: ComponentPublicInstance): void }
这个钩子可以用来在 Vue 更新 DOM 之前访问 DOM 状态。在这个钩子中更改状态也是安全的。
6.updated(更新后)
在组件因为一个响应式状态变更而更新其 DOM 树之后调用。
interface ComponentOptions { updated?(this: ComponentPublicInstance): void }
父组件的更新钩子将在其子组件的更新钩子之后调用。
这个钩子会在组件的任意 DOM 更新后被调用,这些更新可能是由不同的状态变更导致的。
如果你需要在某个特定的状态更改后访问更新后的 DOM,请使用 nextTick() 作为替代。
7.beforeDestroy(销毁前)
在实例销毁之前调用,实例仍然完全可用,
这一步还可以用this来获取实例,一般在这一步做一些重置的操作,比如清除掉组件中的定时器 和 监听的dom事件
8.destroyed(销毁后)
在实例销毁之后调用,调用后,所以的事件监听器会被移出,所有的子实例也会被销毁,该钩子在服务器端渲染期间不被调用
三、代码演示
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vue的数据模型</title> <script src="../js/vue.js"></script> </head> <body> <div id="app"> {{msg}} <button @click="test">按钮</button> <ul id="My"> <li>111</li> </ul> </div> <script> let vm = new Vue({ el: "#app", data: { msg: "hello", // time: new Date(), msg: true, }, methods: { test() { console.log("点击按钮-----"); }, }, //钩子函数,生命周期,在beforeCreate这个阶段, //现在属性msg数据还没有绑定到实例对象vm上,所以数据不能输出来 //钩子函数在new Vue()之后执行 Vue内部给实例添加了一些属性(data)和方法(methods) //钩子函数在data和methods之前执行 beforeCreate() { //属性或方法声明了,但没有和实例绑定 console.log( "beforeCreated函数执行了,---但此时获取不到实例内的属性和方法", this.msg ); //输出:undefined }, //生命周期,在created这个阶段属性msg数据绑定到vm实例对象上 //data和methods之后执行 created() { //属性和方法绑定到实例上,可以通过实例进行调用 console.log( "created执行了,---此时可以获取data和methods中的变量值", this.msg ); //输出:'hello }, /* 2.挂载 */ //虚拟dom挂载成真实dom之前,不可以操作dom //使用场景,预处理data,不会触发update钩子函数 beforeMount() { console.log( "beforeMount执行了,---但此时获取不到真实的DOM节点", "挂载之前" ); console.log(document.getElementById("app")); }, //虚拟dom挂载完毕变成真实dom,此处可以可以操作dom节点 mounted() { console.log("mounted执行了,---此时可以获取到真实的DOM", "挂载后"); console.log(document.getElementById("app")); }, /*2.更新*/ //更新前 beforeUpdate() { console.log(document.querySelectorAll("#My>li")); console.log( "beforeUpdate函数执行了,---此时获取不到更新的真实DOM", this.msg ); }, //更新后 //场景:获取到更新的真实DOM节点 updated() { console.log(document.querySelectorAll("#My>div")); console.log( "update函数执行了,---此时可以获取到更新的真实DOM", this.msg ); }, /*销毁*/ //销毁监听 beforeDestroy() { console.log("beforeDestroy函数执行了", this.msg); }, destroyed() { console.log("destroy函数执行了", this.msg); }, }); setInterval(() => { vm.$destroy(); }, 5000); </script> </body> </html>