生命周期
每一个组件或者实例都会经历一个完整的生命周期,总共分为三个阶段:初始化、运行中、销毁
- 一个组件或者实例的生命周期都是通过new开始的
- 实例化之后,内部会做一些初始化事件与生命周期相关的配置
初始化阶段
初始化阶段会执行四个钩子函数
- beforeCreate
在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。 - created
在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前尚不可用。 - beforeMount
在挂载开始之前被调用:相关的 render 函数首次被调用。 - mounted
实例被挂载后调用,这时 el 被新创建的 vm. e l 替 换 了 。 如 果 根 实 例 挂 载 到 了 一 个 文 档 内 的 元 素 上 , 当 m o u n t e d 被 调 用 时 v m . el 替换了。 如果根实例挂载到了一个文档内的元素上,当mounted被调用时vm. el替换了。如果根实例挂载到了一个文档内的元素上,当mounted被调用时vm.el也在文档内。
运行阶段
运行阶段会执行两个钩子函数
- beforeUpdate
数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。 - updated
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。
销毁
销毁会执行两个钩子函数
- beforeDestroy
实例销毁之前调用。在这一步,实例仍然完全可用。 - destroyed
实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
过程
-
实例、组件通过new Vue() 创建出来之后会初始化事件和生命周期,然后就会执行beforeCreate钩子函数,这个时候,数据还没有挂载到,只是一个空壳,无法访问到数据和真实的dom,一般不做操作
-
挂载数据,绑定事件等等,然后执行created函数,这个时候已经可以使用到数据,也可以更改数据,在这里同步更改数据不会触发updated函数,一般可以在这里做初始数据的获取。 做异步ajax,绑定初始化事件
-
接下来开始找实例或者组件对应的模板,编译模板为虚拟dom放入到render函数中准备渲染,然后执行beforeMount钩子函数,在这个函数中虚拟dom已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发updated,这是在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始化数据的获取
-
接下来开始render,渲染出真实dom,然后执行mounted钩子函数,此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了,可以在这里操作真实dom等事情…
-
当组件或实例的数据更改之后,会立即执行beforeUpdate,然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染,一般不做什么事儿
-
当更新完成后,执行updated,数据已经更改完成,dom也重新render完成,可以操作更新后的dom
-
当经过某种途径调用$destroy方法后,立即执行beforeDestroy,一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件等等
-
组件的数据绑定、监听…去掉后只剩下dom空壳,这个时候,执行destroyed,在这里做善后工作也可以
代码展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<my-component></my-component>
</div>
<template id="my-component">
<div>
<h1 id="title">hello---{{msg}}</h1>
<p><input type="text" v-model="msg"></p>
<button @click="destroy">销毁组件</button>
</div>
</template>
</body>
<script src="../vue.js"></script>
<script>
//初始化阶段
//1.一个组件或者实例的生命周期都是通过new开始的
//2.实例化之后,内部会做一些初始化事件与生命周期相关的配置
Vue.component("my-component",{
template:"#my-component",
data(){
return {
msg:1
}
},
methods:{
destroy(){
this.$destroy()
}
},
//3.这个钩子函数初始化的时候立即执行,此钩子函数里面获取不到数据
//同时页面中的真实dom节点也没有挂载出来,null
beforeCreate(){
console.log("beforeCreate......")
console.log(this.msg)
console.log(document.getElementById("title"))
},
//4.created钩子函数内部的数据已经被挂载,但是真实dom节点仍然未被渲染
//在这个钩子函数里面,如果同步的去更改数据的话,运行中钩子函数是不会执行的。
//通常会在这个钩子函数里面进行ajax异步操作,另外还可以做一些初始化事件的绑定
created(){
//this.msg = 2
console.log("created......")
console.log(this.msg)
console.log(document.getElementById("title"))
//定时器
this.timer = setInterval(()=>{
console.log(111)
this.msg++
},3000)
},
//5.接下来的过程,就是组件或实例去查找各自的模板,然后将其编译成虚拟dom,即将其放入render函数中做初始化渲染
//6.beforeMount代表dom马上就要渲染出来,但是还没有真正的渲染出
//此钩子函数与created基本一致,可以做ajax与事件初始化绑定操作
beforeMount(){
console.log("beforeMount......")
console.log(this.msg)
console.log(document.getElementById("title"))
},
//生成好了虚拟dom,然后在render函数里面替换对应的el,渲染真实dom节点
//相当于在render函数里面做一个初始换渲染操作
/*render(){
console.log("render......")
}*/
//7.mounted钩子函数是初始化阶段最后一个钩子函数
//数据已经挂载完毕,真实dom已经渲染出来
//这个钩子函数可以用来做一些实例化的相关操作 例如:拖拽效果
mounted(){
console.log("mounted......")
console.log(this.msg)
console.log(document.getElementById("title"))
},
//8.运行时钩子函数初始化阶段是不会执行的
//只有dom挂载完毕,当数据发生变化的时候,beforeUpdate钩子函数才会执行
beforeUpdate(){
console.log("beforeUpdate......")
console.log(this.msg)
console.log(document.getElementById("title").innerHTML)
},
//9.这个钩子函数里面dom获取的数据内容是更新后的内容
//生成新的虚拟dom,与上一次的虚拟dom结构进行对比,比较出来差异(diff)再去进行真实的dom渲染
//这里的updated中的真实dom里面显示的数据,跟在内存里面的data数据趋于一致
updated(){
console.log("updated......")
console.log(document.getElementById("title").innerHTML)
},
//10.组件销毁就会触发,vm.$destroy()方法被执行的时候,组件就会销毁
//销毁之前,分手之前,在吵架
//做一些清除事件绑定,清除定时器相关操作
beforeDestroy(){
console.log("beforeDestroy......")
clearInterval(this.timer)
},
//11.完成时,吵架结束,已经分手
//数据绑定不存在了
//销毁后dom结构还存在,分手后以前的回忆没有忘记,未清除
destroyed(){
console.log("destroyed......")
}
})
new Vue({}).$mount("#app")
</script>
</html>