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 ...
随机推荐
- swif(六)swift闭包
// // main.swift // LessonSwiftSix // // Created by keyan on 15/9/13. // Copyright (c) 2015年 keyan. ...
- 深入理解JVM虚拟机(二):JDK 内存类的异常分析
JVM数据存储 堆存储(Heap):对象存储,实际上就是JAVA的数据存储 方法堆栈(Method Stack):存储方法调用的关系. 永久代(Perm):在JDK1.6及之前,常量数据存储于此区域 ...
- Python—下载安装与使用
安装依赖包 首先安装gcc编译器,编译时需要使用gcc.gcc有些系统版本已经默认安装,通过 gcc --version 查看,没安装的先安装 [root@localhost ~]# yum -y ...
- gdb x命令使用方法
x命令是直接查看指定地址为开头的内存里的内容 既然是要看,就分你想怎么看,和看多少 怎么看: d 按十进制格式显示 x 按十六进制格式显示 a 按十六进制格式显示 u 按十六进制格式显示无符号整型 o ...
- SSDB数据库笔记
目录 环境 配置文件 启动服务器 客户端 SSDB:一个高性能的支持丰富数据结构的 NoSQL 数据库, 用于替代 Redis. 参考文献: SSDB官网 环境 win10 下 wsl 环境 ubun ...
- 设置了相对定位relative之后,改变top值,如何去掉多余空白?
众所周知,relative和absolute有一个区别在于relative是相对自身定位,而absolute是相对于最近的定位父级定位,而此时的相对定位经过top值改变其在文档流中的位置之后,自身本来 ...
- luoguP3979 遥远的国度
换根的树剖 https://www.luogu.org/problem/P3979 题意: (出题人口活好.... 给定一棵以 root 为根的 n 个点的有根树,对于任意一个点 x, 给定他 的点权 ...
- 3.web基础$_GET
http://123.206.87.240:8002/get/
- angular和ionic4对过滤器pipe的使用
以下为自定义过滤器 import { Pipe, PipeTransform, Injectable } from '@angular/core'; import { DomSanitizer} fr ...
- <Tree> 298 250 366 199(高频) 98(高频)
298. Binary Tree Longest Consecutive Sequence 先序遍历,根左右.如果该节点的 value == 父节点value + 1, 则长度+1; 否则重置为1. ...