Vue.js 源码分析(九) 基础篇 生命周期详解
先来看看官网的介绍:

主要有八个生命周期,分别是:
beforeCreate、created、beforeMount、mounted、beforeupdate、updated 、beforeDestroy和destroyed,分别对应八个不同的时期,另外还有两个activated和deactivated生命周期是对应Keep-Alive组件的
关于这八个生命周期的具体用法官网介绍的很详细了,飞机入口:点我点我 ,另外还有一张比较直观图形介绍,飞机入口:点我点我
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<title>Document</title>
</head>
<body>
<div id="app">
<p>{{message}}</p>
<button @click="test1()">测试(更新操作)</button>
<button @click="test2()">测试(销毁操作)</button>
</div>
<script>
Vue.config.productionTip=false;
Vue.config.devtools=false;
new Vue({
el:'#app',
data:{message:"Hello World!"},
beforeCreate:function(){ console.log('beforeCreate'); },
created:function(){ console.log('created'); },
beforeMount:function(){ console.log('beforeMount'); },
mounted:function(){ console.log('mounted'); },
beforeUpdate:function(){ console.log('beforeUpdate'); },
updated:function(){ console.log('updated'); },
beforeDestroy:function(){ console.log('beforeDestroy'); },
destroyed:function(){ console.log('destroyed'); },
methods:{
test1:function(){this.message="Hello Vue!";},
test2:function(){this.$destroy();},
}
})
</script>
</body>
</html>
页面渲染如下:

渲染完成后控制台输出:

当点击了测试(更新操作)这个按钮后,修改了Vue实例的message值做了更新操作,此时控制台输出如下:

当我们点击测试(销毁操作)按钮时,Vue实例做了销毁操作,控制台输出如下:

writer by:大沙漠 QQ:22969969
对于Vue的插件(包括官方的生态)来说,绝大多数都用到了beforeCreate()这个生命周期函数,可以在实例化前混入一些属性,以vuex为例,如下:
function applyMixin (Vue) {
var version = Number(Vue.version.split('.')[0]);
if (version >= 2) {
Vue.mixin({ beforeCreate: vuexInit }); //如果Vue的版本大于2,则将vuexInit混入到beforeCreate生命周期函数,这样vuex就会进行初始化
} else {
// override init and inject vuex init procedure
// for 1.x backwards compatibility.
var _init = Vue.prototype._init;
Vue.prototype._init = function (options) {
if ( options === void 0 ) options = {};
options.init = options.init
? [vuexInit].concat(options.init)
: vuexInit;
_init.call(this, options);
};
}
vue-router也是的,如下:
Vue.mixin({ //混入了两个生命周期,分别是beforeCreate和destroyed
beforeCreate: function beforeCreate () {
if (isDef(this.$options.router)) {
this._routerRoot = this;
this._router = this.$options.router;
this._router.init(this);
Vue.util.defineReactive(this, '_route', this._router.history.current);
} else {
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;
}
registerInstance(this, this);
},
destroyed: function destroyed () {
registerInstance(this);
}
});
源码分析
生命周期的源码实现比较简单,都是通过Vue内部的一个叫callHook()的全局函数执行的,如下:
function callHook (vm, hook) { //第2914行 vm:vue实例 hook:对应的操作名(例如:beforeCreate、created等)
// #7573 disable dep collection when invoking lifecycle hooks
pushTarget();
var handlers = vm.$options[hook]; //获取生命周期函数
if (handlers) {
for (var i = 0, j = handlers.length; i < j; i++) { //遍历生命周期函数
try {
handlers[i].call(vm); //执行该函数,以vm作为上下文
} catch (e) {
handleError(e, vm, (hook + " hook"));
}
}
}
if (vm._hasHookEvent) {
vm.$emit('hook:' + hook);
}
popTarget();
}
beforeCreate和created是在init()的时候执行的,如下:
Vue.prototype._init = function (options) { //第4576行
/*略*/
vm._self = vm;
initLifecycle(vm);
initEvents(vm);
initRender(vm);
callHook(vm, 'beforeCreate'); //执行beforeCreate生命周期函数
initInjections(vm); // resolve injections before data/props
initState(vm);
initProvide(vm); // resolve provide after data/props
callHook(vm, 'created'); //执行created生命周期函数
/*略*/
};
beforeMount和mounted是在挂载的时候在mountComponent()里执行的,如下:
function mountComponent(vm, el, hydrating) { //第2739行 挂载组件 vm:Vue实例 el:真实的DOM节点对象
/*略*/
callHook(vm, 'beforeMount'); //挂载前 执行生命周期里的beforeMount事件
var updateComponent;
if ("development" !== 'production' && config.performance && mark) { //开启了性能追踪时的分支
/*略*/
} else {
updateComponent = function () {vm._update(vm._render(), hydrating);};
}
new Watcher(vm, updateComponent, noop, null, true);
hydrating = false;
if (vm.$vnode == null) {
vm._isMounted = true; //设置vm._isMounted为true,表示已挂载
callHook(vm, 'mounted'); //执行生命周期里的Mount事件
}
return vm
}
beforeUpdate是在Vue原型上的_update更新时触发的,如下:
Vue.prototype._update = function (vnode, hydrating) { //第2646行
var vm = this;
if (vm._isMounted) { //如果已经挂载了,则表示已经挂载了
callHook(vm, 'beforeUpdate'); //则触发beforeUpdate
}
/*略*/
}
updated是在nextTick()执行时当watcher执行完了之后触发的,如下:
function callUpdatedHooks (queue) { //第3016行
var i = queue.length;
while (i--) {
var watcher = queue[i];
var vm = watcher.vm;
if (vm._watcher === watcher && vm._isMounted) { //如果当前是渲染watcher,且已经挂载了
callHook(vm, 'updated'); //则触发update生命周期函数
}
}
}
beforeDestroy和destroyed是在Vue原型的$destroy()方法里触发的,如下:
Vue.prototype.$destroy = function () { //第2695行
var vm = this;
if (vm._isBeingDestroyed) {
return
}
callHook(vm, 'beforeDestroy'); //触发beforeDestroy生命周期函数
/*这里进行销毁过程*/
callHook(vm, 'destroyed'); //触发destroyed生命周期函数
/*略*/
};
}
Vue.js 源码分析(九) 基础篇 生命周期详解的更多相关文章
- Vue.js 源码分析(十) 基础篇 ref属性详解
ref 被用来给元素或子组件注册引用信息.引用信息将会注册在父组件的 $refs 对象上.如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素:如果用在子组件上,引用就指向组件实例,例如: ...
- Vue.js 源码分析(十三) 基础篇 组件 props属性详解
父组件通过props属性向子组件传递数据,定义组件的时候可以定义一个props属性,值可以是一个字符串数组或一个对象. 例如: <!DOCTYPE html> <html lang= ...
- Vue.js 源码分析(四) 基础篇 响应式原理 data属性
官网对data属性的介绍如下: 意思就是:data保存着Vue实例里用到的数据,Vue会修改data里的每个属性的访问控制器属性,当访问每个属性时会访问对应的get方法,修改属性时会执行对应的set方 ...
- Vue.js 源码分析(三) 基础篇 模板渲染 el、emplate、render属性详解
Vue有三个属性和模板有关,官网上是这样解释的: el ;提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标 template ;一个字符串模板作为 Vue 实例的标识使用.模板将会 ...
- Vue.js 源码分析(二) 基础篇 全局配置
Vue.config是一个对象,包含Vue的全局配置,可以在启动应用之前修改下列属性,如下: ptionMergeStrategies ;自定义合并策略的选项silent ...
- Vue.js 源码分析(八) 基础篇 依赖注入 provide/inject组合详解
先来看看官网的介绍: 简单的说,当组件的引入层次过多,我们的子孙组件想要获取祖先组件的资源,那么怎么办呢,总不能一直取父级往上吧,而且这样代码结构容易混乱.这个就是这对选项要干的事情 provide和 ...
- Vue.js 源码分析(七) 基础篇 侦听器 watch属性详解
先来看看官网的介绍: 官网介绍的很好理解了,也就是监听一个数据的变化,当该数据变化时执行我们的watch方法,watch选项是一个对象,键为需要观察的数据名,值为一个表达式(函数),还可以是一个对象, ...
- Vue.js 源码分析(十一) 基础篇 过滤器 filters属性详解
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化.过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持).过滤器应该被添加在 JavaScrip ...
- Vue.js 源码分析(五) 基础篇 方法 methods属性详解
methods中定义了Vue实例的方法,官网是这样介绍的: 例如:: <!DOCTYPE html> <html lang="en"> <head&g ...
随机推荐
- 中文代码之Django官方入门:建立模型
参考编写你的第一个 Django 应用,第 2 部分 创建项目后,首先用中文命名应用: $ python3 manage.py startapp 投票 之后在models.py建立模型,其他各种相关配 ...
- PHP比较两个数组的差异
array_diff($arr, $arr1); //比较数组差异 $arr = [1,2,3,4]; $arr1 = [1,2,3]; $diff = array_diff($arr, $arr1) ...
- python从入门到放弃之协程
协程 协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B ...
- SQL Server Alwayson 主从数据库账号同步
我们建立了Alwayson后,辅助副本下的数据库是没有相应的账号的,怎么样进行账号的同步呢?怎么在不知道密码的情况下,进行账号的同步设置. 我们可以通过SP--sp_help_revlogin 来实现 ...
- bayaim_今晚打老虎
bayaim_2018年11月22日11:01:14 <<<--- 再牛逼的肖邦,也尼玛弹奏不出我内心的悲伤.--->>> 艹,今天想骂人,艹TMD自己,不小心把自 ...
- 4-9 Panadas与sklearn结合实例
1.显示百分比的柱状图 In [1]: import pandas as pd import numpy as np import matplotlib.pyplot as plt %matplo ...
- python函数内容
在刚接触python的时候就有个疑问,什么是函数? python语言的函数和数学语言的函数有区别吗? 什么是函数 数学函数:给定一个数集A,假设其中的元素为x.现对A中的元素x施加对应法则f,记作f( ...
- Java面试中遇到的坑【篇二面试干货】
俗话说早起的鸟儿有虫吃,现在临年关越来越近,有跳槽的想法的同事也都打算年前做好功课年后入职,所谓年终奖拿了,工作换的也是水到渠成. 说到这里想必有同学要说了,年底了放着年终奖不拿为何要跳槽呢?这个就要 ...
- 【西北师大-2108Java】第四次作业成绩汇总
[西北师大-2108Java]第四次作业成绩汇总 深入理解程序设计中算法与程序的关系: 深入理解java程序设计中类与对象的关系: 理解OO程序设计的第2个特征:继承.多态: 学会采用继承定义类设计程 ...
- Jike_Time-决策树
根节点 非叶子节点(决策点) 叶子节点(决策结果) 分支 熵代表混乱程度 信息增益 构造树的基本想法是随着树深度的增加.节点的熵迅速地降低.熵降低的速度越快越好,这样我们有望得到一颗高度最矮的决策树 ...