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 ...
随机推荐
- QT QNetworkAccessManager 如何支持RESTFul的HTTP Patch方法
HTTP Patch方法是除了post,get,put,delete之外的一个新方式, 网上查不到的,也算是独家吧: 主要用下面这个方法: QNetworkReply *sendCustomReque ...
- 教你如何添加Xcode 9.3配置包?(安装流程可供其他版本安装参考)
1.准备好你想要的Xcode版本的安装包 ,这里以Xcode 9.3为例. → 2.打开Xcode开发工具的安装路径 ...
- iOS开发时获取第一响应者
上篇中提到键盘相应时间中用到了获取当前第一响应者的方法是苹果的是有方法,无法上传到App Store,本文将介绍一种非常简单的且未用到私有API的方法来获取当前第一响应者. 实现思路:用到的iOS A ...
- 真机调试(A valid provisioning profile for this executable was not found.)
这个问题是因为provisioning的问题,因为真机没有加入到账号下面的原因 解决步骤 1.吧identifier复制然后再平开开发中心 2.点击+号添加设备保存 3.在develope中选中保存即 ...
- C/S与B/S架构
目录 软件开发架构 C/S架构 数据放在服务端和客户端的利弊: B/S架构 软件开发架构 开发软件,必须要开发一套 客户端 和 服务端 服务端与客户端的作用 服务端:24小时不间断提供服务 客户端:享 ...
- 01-day-什么是webpack
.sass后缀的文件名 比较老了 现在它的后缀名是.scss 其实他们是同一个东西 只是 后缀名发生了变化 以 .sass写的文件的内容是 他没有括号 没有分号 有点怪 它跟新为了.scss 就有了花 ...
- python多版本共存pip指向问题
这两天一致被一个问题困扰,电脑里装了anaconda和python3.7,在命令行里输入python,想要python3.7,出现的确实python3.6,或使用pip安装包时,不知道是装在里pyth ...
- python27期尚哥讲TCP:
TCP:传输控制协议(使用情况多于udp) 稳定:保证数据一定能收到 相对UDP会慢一点 web服务器一般都使用TCP(银行转账,稳定比快要重要)TCP通信模型: 在通信之前,必须先等待建立链接 TC ...
- miniapp之登录、授权和支付
微信小程序代码实现(登录.授权和支付) ==整体流程看上一篇博客,或者去微信公众平台查看文档== ==只列出核心代码,详细代码见码云michaelben== 登录 // //小程序端 // app.j ...
- Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) A. Forgetting Things 水题
A. Forgetting Things Kolya is very absent-minded. Today his math teacher asked him to solve a simple ...