1: 钩子函数 自定义策略
2: 资源选项 自定义策略
3: 选项 watch 合并策略
(function(global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.Vue = factory());
})(this, function() {
var warn = function(msg) {
console.error("[Vue Warn]: " + msg);
}
var LIFECYCLE_HOOKS = [
'beforeCreate',
'created',
'beforeMount',
'mounted',
'beforeUpdate',
'updated',
'beforeDestroy',
'destroyed',
'activated', //内置组件 激活 keep-alive
'deactivated', // 停用 keep-alive
'errorCaptured'
];
var ASSET_TYPES = [ //选项components directives filters
'component',
'directive',
'filter'
];
function isPlainObject(obj){
return toString.call(obj) === "[object Object]";
}
function assertObjectType(name, vaule, vm ){
if(!isPlainObject(vaule)){
warn("选项"+name+"的值无效:必须是个对象");
}
}
function extend(to, _from){ //childVal
for( var key in _from){
to[key] = _from[key];
}
return to;
}
var hasOwnProperty = Object.prototype.hasOwnProperty;
var hasOwn = function(obj, key) {
hasOwnProperty.call(obj, key);
}
var uid = 0;
function resolveConstructorOptions(Con) {
var options = Con.options;
/*
判断 Con.super == Vue
*/
return options;
}
function checkComponents(options) {
for (var key in options.components) {
validataComponentName(key);
}
}
//检测key 是否在makeMap
function makeMap(str, toLowerCase) {
var map = {};
var list = str.split(","); //["slot","component"]
for (var i = 0; i < list.length; i++) {
map[list[i]] = true;
}
return toLowerCase ? function(val) {
return map[val.toLowerCase()];
} : function(val) {
return map[val];
}
}
var isHTMLTag = makeMap(
'html,body,base,head,link,meta,style,title,' +
'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +
'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
'embed,object,param,source,canvas,script,noscript,del,ins,' +
'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
'output,progress,select,textarea,' +
'details,dialog,menu,menuitem,summary,' +
'content,element,shadow,template,blockquote,iframe,tfoot'
);
//保留标签不能注册为组件
var isSVG = makeMap(
'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +
'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',
true
);
//配置对象
var config = {
//自定义的策略
optionMergeStrategies: {}
}
var strats = config.optionMergeStrategies;
strats.el = function(parent, child, vm, key) {
if (!vm) { //
warn("选项" + key + "只能Vue在实例中使用");
}
return defaultStrat(parent, child);
}
function mergeData(to, form) {
if (!form) {
return to;
}
//终极合并 待续:
}
function mergeDataorFn(parentVal, childVal, vm) {
if (!vm) {
//合并处理 parentVal childVal 对应的值都应该是函数
if (!childVal) {
return parentVal;
}
if (!parentVal) {
return childVal;
}
return function mergeDataFn(parentVal, childVal, vm) { //只是一个函数 什么样的情况下调用 加入响应式系统
//合并 子组件data对应的函数 父组件data对应的函数
return mergeData(
typeof childVal === "function" ? childVal.call(this, this) : childVal,
typeof parentVal === "function" ? parentVal.call(this, this) : parentVal
);
}
} else { //Vue的实例
return function mergedInstanceDataFn() {
var instenceData = typeof childVal === "function" ? childVal.call(vm, vm) : childVal;
var dafaultData = typeof parentVal === "function" ? parentVal.call(vm, vm) : parentVal;
if (instenceData) {
return mergeData(instenceData, dafaultData);
} else {
return dafaultData;
}
}
}
}
//自定义策略 Vue.options.data options vm
strats.data = function(parentVal, childVal, vm) {
if (!vm) { //子组件 子类
if (childVal && typeof childVal !== "function") {
warn("data选项的值应该为function 返回组件中每个实例值");
}
return mergeDataorFn(parentVal, childVal); //数据的合并
}
return mergeDataorFn(parentVal, childVal, vm);
}
function mergeHook(parentVal, childVal) { //undefined function
return childVal ?
parentVal ? //有值
parentVal.concat(childVal) :
Array.isArray(childVal) ? childVal : [childVal] : parentVal;
}
// 钩子函数自定义策略
LIFECYCLE_HOOKS.forEach(function(hook) {
strats[hook] = mergeHook;
})
function mergeAssets(parentVal, childVal, vm, key){ //Vue.options.components
var res = Object.create(parentVal||null);
if(childVal){
assertObjectType(key, childVal, vm);
return extend(res,childVal); //对象 res.__proto__ == Vue.options.components
}
return res;
}
//资源选项 自定义策略
ASSET_TYPES.forEach(function(type) {
strats[type + "s"] = mergeAssets;
})
//wacth选项自定义策略
strats.watch = function(parentVal, childVal, vm, key){
if(!childVal){
return Object.create( parentVal || null);
}
assertObjectType(key, childVal, vm);
if(!parentVal){
return childVal;
}
var res = {};
extend(res, parentVal);
for(var key in childVal){
var parent = res[key]; //有可能是为undefined
var child = childVal[key];
if(parent && !Array.isArray(parent)){
parent = [parent];
}
res[key] = parent ? parent.concat(child) : Array.isArray(child) ? child : [child]
}
return res;
}
//内置标签
var isbuiltInTag = makeMap("slot,component", true);
var isReservedTag = function(tag) {
return isSVG(tag) || isHTMLTag(tag);
}
function defaultStrat(parent, child) {
return child === undefined ? parent : child;
}
function validataComponentName(key) {
//1:不能使用Vue内置标签 slot component 2: 不能使用html || svg属性名称
//2: 规范组件的名称必须是由字母或中横线组成, 且必须是由字母开头
if (!/^[a-zA-Z][\w-]*$/.test(key)) {
warn("组件的名称必须是由字母或中横线组成, 且必须是由字母开头");
}
if (isbuiltInTag(key) || isReservedTag(key)) {
warn("不要把内置组件或者保留的html ||svg 元素作为组件的id: " + key);
}
}
//选项合并 返回新的对象
function mergeOptions(parent, child, vm) {
//规范的检测 components props inject directives
checkComponents(child);
var options = {};
var key;
for (key in parent) {
mergeField(key); //components directives _base
}
for (key in child) { //自定义的选项配置 created
if (!hasOwn(parent, key)) {
mergeField(key); //components el data name
}
}
//默认策略 自定义的策略
function mergeField(key) {
//components directives _base created
var result = strats[key] || defaultStrat;
options[key] = result(parent[key], child[key], vm, key); // parent.options.created 1
}
return options;
}
function initMixin(Vue) {
Vue.prototype._init = function(options) {
var vm = this;
//有多少个Vue的实例对象
vm._uid = uid++;
vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor), options, vm);
}
}
function Vue(options) {
//安全机制
if (!(this instanceof Vue)) {
warn("Vue是一个构造函数 应该用new关键字调用")
}
this._init(options); //初始化
}
initMixin(Vue); // 初始化选项: 1:规范 2:合并策略
//全局API
Vue.options = {
components: { //内置组件
keepAlive:{},
transition:{},
transitionGroup:{}
},
directives: {},
_base: Vue
}
//初始化全局配置
function initExtend(Vue) {
Vue.extend = function(extendOptions) { //参数对象
extendOptions = extendOptions || {};
var Super = this; //Vue
var Sub = function VueComponent(options) { //构造函数
this._init(options); //Sub 实例对象
}
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
//第一次调用Super.options == Vue.options
//第二次调用Super.options == sub.options Super === Sub
Sub.options = mergeOptions(Super.options, extendOptions);
Sub.extend = Super.extend;
return Sub;
}
}
initExtend(Vue);
return Vue;
});
//Sub 实例对象 __proto__ => Sub.prototype => __proto__ => Super.prototype == Vue.prototype