vue全部功能的实现都是围绕其生命周期进行的,在生命周期的不一样阶段调用对应的钩子函数能够实现组件数据管理和DOM渲染两大重要功能。学习实例的生命周期,能帮助咱们理解vue实例的运行机制,更好地利用钩子函数完成咱们的业务代码。vue
一、即将建立:对应的钩子函数为beforeCreate。此阶段为实例初始化以后,此时的数据观察和事件机制都未造成。node
<template> <div class="router-page-wrap" style="background: #fc595d;"> this is usercenter <input type="text" v-model="message" ref="input"> {{message}} </div> </template> <script> var common = require('common'); module.exports = { data : function() { return { message : 'not update' } }, beforeCreate : function () { console.log('this is beforeCreate :', this.message, this.$refs.input); } } </script>
获得的结果是:dom
此时,实例中的data和el都是undefined。所以,在beforeCreate钩子函数中不能使用data中的数据,也不能得到DOM节点。异步
二、建立完毕:对应的钩子函数为created。在这个阶段vue实例已经建立,咱们在一样打印一下data和DOM元素。函数
上面代码的基础上咱们添加created钩子函数:工具
获得的结果是什么呢??学习
此时,咱们可以读取到数据data的值,可是DOM尚未生成,因此和DOM相关的属性还不存在,天然也就不能获取DOM元素。在Vue2的源码中也是这样描述的:ui
首先,运行new Vue()
的时候,会进入代码src/core/instance/index.js
的Vue构造方法中,并执行this._init()
方法。在_init
中,会对各个功能进行初始化,并执行beforeCreate
和created
两个生命周期方法。核心代码以下:this
initLifecycle(vm) initEvents(vm) callHook(vm, 'beforeCreate') initState(vm) callHook(vm, 'created') initRender(vm)
能够看到,到当执行钩子函数created时,complier尚未将template解析成render方法,DOM天然不能获取spa
三、即将挂载:对应的钩子函数是beforemount。在上个阶段咱们知道DOM还没生成,相关属性仍是undefined,那么此阶段为即将挂载,将发生什么呢?
增长一下代码:
打印一下,咱们获得:
结果好像和上一个阶段并无什么区别......弄的我好失落....那到底beforeMount这个阶段的意义是什么呢?难道这是vue给我设的一个坑??等等~,先别跳!!让咱们问问源(zu)码(zong)(︶.̮︶✽)
if (vm.$options.el) { vm.$mount(vm.$options.el) }
在vue2的源码中在讲述mount这一重要步骤时进行了一个关键的判断,就是判断vue的挂载节点是否存在!!那么,挂载节点时如何存在了的呢?这必定就是在beforeMount这一阶段完成的!让咱们立刻上代码实验一下刚才的断言。在这里换一种建立vue的方式。
如今咱们知道vue实例和DOM实际上是分开的两个概念,然而,vue实例的必须和DOM相关联并改变DOM才能完成它的使命。这就须要将Vue挂载到DOM上。所以,vue提供了一个el参数来肯定挂载的DOM节点。当咱们根据vue构造函数new出一个Vue时,只要设定了这个el元素,那么这个新的Vue一切操做将只对这个el及其子元素有效。
这时咱们将获得打印的结果以下:
能够看到,这里数据name的值还没被渲染到DOM中,然而经过id已经可以取得dom的根节点了,这个节点即挂载节点。
走到这里,beforeMount的意义已经逐渐清晰了。在这一阶段,咱们虽然依然得不到具体的DOM元素,但vue挂载的根节点已经建立,下面vue对DOM的操做将围绕这个el继续进行。在这个阶段vue成功得到了DOM王国国王--根元素el的信任,以后vue经过掌控“数据驱动”这台国家机器得到了对DOM王国的绝对统治权,“挟天子以令诸侯”,vue的全部命令都将在对DOM每一个元素的控制中获得精确执行。
beforeMount这个阶段是过渡性的,通常一个项目只能用到一两次,但它倒是意义非凡的!!在它以后vue将执行mount函数,带有vue属性的DOM及vue数据将所有被呈现,$refs将能够在DOM中使用并获取元素。最重要的是,以后咱们将迎来辉煌的mounted阶段。beforeMount这个过程在Vue2的源码中是这样描述的:
能够看出,$mount函数的操做都基于beforeMount阶段获取的根元素el。($mount函数将根据el,template,render属性调用render方法,即咱们平时说的compile过程。compile会把咱们写的vue语言编译成render(JSX),这一步通常都是构建工具帮咱们完成的啦,啦啦啦~)。
根据源码,_render方法执行完以后,会执行_mount方法,在这个过程当中会首先new出造成一个watcher对象,会运行传入的一个_render方法主要就是运行以前compile的render方法,造成vNode节点,也就是大名鼎鼎的虚拟DOM。拿到vNode后,传入vm._update()
方法,进行DOM更新。(watcher和下面将讲到的update涉及到虚拟DOM原理,会在之后的文章中结合vue详细说明,感受本身挖了一个坑~~)
四、渲染完毕:对应的钩子函数是mounted。mounted是平时咱们使用最多的函数了,通常咱们的异步请求都写在这里。在这个阶段,数据和DOM都已被渲染出来。
继续增长代码:
打印一下:
“千呼万唤始出来”,咱们终于获得了想要的结果!!
不过,这并非最终的结果。(◐ˍ◑),由于更新即将到来~
五、即将更新渲染:对应的钩子函数是beforeUpdate。vue遵循数据驱动DOM的原则,当咱们修改vue实例的data时,vue会自动帮咱们更新视图。那么当咱们调用beforeMount函数时,会发生什么呢?
为了说明数据变化对DOM的影响,我首先更新代码,增长了一个method方法。到目前为止,代码以下:
<template> <div class="router-page-wrap" style="background: #fc595d;"> this is usercenter <input type="text" v-model="message" ref="input" id="input"> <em ref="em">{{message}}</em> <button v-touch:tap="messageChange">changeMessage</button> </div> </template> <script> var common = require('common'); module.exports = { data : function() { return { message : '个人博客园' } }, methods : { messageChange : function () { this.message = 'emma的博客园' } }, beforeCreate : function () { console.log('this is beforeCreate :', this.message, this.$refs.input); }, created : function () { console.log('this is created :') console.log('message :' , this.message); console.log('DOM element:', this.$refs.input); }, beforeMount : function () { console.log('this is beforeMount :') console.log('message :' , this.message); console.log('DOM element:', this.$refs.input); }, mounted : function () { console.log('this is mounted :') console.log('message :' , this.message); console.log('DOM element:', this.$refs.input); }, beforeUpdate : function () { console.log('=即将更新渲染='); let name = this.$refs.em.innerHTML; console.log('name:'+name); } } </script>
运行以后:
能够看到,beforeUpdate函数在数据更新后并没当即更新数据,可是DOM中的数据已经改变,这是Vue双向数据绑定的做用,之后也会讲到,哇塞,又一个坑~~
六、更新渲染后:对应的钩子函数是updated。为了避免使看到同-函数在不能阶段的效果,我注释掉beforeUpdate函数,添加update函数并绑定了刚才的click事件。
咱们获得预料中的结果:
如今DOM终于和咱们更改过的内容同步了!
七、销毁以前:对应的钩子函数是beforeDestroy。到上一步vue已经成功的经过数据驱动DOM更新,当咱们不在须要vue操纵DOM时,就须要销毁Vue,也就是清除vue实例与DOM的关联,调用destroy方法能够销毁当前组件。在销毁前,会触发beforeDestroy钩子函数。
八、销毁以后:对应的钩子函数是destroyed。在销毁后,会触发destroyed钩子函数。
咱们经过调用destroy函数观察vue实例销毁先后vue和DOM的变化。增长代码以下:
调用destroy前,咱们改变name,在视图随之改变,beforeDestroy获取的DOM和咱们更新后的结果一致。
调用destroy后,咱们改变name,视图不会改变,destroyed也不会获取到DOM信息了。
销毁以前,修改name的值,能够成功修改视图显示的内容为更新后的内容,调用实例的$destroy( )方法以后,vue实例与DOM的关系解绑,vue数据的任何变化都不会使DOM更新,说明实例成功被销毁了~~
vue的生命周期的思想贯穿在组件开发的始终,经过熟悉其生命周期调用不一样的钩子函数,咱们能够准确地控制数据流和其对DOM的影响;vue生命周期的思想是Vnode和MVVM的生动体现和继承,之后我将继续学习相关的知识,在一个更高的高度学习vue,我会在学习中继续和你们不断分享学习的点滴感悟,更但愿得到你们对个人文章积极提出问题和建议,咱们共同讨论,共同进步~~