127  
查询码:00001069
vue(基于2.X)源码分析(三)
作者: 朱凡 于 2020年05月13日 发布在分类 / FM组 / FM_App 下,并于 2020年05月13日 编辑

vue(基于2.X)源码分析(三)

内容 生命周期钩子 资源选项合并策略

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



 推荐知识

 历史版本

修改日期 修改人 备注
2020-05-13 22:10:21[当前版本] 朱凡 创建版本

  目录
    知识分享平台 -V 4.8.7 -wcp