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

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

内容:

1:  子类父类  切入点
2:    Vue.extend()    //创建的是Vue的子类 

注:下面的代码是自定义,非官方源码,仅供参考,不可放到项目上使用,5月中旬将补充源码注释

(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 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);
	}

	//内置标签
	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  data    sub.options.data
		}
		for (key in child) { //自定义的选项配置
			if (!hasOwn(parent, key)) {
				mergeField(key); //components el data  name
			}
		}

		//默认策略 自定义的策略 
		function mergeField(key) {
			//components  directives  _base  data
			var result = strats[key] || defaultStrat;
			options[key] = result(parent[key], child[key], vm, key); // function undefined 
		}
		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: {},
		directives: {},
		_base: Vue
	}

	//初始化全局配置
	function initExtend(Vue) {
		Vue.extend = function(extendOptions) { //参数对象
			extendOptions = extendOptions || {};
			var Super = this; //sub
			var Sub = function VueComponent() { //构造函数
				this._init(); //Vue.prototype._init
			}
			Sub.prototype = Object.create(Super.prototype); //Super sub
			Sub.prototype.constructor = Sub;
			//第一次调用Super.options   == Vue.options
			//第二次调用Super.options    == sub.options
			Sub.options = mergeOptions(Super.options, extendOptions);
			Sub.extend = Super.extend;
			return Sub;
		}
	}
	initExtend(Vue);
	return Vue;
});



 推荐知识

 历史版本

修改日期 修改人 备注
2020-05-05 16:32:51[当前版本] 朱凡 创建版本

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