Vue 实例有一个完整的生命周期,也就是从开始创建
、初始化数据
、编译模版
、挂载Dom -> 渲染
、更新 -> 渲染
、卸载
等一系列过程,我们称这是Vue的生命周期
总共分为8个阶段:
Vue的生命周期过程也会运行一些叫做生命周期钩子的函数
,这给了用户在不同阶段添加自己的代码的机会。
所有的生命周期钩子自动绑定 this 上下文
到实例中,因此你可以访问数据,对 property 和方法进行运算。
这意味着你不能使用箭头函数
来定义一个生命周期方法 (例如 created: () => this.fetchTodos())。
这是因为箭头函数绑定了父上下文
,因此 this 与你期待的 Vue 实例不同。
在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前
被调用。
在实例创建完成后被立即调用。在这一步,实例已完成
以下的配置:数据观测 (data observer)
,property 和方法的运算
,watch/event 事件回调
。然而,挂载阶段还没开始,$el property
目前尚不可用
。
在挂载开始之前被调用:相关的 render 函数首次被调用,
该钩子在服务器端渲染期间不被调用。
实例被挂载后调用,这时 el 被新创建的 vm.$el 替换
了。如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm.$el 也在文档内。
注意
mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick
该钩子在服务器端渲染期间不被调用。
mounted: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been rendered
})
}
数据更新时调用,发生在虚拟 DOM 打补丁之前(即视图未更新)
。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。
注意 updated 不会保证所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以在 updated 里使用 vm.$nextTick
:
该钩子在服务器端渲染期间不被调用。
updated: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been re-rendered
})
}
被 keep-alive 缓存的组件激活时调用。
该钩子在服务器端渲染期间不被调用。
被 keep-alive 缓存的组件停用时调用。
该钩子在服务器端渲染期间不被调用。
实例销毁之前调用。在这一步,实例仍然完全可用。
该钩子在服务器端渲染期间不被调用。
实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
该钩子在服务器端渲染期间不被调用。
首先,我设置了下面的例子
new Vue({
el:document.getElementsByTagName('div')[0],
created() {
console.log('created被触发')
}
)
el 和 created 就是传入 Vue 的自定义选项
合并,主要是为了把全局设置的钩子
和 组件自定义的钩子
合并起来,就算你没有全局钩子,也要存在数组里面,比如 created 是下面
vm.$options={
created:[fn,fn,fn...]
}
function initLifecycle(vm) {
vm._isMounted = false;
vm._isDestroyed = false;
vm._isBeingDestroyed = false;
}
这个函数会在 beforeCreated 钩子触发前调用,在 Vue.prototype._init 中,下个问题源码有显示。其中的标志位什么时候设置呢,是在相应的钩子触发之后,具体看下面源码
通过下面 这个函数
function callHook(vm, hook) {
// 是自己传入的 created 等回调
var handlers = vm.$options[hook];
if (handlers) {
// 执行多个同名钩子
for (var i = 0,j = handlers.length; i < j; i++) {
handlers[i].call(vm);
}
}
}
比如触发 created 就会这么调用
callHook(vm,‘created’)
直接拿到钩子,然后遍历执行,绑定上下文对象。
为什么是数组?,一个实例通过mixins
可能有很多个相同钩子
,所以合并成的数组
源码如下,只列出常用的几个钩子
function Vue(opt){
this._init(opt)
}
Vue.prototype._init(opt){
// ... 合并选项
// ... 设置初始值 ,事件 等数据
initLifecycle(vm)
callHook(vm, 'beforeCreate');
// ... 初始化选项等数据
callHook(vm, 'created');
// ...获取挂载的DOM 父节点
callHook(vm, 'beforeMount');
// ...解析模板成渲染函数,并执行渲染函数,生成DOM插入页面
vm._isMounted = true;
callHook(vm, 'mounted');
}
// 组件更新时会调用这个函数
Vue.prototype._update = function(
vnode, hydrating
) {
if (vm._isMounted) {
callHook(vm, 'beforeUpdate');
}
// ...重新调用渲染函数,对比旧节点和新节点,得到最小差异,然后只更新这部分页面
callHook(vm, 'updated');
}
// 节点被移除时会调用这个函数
Vue.prototype.$destroy = function() {
callHook(vm, 'beforeDestroy');
vm._isBeingDestroyed = true;
// ...实例被消除,移除所有 watcher
vm._isDestroyed = true;
// ...DOM被移除
callHook(vm, 'destroyed');
}
谢谢你阅读到了最后
期待你 点赞、评论、收藏、关注