图示
上图是Vue官方给的生命周期图示,该图贯穿全文,先浏览一下,咱们一步步的来
(本文不涉及源码分析,因为本人也不太懂源码,只是相当于做个笔记,恳求大佬补充或纠错)
beforeCreate 调用前 : new Vue()
Vue是一个简单的构造函数,调用之后
- 合并配置
- 初始化生命周期
- 初始化事件中心
- 初始化渲染
完成后调用第一个生命周期钩子:beforeCreate
created 调用前:
- 初始化
inject - 初始化
props,methods,data,computed,watch - 初始化
provide
完成后调用:created
可见,created 调用时,数据已经初始化好了,一般在这个钩子里进行网络请求
beforeMount 调用前:
- 检查有无 el 选项,若没有 el 选项,生命周期会停止,等待手动调用 $mount(el)
- 若有 el 选项,则检查有无 template 选项,若有则将 template 编译成 render 函数,若没有则将 el 的outHTML 属性的值(是个字符串)作为模板,随后编译成 render 函数
来一步步的验证一下:
- 没有 el 且没有调用 $mount() 的情况,生命周期到 created 就结束了,如下图可以看到 beforeMount 没有被调用
之后我们手动调用 $mount(el) ,生命周期恢复正常
- 有 el 的情况,检查有无 template ,若有,则将 template 编译成 render 函数,经一系列步骤(稍后阐述)后渲染成真实DOM
可以看到 template 替换掉了初始的 id 为 app 的 Div
若没有 template ,则将el的 outerHTML 属性的值作为 template
直接使用render函数:
除了通过 el ,template ,也可以直接写成 render 函数,特别是在开发的时候(脚手架构建),因为开发版本是Runtime Only,不带有 Compiler ,编译操作是通过 vue-loader 完成的
下面看下一直接使用 render 函数的效果:
优先级问题 :
render > template > el
根据上面的讲述,这个结论已经是不证自明了
验证小总结:
el 是必须要有的,它提供了一个页面上已经存在的 DOM 元素作为 Vue 实例的挂载目标,不然连目标都没有,也没必要创建一个 Vue 实例了。至于 template ,它也是要有的,如果没有提供 template 选项,还是会找到el 的 outerHTML 属性作为 template ,template 和 el.outerHTML 的值都是模板字符串,目的就是为了编译成 render 函数,当然,最后也说了,可以直接使用 render ,特别是在开发版本中,必须要使用 render 。
说了这么多,beforeMount 这个钩子调用前,主要是通过编译确保得到 render 函数,下一步就好将虚拟 DOM 变成真实 DOM 了
所以,不开玩笑的说,beforeMount 钩子好像没有什么实质性的作用,在里面写代码好像也没有啥意义(个人愚见)
此时,beforeMount 调用,进行下一步
mounted 调用前:
这里进行的是页面渲染,大致步骤是:render → Vnode → vm.$el
然后用 vm.$el 代替 el
具体实现要去看源码,我就不误人子弟了
好了,到这里,调用了 mounted 钩子,在 mounted 钩子中,已经可以获取到真实的 DOM 节点了,一般在这里进行 DOM 相关的操作。
beforeUpdata 调用前:
数据发生改变,则调用 beforeUpdate
需要注意的是,在 beforeUpdate 钩子中,只能获取到数据,不能获取到已更新的 DOM ,因为此时 DOM 还没有更新。同理,在同步代码中,更不可能获取到已更新的 DOM ,例如:
那我不服气,硬是要在获取到已更新的DOM怎么办呢?也是有办法的,可以使用 vm.nextTick() ,其实 nextTick 也没那么神奇,相当于一个回调,等DOM更新了再调用,其中代码的执行顺序在 beforeUpdata 之后。出门左拐 nextTick官网示例 ,不赘述了。
upDated 调用前:
在这里,经历一系列的 patch 、diff 后,虚拟 DOM 重新渲染。
要注意 diff 算法,当改变的数据内容没有发生变化,或者没有改变 DOM 中引用的数据时,不会执行更新。
没什么好说的(其实是没什么会说的,等我研究懂源码再杀回来!!),看图:
DOM 重新渲染后,upDated 钩子就调用了,在该钩子中,已经可以获取到更新之后的 DOM 了。
beforeDestroy 调用前
看个例子吧:
子组件内容:
父组件内容:v-for循环渲染子组件,点击按钮更新数据,移除一个子组件
开始操作:
除了这种操作,路由跳转组件等也会触发该生命周期钩子,但不包括被 keep-alive 包裹的组件,这里不赘述。
destroyed 调用前
beforeDestroy 钩子触发之后,会卸载 watcher ,卸载事件监听器,清除父子关系,随后调用 destroyed 钩子。
至此,生命周期完毕。
如我所说,研究懂源码之后,我会升级本文章的。
文章中如果有错误,不严谨的地方,烦请大佬指出,看到后会第一时间修改。
感谢阅读
完