目录
实例生命周期钩子
每个Vue实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到DOM并在数据变化时更新DOM等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
比如created钩子可用用来在一个实例被创建之后执行代码,也有一些其它的钩子,在实例生命周期的不同阶段被调用,如mounted、updated和destroyed。生命周期钩子的this上下文指向调用它的Vue实例。
vue.2.5.1.生命周期钩子.js
// 整体结构是立即执行函数。
// 带两个参数,一个global用作全局变量存放,一个factory工厂函数制造一些初始化方法。
// typeof判断变量类型,以此校验执行环境
// 需要理解逻辑运算符之间的优先级,
// 其中用到了几个不理解的变量,属性和方法,分别是 module、module.exports、define、define.amd
(function (global, factory) {// global = window, factory
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global.Vue = factory());
// 暴露出factory工厂函数
}(this, function () {
// ASSET_TYPES 常量复用
// Vue.options.components
// Vue.component.. Vue.directive..
var ASSET_TYPES = [
'component',
'directive',
'filter'
];
// 生命周期钩子常量组
var LIFECYCLE_HOOKS = [
'beforeCreate',
'created',
'beforeMount',
'mounted',
'beforeUpdate',
'updated',
'beforeDestroy',
'destroyed',
'activated',
'deactivated',
'errorCaptured',
'serverPrefetch'
];
// Vue 全局配置对象
// 最终config会暴露为Vue.config
var config = {
/**
* 选项合并策略(用于core/util/options)
*/
//$flow-disable-line 禁用行
optionMergeStrategies: Object.create(null),
}
/**
* 检查对象是否具有该属性
*/
var hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwn(obj, key) {
return hasOwnProperty.call(obj, key)
}
/** 自定义策略
* 选项覆盖策略是处理
* 如何合并父选项值和子选项
* 将值转换为最终值。
*/
// 自定义处理用在了很多地方,如el,props,watch....
var strats = config.optionMergeStrategies;
// 自定义策略处理
strats.data = function (parentVal, childVal, vm) {
// 组件的基本原理
// 聚焦到vm,判别是根实例,还是组件
if (!vm) { // 组件,不是根实例
if (childVal && typeof childVal !== "function") {
console.error("data选项应该为函数 返回组件中每个实例的值")
}
}
}
// 所有钩子函数的自定义策略 parentVal === undefined childVal === function(){}
function mergeHook(parentVal, childVal) {
return childVal
? parentVal // 数组
? parentVal.concat(childVal) // 合并parentVal、childVal
: Array.isArray(childVal) // 是不是数组
? childVal
: [childVal] // [function(){}]
: parentVal;
}
LIFECYCLE_HOOKS.forEach(hook => {
strats[hook] = mergeHook;
})
/**
* "所有"选项默认策略
*/
var defaultStrat = function (parentVal, childVal) {
return childVal === undefined
? parentVal
: childVal
};
function mergeOptions(parent, child, vm) {
/* 选项规范检测 Components Props Inject Directives */
var options = {};
var key;
for (key in parent) {
//parent-> 'components', 'directives', 'filters'
mergeField(key);
}
for (key in child) {
if (!hasOwn(parent, key)) { // 父组件没有这个key,才会扩展key
mergeField(key);
}
}
// 选项的策略处理;要考虑el,data,生命周期的钩子函数...
// 自定义策略挂载在(strats对象) 默认策略
function mergeField(key) { // 组件也会调用,组件包含vue的除根实例特有的el等外的实例
console.log(key);
// 属性值 || 默认策略
var strat = strats[key] || defaultStrat;
// 给options扩展key属性
options[key] = strat(parent[key], child[key], vm, key);
}
return options;
}
// 执行钩子函数方法
function callHook(vm, hook) {
var handlers = vm.$options[hook];
if (handlers) {
for (var i = 0, j = handlers.length; i < j; i++) {
handlers[i].call(vm)
}
}
}
function initMixin(Vue) {
Vue.prototype._init = function (options) {
var vm = this;
// a uid
// 选项合并,给$options插入方法,参数
vm.$options = mergeOptions(
// 返回vue选项的引用
Vue.options, // Vue.options
options || {}, // options
vm // Vue
);
// 执行钩子函数beforeCreate
callHook(vm, 'beforeCreate')
};
}
// config ,Vue全局配置对象
function initGlobalAPI(Vue) {
var configDef = {};
configDef.get = function () { return config; };
{
configDef.set = function (newVal) {
console.error('不要尝试修改Vue.config的引用',
'Do not replace the Vue.config object, set individual fields instead.'
);
};
}
// 让Vue可访问config
// 不直接写Vue.config而是监听,就是防止Vue.config引用被篡改
Object.defineProperty(Vue, 'config', configDef);// 监听你对Vue.config属性的访问,暴漏出自定义策略接口
}
function initExtend(Vue) {
/**
*每个实例构造函数(包括Vue)都有一个唯一的
*cid。这使我们能够创建包装的“子对象”
*“构造函数”用于原型继承并缓存它们。
*/
// 用于原型继承 缓存构造函数
Vue.cid = 0;
var cid = 1;
/**
* 类继承
*/
Vue.extend = function (extendOptions) {
extendOptions = extendOptions || {};
var Super = this; // Super === Vue
var SuperId = Super.cid;
// 缓存检测 cachedCtors
var cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {});
// 缓存处理cachedCtors[0] = 子类的引用
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId]
}
var name = extendOptions.name || Super.options.name;
if (name) {
// validateComponentName(name); // 组件名称规范检查
}
// 子类 构造函数
var Sub = function VueComponent(options) {
this._init(options);
};
// 把Vue的原型引用赋给Sub
// {}.__proto__ = Super.prototype = Vue.prototype
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.cid = cid++;
// 组件在初始化 mergeOptions 选项的合并 => 规范的检测 => 策略的处理
Sub.options = mergeOptions(
Super.options, // Vue.options
extendOptions // 组件的选项对象
);
Sub['super'] = Super;
//对于props和computed属性,我们在
//在扩展原型上扩展时的Vue实例。这
//避免为创建的每个实例调用Object.defineProperty。
if (Sub.options.props) {
initProps$1(Sub);
}
if (Sub.options.computed) {
initComputed$1(Sub);
}
// 允许进一步扩展/混合/插件使用 extension/mixin/plugin
// Sub.extend = Super.extend;
// Sub.mixin = Super.mixin;
// Sub.use = Super.use;
//创建资产寄存器,以便扩展类
//也可以拥有他们的私人资产。
// Super == Vue Vue.component【注册全局组件的一种方法】 不等于 Vue.options.components【挂载内置抽象组件】
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type];
});
//启用递归自查找
// if (name) {
// Sub.options.components[name] = Sub;
// }
//在扩展时保留对超级选项的引用。
//稍后在实例化时,我们可以检查Super的选项是否有
//已更新。
// Sub.superOptions = Super.options;
// Sub.extendOptions = extendOptions;
// Sub.sealedOptions = extend({}, Sub.options);
// 缓存构造函数
cachedCtors[SuperId] = Sub;
return Sub
};
}
// 拿到空对象的引用
Vue.options = Object.create(null);
// 添加内置组件'components',指令'directives',过滤器'filters',他们都加一个空对象的引用
ASSET_TYPES.forEach(function (type) {
// ASSET_TYPES 常量复用
Vue.options[type + 's'] = Object.create(null);// Vue.options.components
});
function Vue(options) {
if (!(this instanceof Vue)) { // 得new一个Vue,不然就报错
warn('Vue is a constructor and should be called with the `new` keyword');
}
// 初始化
this._init(options);
}
initMixin(Vue);
initGlobalAPI(Vue);
initExtend(Vue)
return Vue;
}));
demo.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue.2.5.1.生命周期</title>
</head>
<body>
<div id="app"></div>
<script src="vue.2.5.1.生命周期.js"></script>
<script>
// // count 自定义策略处理 parentVal == Vue.options.count = undefined, childVal === 1
// Vue.config.optionMergeStrategies.count = function (parentVal, childVal, vm) {
// return childVal >= 10 ? childVal : 10
// }
// // Vue 构造函数
// var vm = new Vue({
// el: "#app",
// data: {
// root: "max"
// },
// count: 1,
// beforeCreate: [
// function () { console.log("hello OMG") },
// function () { console.log("hello KX") },
// ]
// })
// // 组件的这些选项,组件时可复用的Vue的实例data,computed,watch,methods以及生命周期钩子等,仅有的例外是el这样根实例特有的选项
// //
// console.log(vm.$options)
// 响应式系统的搭建
Vue.extend({
data: { // data的选项必须是函数 创建组件
}
})
</script>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue-v2.6.14</title>
</head>
<body>
<div id="app">
<componen-a></componen-a>
</div>
<script src="vue-v2.6.14.js"></script>
<script>
// 组件选项的对象——注册局部组件的方式
var ComponentA = {
name: "ComponentA",
template: "<div>123</div>"
}
new Vue({
name: 'App',
el: "#app",
components: {
"componen-a": ComponentA
}
})
// json 对象 组件选项对象 Vue.extend() 创建一个子类 实例化子类(createComponentInstanceForVnode) => 组件
// createComponentInstanceForVnode 实例化组件
// 组件系统
</script>
</body>
</html>