封装postMessage跨域

77 阅读1分钟
(function () {
	if (window.CD) {
		console.log('已经存在 window.CD变量');
		return;
	}
	const CD = () => {};
	CD.prototype = {
		version: '1.0.0',
		component: {},
		components: {},
		interfaces: {},
		/**
		 * 初使化
		 */
		init: () => {
			window.CD.component = {
				type: window.CD.isMaster() ? 'MASTER' : 'SLAVE',
				name: window.CD.isMaster() ? 'MASTER' : window.name,
				url: window.location.host,
				port: window.location.port || 80
			};
			if (!window.CD.component.name) {
				throw new Error('Error iframe must has a name');
			}
			window.CD.register(window.CD.component);
			window.CD.extendFun('register', data => {
				window.CD.components[data.component.name] = data.component;
			});
		},
		/**
		 * 是否是Master
		 * 如果窗口为顶层窗口则认为是Master
		 */
		isMaster: () => {
			return window === window.top;
		},
		/**
		 * Salve将自身组件注册到MASTER端
		 */
		register: () => {
			const param = {
				componentName: 'MASTER',
				methodFunc: 'register',
				dataV: {
					info: 'i m coming register!',
					component: window.CD.component
				}
			};
			window.CD.send(param);
		},
		/**
		 * 扩展接口方法
		 * @param {String} name接口名称
		 * @param {Function} fun 接口方法
		 */
		extendFun: (name, fun) => {
			window.CD.interfaces[name] = fun;
		},
		/**
		 * 打印跨域日志的方法
		 *
		 * @param {Object} mesg 要打印跨域消息的内容
		 */
		log: mesg => {
			if (!window.console || typeof window.console === 'undefined') {
				return;
			}
			window.console.log(`[${new Date()}'][${window.CD.version}][${window.CD.component.type}][${window.CD.component.name}][${mesg.type}][${window.JSON.stringify(mesg)}]`);
		},
		/**
		 * 发送信息到其它组件 - html5原生态方法包装
		 *
		 * @param {Window} targetWindow目标系统window对象
		 * @param {String} targetUrl目标系统 URL
		 * @param {Object} mesg 对象
		 */
		postMessage: (targetWindow, targetUrl, mesg) => {
			window.CD.log(mesg);
			if (targetWindow) {
				targetWindow.postMessage(JSON.stringify(mesg), targetUrl);
			}
		},
		/**
		 * 发送消息方法
		 * @param {String} componentName组件名称
		 * @param {String} method接口名称
		 * @param {Object} data数据
		 * @param {Function} callback回调
		 */
		send: dataParam => {
			const {
				componentName,
				methodFunc,
				dataV,
				callback,
				typeV
			} = dataParam;
			if (window.CD.isMaster() && componentName === 'MASTER') {
				return;
			}
			const sourceV = window.CD.component.name;
			const mesg = {
				source: sourceV,
				target: componentName,
				method: methodFunc,
				data: dataV,
				type: typeV || 'REQUEST'
			};
			if (callback) {
				window.CD.extendFun(methodFunc + 'Callback', callback);
			}
			const w = window.CD.isMaster() ? window.document[componentName] : window.top;
			window.CD.postMessage(w, '*', mesg);
		},
		/**
		 * 处理接收到的其它系统的请求跨域请求
		 *
		 * @param {Event} event事件对象
		 */
		process: event => {
			if (!event.data) {
				console.log('event is null!');
				return;
			}
			try {
				const mesg = JSON.parse(event.data);
				window.CD.log(mesg);
				const interface1 = window.CD.interfaces[mesg.method];
				let result;
				if (interface1) {
					result = interface1.call(window.CD, mesg.data);
				} else {
					throw new Error(`[${window.CD.component.name}] not have interface:[${mesg.method}]`);
				}
				if (result) {
					const param = {
						componentName: mesg.source,
						methodFunc: `${mesg.method}Callback`,
						dataV: result,
						callback: null,
						typeV: 'RETURN'
					};
					window.CD.send(param);
				}
			} catch (e) {
			}
		},
		/**
		 * 绑定窗口事件,用于监听跨域事件
		 */
		listen: () => {
			if (window.addEventListener) { // 非IE
				window.addEventListener('message', event => {
					window.CD.process(event);
				}, false);
			} else { // IE
				window.attachEvent('onmessage', event => {
					window.CD.process(event);
				});
			}
		}
	};
	window.CD = new CD();
	window.CD.init();
	window.CD.listen();
})();