对Vue生命周期的理解

一、生命周期概念

首先,每一个vue实例都有一个完整的生命周期,主要分为五个阶段:创建、初始化、渲染、运行、销毁。 也就是从创建(new Vue())、初始化数据(init)、编译模板(render function)、挂载Dom($el)、渲染($mount)→更新(update)→渲染(Virtual Dom re-Render)、销毁(destory)等一系列过程,我们称这是Vue的生命周期。

通俗说就是Vue实例从创建到销毁的过程,就是生命周期。

二、vue生命周期图解

三、具体详解

1.创建阶段

new Vue() 创建

表示开始创建一个vue实例对象。

2.初始化阶段

创建之后这个时候就会调用this._init()方法,

letuid =0Vue.prototype._init =function(options){constvm= thisvm._uid = uid++  // 组件唯一标识vm.$options= mergeOptions(  // 合并optionsresolveConstructorOptions(vm.constructor),options|| {},vm)  ...  initLifecycle(vm) // 开始一系列的初始化  initEvents(vm)  initRender(vm)  callHook(vm,'beforeCreate')  initInjections(vm)  initState(vm)  initProvide(vm)  callHook(vm,'created')  ...if(vm.$options.el) {vm.$mount(vm.$options.el)  }}

2.1 合并options配置

1. 初始化new Vue

在执行new Vue构造函数时,参数就是一个对象,也就是用户自定义配置;会将它和vue之前定义的原型方法、全局API 属性、还有全局的Vue.mixin内的参数,将这些都合并成一个新的options, 最后赋值给一个新的属性$options。

2. 子组件初始化

如果是子组件初始化, 除了合并以上那些外,还会将父组件的参数进行合并, 如有父组件定义在子组件上的event, props 等等。

经过合并之后就可以通过this.options.data访问到用户定义的data函数,this.options.name访问到用户定义的组件名称,这个合并后的属性很重要,会被经常使用到。

2.2 初始化事件和生命周期

刚初始化一个空的vue实例对象,这个时候只有一些生命周期函数和默认的事件,其他的东西都还为创建。

1.initLifecycle(vm)

确认组件(也是vue实例)的父子关系以及初始化vm.$parent, $children实例属性。后面可进行事件的触和数据的传递。

2.initEvents(vm)

主要作用是将父组件在使用v-on 或者 @ 注册自定义事件添加到子组件的事件中心中。

原生事件

在执行initEvent之前模板编译阶段,会判断遇到的是html标签名 还是组件名。

如果是html标签名,就会在转为真是dom之后使用addEventListener注册浏览器原生事件。 当然这个步骤是在挂载dom的最后阶段,这歌时候是初始化阶段,主要处理自定义事件。

自定义事件

在经过合并options 阶段后, 子组件就可以从 vm.$options._parentListeners读取到父组件传过来的自定义事件。 通过updateListeners方法, 它的作用是借助之前定义的$on, $emit方法, 完成父子组件事件的通信。

3. initRender(vm)

主要作用是挂载,将render函数转化为vnode的方法。

exportfunctioninitRender(vm){  vm._vnode = null  ...

  vm._c =(a,b,c,d) =>createElement(vm,a,b,c,d,false)//转化编译器的vm.$createElement =(a,b,c,d) =>createElement(vm,a,b,c,d,true)// 转化手写的  ...}

主要作用是挂载vm._c 和 vm.createElement两个方法,它门只是最后一个参数不同,这两个方法都可以将render函数转为vnode,从命名大家应该可以看出区别,vm.c转换的是通过编译器将template转换而来的render函数;而vm.createElement 两个方法,它门只是最后一个参数不同,这两个方法都可以将render函数转为vnode, 从命名大家应该可以看出区别,vm._c 转换的是通过编译器将template 转换而来的 render 函数; 而 vm.createElement两个方法,它门只是最后一个参数不同,这两个方法都可以将render函数转为vnode,从命名大家应该可以看出区别,vm.c转换的是通过编译器将template转换而来的render函数;而vm.createElement 转换的是用户自定义的 render 函数, 比如:

new Vue({data: {    msg:'hello Vue!'},  render(h) {// 这里的 h 就是vm.$createElementreturnh('span',this.msg);    }}).$mount('#app');

4.callHook(vm, ''beforeCreate)

执行beforeCreate里的内容;

灵魂一问:请问可以在beforeCreate 钩子内通过 this 访问到data中定义的变量么,为什么? 请问这个钩子可以做什么?

是不可以访问的。 因为在vue 初始化阶段, 这个时候data 中的变量还没有挂载到this 上, 这个时候访问值会是 undefined。 beforeCreate 这个钩子在平时业务开发中比较少用。 像插件内部install 方法通过Vue.use 方法安装时一般会选在beforeCreate 这个钩子内执行, vue-router 和 vuex 就是这么干的。

2.3 初始化注入和校验

1. initInjections(vm) 主要作用是初始化inject,可以访问到对应的依赖。

inject 和 provide 是vue@2.2 版本添加的一对需要一起使用的API, 它允许父级组件向它之后的子孙组件提供依赖,让子孙组件无论嵌套多深都可以访问到。

provide : 提供一个对象或是返回一个对象的函数。 inject : 是一个字符串数组或对象。

举一个栗子:

app.vue 根组件export default {  provide() {    return {      app: this    }  },  data() {    return {      info:'hello world!'}  }}child.vue 子孙组件export default {  inject: ['app'],  methods: {    handleClick() {      this.app.info='hello vue 变 world 啦!'}  }}

这样可以简单实现vuex的功能,但是要注意组件之间层级关系,可能会造成混乱的现象。

2. initState(vm)

初始化会被使用到的状态:props、methods、data、computed、watch。

initProps(vm,propOptions)

主要作用是检测子组件接收的值是否符合规则,以及对应的值可以用this直接访问。

initMethods(vm, methods):

主要作用是将methods内的方法挂载到this下。命名规范的检查。不能与props的key重名,以及不能以_、$开头。

initData(vm)

主要作用是初始化data,挂载到this下。

3. initProvide(vm)

主要作用是初始化provide为子组件提供依赖。

4. callHook(vm, 'created')

作用是执行用户定义的created钩子函数,有mixin混入的也一并执行。

灵魂一问:请问methods 内的方法可以使用箭头函数么? 会产生怎样的结果?

答案: 是不可以使用箭头函数的, 因为箭头函数的this是在定义时就绑定的。 在vue的内部, methods 内每个方法的上下文是当前的vm组件实例, methods[key].bind(vm)。 如果使用箭头函数,函数的上下文就变成了父级的上下文, 也就是undefined了, 结果就是通过undefined 访问任何变量都会报错。

在created中,data和methods都已经初始化好了。最早也只能在created里调用methods方法和操作data数据。

另外注意

如果要在created阶段中进行dom操作,就要将操作都放在 Vue.nextTick() 的回调函数中,因为created() 钩子函数执行的时候 DOM 其实并未进行任何渲染,而此时进行 DOM 操作无异于徒劳,所以此处一定要将 DOM 操作的 js 代码放进 Vue.nextTick() 的回调函数中。 一般我们最好不要在created里操作dom。

Vue.nextTick( [callback, context] ):在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

3.渲染阶段

3.1 编译模板

从created到beforeMount的过程中,首先会判断vue实例中有没有el选项,如果有的话则进行下面的编译,但是如果没有el选项,则停止生命周期,直到vue实例上调用vm.$mount(el)。 如果有el,再判断是否有template参数,如果有,则把其当作模板编译成render函数,如果没有,则把外部的html作为模板编译。template中的模板优先级高于outer HTML模板。 在vue对象中还有一个render函数,它是以createElement作为参数,然后做渲染操作,而且我们可以直接嵌入JSX. 综合排名优先级:render函数选项 > template选项 > outer HTML

3.2 beforeMount

此函数进行时,模板已经在内存中编译好了,但是尚未挂载到页面中去,此时,页面还是旧的。

3.3 挂载

这一步,将内存中编译好的模板,替换到浏览器的页面中去。

3.4 mounted

这个节点表示整个vue实例已经初始化完毕了,此时组件已经脱离了创建-渲染阶段,进入到运行阶段。

4.运行阶段

运行阶段的生命周期函数式beforeCreate和created,这个两个事件会根据数据data的改变,有选择性的触发0次或多次。

4.1 beforeUpdate

这个生命周期里,页面中显示的数据还是旧的,但是咱们data的数据是最新的,页面尚未和最新的数据保持同步。

4.2 虚拟Dom重新编译渲染

这一步执行的是:现根据data中最新的数据,在内存中,重新渲染出一份最新的内存DOM树, 当最新的内存DOM树 被更新之后, 会把最新的内存DOM树,重新渲染到真是的页面中去,这个时候就完成了数据从data(Mode层)=> View(视图层)的更新。

4.3 Updated

updated执行时,页面和data已经保持同步了,都是最新的。

5.销毁阶段

5.1 beforeDestory

当执行beforeDestory钩子函数的时候,Vue实例就已经从运行阶段进入到了销毁阶段:

这个时候,实例上所有的data和methods,以及过滤器、指令等等 都还处于 可用状态,此时还没有真正执行销毁的过程。

5.2 destroyed

当执行到destroyed钩子函数的时候,组件已经被完全销毁了,此时Vue实例所有的data、methods、过滤器、指令... 都用不了。

总结:以上就是我所总结的对Vue生命周期的理解,也是参考了各方面的解释,结合自己的理解,对Vue生命周期进行梳理。当梳理了之后,你会发现你对Vue会又更好的理解。

更多内容请访问我的博客网站:http://www.jscwwd.com/article/5e65f4e249a13d1a89caf57c##toc412

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容