vue 生命周期 详解

详解 Vue Lifecycle

先来看看 vue 官网对 vue 生命周期的介绍

Vue Lifecycle

Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载 Dom、渲染→更新→渲染、销毁等一系列过程,我们称这是 Vue 的生命周期。通俗说就是 Vue 实例从创建到销毁的过程,就是生命周期。

每一个组件或者实例都会经历一个完整的生命周期,总共分为三个阶段:初始化、运行中、销毁。

  1. 实例、组件通过 new Vue() 创建出来之后会初始化事件和生命周期,然后就会执行 beforeCreate 钩子函数,这个时候,数据还没有挂载呢,只是一个空壳,无法访问到数据和真实的 dom,一般不做操作

  2. 挂载数据,绑定事件等等,然后执行 created 函数,这个时候已经可以使用到数据,也可以更改数据, 在这里更改数据不会触发 updated 函数,在这里可以在渲染前倒数第二次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取

  3. 接下来开始找实例或者组件对应的模板,编译模板为虚拟 dom 放入到 render 函数中准备渲染,然后执行 beforeMount 钩子函数,在这个函数中虚拟 dom 已经创建完成,马上就要渲染, 在这里也可以更改数据,不会触发 updated,在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取

  4. 接下来开始 render,渲染出真实 dom,然后执行 mounted 钩子函数,此时,组件已经出现在页面中,数据、真实 dom 都已经处理好了, 事件都已经挂载好了,可以在这里操作真实 dom 等事情...

  5. 当组件或实例的数据更改之后,会立即执行 beforeUpdate,然后 vue 的虚拟 dom 机制会重新构建虚拟 dom 与上一次的虚拟 dom 树利用 diff 算法进行对比之后重新渲染,一般不做什么事儿

  6. 当更新完成后,执行 updated,数据已经更改完成,dom 也重新 render 完成,可以操作更新后的虚拟 dom

  7. 当经过某种途径调用 $destroy 方法后,立即执行 beforeDestroy,一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件等等

  8. 组件的数据绑定、监听... 去掉后只剩下 dom 空壳,这个时候,执行 destroyed,在这里做善后工作也可以

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <aaa></aaa>
    </div>
<span class="hljs-tag">&lt;<span class="hljs-name">template</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"aaa"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"myp"</span>&gt;</span>A组件<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"destroy"</span>&gt;</span>destroy<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"msg"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>msg:{{msg}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

</body>
<script src="./vue.js"></script>

<script>
// 生命周期:初始化阶段 运行中阶段 销毁阶段
Vue.component("aaa",{
template:"#aaa",
data:function(){
return {msg:'hello'}
},
timer:null,
methods:{
destroy:function(){
this.$destroy()//
}
},
beforeCreate:function(){
console.log('beforeCreate: 刚刚 new Vue() 之后,这个时候,数据还没有挂载呢,只是一个空壳')
console.log(this.msg)//undefined
console.log(document.getElementsByClassName("myp")[0])//undefined
},
created:function(){
console.log('created: 这个时候已经可以使用到数据,也可以更改数据, 在这里更改数据不会触发 updated 函数')
this.msg+='!!!'
console.log('在这里可以在渲染前倒数第二次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取')
console.log('接下来开始找实例或者组件对应的模板,编译模板为虚拟 dom 放入到 render 函数中准备渲染')
},
beforeMount:function(){
console.log('beforeMount:虚拟 dom 已经创建完成,马上就要渲染, 在这里也可以更改数据,不会触发 updated')
this.msg+='@@@@'
console.log('在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取')
console.log(document.getElementsByClassName("myp")[0])//undefined
console.log('接下来开始 render,渲染出真实 dom')
},
// render:function(createElement){
// console.log('render')
// return createElement('div','hahaha')
// },
mounted:function(){
console.log('mounted:此时,组件已经出现在页面中,数据、真实 dom 都已经处理好了, 事件都已经挂载好了')
console.log(document.getElementsByClassName("myp")[0])
console.log('可以在这里操作真实 dom 等事情...')

    <span class="hljs-comment">//    this.$options.timer = setInterval(function () {</span>
    <span class="hljs-comment">//        console.log('setInterval')</span>
    <span class="hljs-comment">//         this.msg+='!'  </span>
    <span class="hljs-comment">//    }.bind(this),500)</span>
    },
    <span class="hljs-attr">beforeUpdate</span>:<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>){
    	<span class="hljs-comment">//这里不能更改数据,否则会陷入死循环</span>
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'beforeUpdate:重新渲染之前触发'</span>)
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染'</span>)         
    },
    <span class="hljs-attr">updated</span>:<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>){
    	<span class="hljs-comment">//这里不能更改数据,否则会陷入死循环</span>
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'updated:数据已经更改完成,dom也重新render完成'</span>)
    },
    <span class="hljs-attr">beforeDestroy</span>:<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>){
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'beforeDestory:销毁前执行($destroy方法被调用的时候就会执行),一般在这里善后:清除计时器、清除非指令绑定的事件等等...'</span>)
        <span class="hljs-comment">// clearInterval(this.$options.timer)</span>
    },
    <span class="hljs-attr">destroyed</span>:<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>){
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'destroyed:组件的数据绑定、监听...都去掉了,只剩下dom空壳,这里也可以善后'</span>)
    }
})



<span class="hljs-keyword">new</span> <span class="hljs-title class_">Vue</span>({
}).$mount(<span class="hljs-string">'#app'</span>)

</script>
</html>