【html页面引入vue页面】使用httpVueLoader.js让html页面引入vue文件当组件使用,html组件化开发

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

前言

最近遇到的一个需求就是html页面需要组件化开发然后找了一圈发现很多组件化开发不好用
一般就是几种比较用的多的一个是iframe嵌套页面一个就是通过js生成页面写组件。感觉都挺麻烦的。就想着有没有能像vue哪样简单的组件引入方式。而且iframe加载也慢。没有组件快。
后来发现了这个httpVueLoader.js非常好用。
只需要引入这个文件然后其他使用方法和vue差不多了。稍微有点变动可能就是传值方面。
传值下面也给出了方案。集中传值的方法应该大体是够用了的。

httpVueLoader.js代码

创建一个httpVueLoader.js文件然后把这段代码复制进去。

(function umd(root,factory){
	if(typeof module==='object' && typeof exports === 'object' )
		module.exports=factory()
	else if(typeof define==='function' && define.amd)
		define([],factory)
	else
		root.httpVueLoader=factory()
})(this,function factory() {
	'use strict';

	var scopeIndex = 0;

	StyleContext.prototype = {

		withBase: function(callback) {

			var tmpBaseElt;
			if ( this.component.baseURI ) {

				// firefox and chrome need the <base> to be set while inserting or modifying <style> in a document.
				tmpBaseElt = document.createElement('base');
				tmpBaseElt.href = this.component.baseURI;

				var headElt = this.component.getHead();
				headElt.insertBefore(tmpBaseElt, headElt.firstChild);
			}

			callback.call(this);

			if ( tmpBaseElt )
				this.component.getHead().removeChild(tmpBaseElt);
		},

		scopeStyles: function(styleElt, scopeName) {

			function process() {

				var sheet = styleElt.sheet;
				var rules = sheet.cssRules;

				for ( var i = 0; i < rules.length; ++i ) {

					var rule = rules[i];
					if ( rule.type !== 1 )
						continue;

					var scopedSelectors = [];

					rule.selectorText.split(/\s*,\s*/).forEach(function(sel) {

						scopedSelectors.push(scopeName+' '+sel);
						var segments = sel.match(/([^ :]+)(.+)?/);
						scopedSelectors.push(segments[1] + scopeName + (segments[2]||''));
					});

					var scopedRule = scopedSelectors.join(',') + rule.cssText.substr(rule.selectorText.length);
					sheet.deleteRule(i);
					sheet.insertRule(scopedRule, i);
				}
			}

			try {
				// firefox may fail sheet.cssRules with InvalidAccessError
				process();
			} catch (ex) {

				if ( ex instanceof DOMException && ex.code === DOMException.INVALID_ACCESS_ERR ) {

					styleElt.sheet.disabled = true;
					styleElt.addEventListener('load', function onStyleLoaded() {

						styleElt.removeEventListener('load', onStyleLoaded);

						// firefox need this timeout otherwise we have to use document.importNode(style, true)
						setTimeout(function() {

							process();
							styleElt.sheet.disabled = false;
						});
					});
					return;
				}

				throw ex;
			}
		},

		compile: function() {

			var hasTemplate = this.template !== null;

			var scoped = this.elt.hasAttribute('scoped');

			if ( scoped ) {

				// no template, no scopable style needed
				if ( !hasTemplate )
					return;

				// firefox does not tolerate this attribute
				this.elt.removeAttribute('scoped');
			}

			this.withBase(function() {

				this.component.getHead().appendChild(this.elt);
			});

			if ( scoped )
				this.scopeStyles(this.elt, '['+this.component.getScopeId()+']');

			return Promise.resolve();
		},

		getContent: function() {

			return this.elt.textContent;
		},

		setContent: function(content) {

			this.withBase(function() {

				this.elt.textContent = content;
			});
		}
	};

	function StyleContext(component, elt) {

		this.component = component;
		this.elt = elt;
	}


	ScriptContext.prototype = {

		getContent: function() {

			return this.elt.textContent;
		},

		setContent: function(content) {

			this.elt.textContent = content;
		},

		compile: function(module) {

			var childModuleRequire = function(childURL) {

				return httpVueLoader.require(resolveURL(this.component.baseURI, childURL));
			}.bind(this);

			var childLoader = function(childURL, childName) {

				return httpVueLoader(resolveURL(this.component.baseURI, childURL), childName);
			}.bind(this);

			try {
				Function('exports', 'require', 'httpVueLoader', 'module', this.getContent()).call(this.module.exports, this.module.exports, childModuleRequire, childLoader, this.module);
			} catch(ex) {

				if ( !('lineNumber' in ex) ) {

					return Promise.reject(ex);
				}
				var vueFileData = responseText.replace(/\r?\n/g, '\n');
				var lineNumber = vueFileData.substr(0, vueFileData.indexOf(script)).split('\n').length + ex.lineNumber - 1;
				throw new (ex.constructor)(ex.message, url, lineNumber);
			}

			return Promise.resolve(this.module.exports)
			.then(httpVueLoader.scriptExportsHandler.bind(this))
			.then(function(exports) {

				this.module.exports = exports;
			}.bind(this));
		}
	};

	function ScriptContext(component, elt) {

		this.component = component;
		this.elt = elt;
		this.module = { exports:{} };
	}


	TemplateContext.prototype = {

		getContent: function() {

			return this.elt.innerHTML;
		},

		setContent: function(content) {

			this.elt.innerHTML = content;
		},

		getRootElt: function() {

			var tplElt = this.elt.content || this.elt;

			if ( 'firstElementChild' in tplElt )
				return tplElt.firstElementChild;

			for ( tplElt = tplElt.firstChild; tplElt !== null; tplElt = tplElt.nextSibling )
				if ( tplElt.nodeType === Node.ELEMENT_NODE )
					return tplElt;

			return null;
		},

		compile: function() {

			return Promise.resolve();
		}
	};

	function TemplateContext(component, elt) {

		this.component = component;
		this.elt = elt;
	}



	Component.prototype = {

		getHead: function() {

			return document.head || document.getElementsByTagName('head')[0];
		},

		getScopeId: function() {

			if ( this._scopeId === '' ) {

				this._scopeId = 'data-s-' + (scopeIndex++).toString(36);
				this.template.getRootElt().setAttribute(this._scopeId, '');
			}
			return this._scopeId;
		},

		load: function(componentURL) {

			return httpVueLoader.httpRequest(componentURL)
			.then(function(responseText) {

				this.baseURI = componentURL.substr(0, componentURL.lastIndexOf('/')+1);
				var doc = document.implementation.createHTMLDocument('');

				// IE requires the <base> to come with <style>
				doc.body.innerHTML = (this.baseURI ? '<base href="'+this.baseURI+'">' : '') + responseText;

				for ( var it = doc.body.firstChild; it; it = it.nextSibling ) {

					switch ( it.nodeName ) {
						case 'TEMPLATE':
							this.template = new TemplateContext(this, it);
							break;
						case 'SCRIPT':
							this.script = new ScriptContext(this, it);
							break;
						case 'STYLE':
							this.styles.push(new StyleContext(this, it));
							break;
					}
				}

				return this;
			}.bind(this));
		},

		_normalizeSection: function(eltCx) {

			var p;

			if ( eltCx === null || !eltCx.elt.hasAttribute('src') ) {

				p = Promise.resolve(null);
			} else {

				p = httpVueLoader.httpRequest(eltCx.elt.getAttribute('src'))
				.then(function(content) {

					eltCx.elt.removeAttribute('src');
					return content;
				});
			}

			return p
			.then(function(content) {

				if ( eltCx !== null && eltCx.elt.hasAttribute('lang') ) {

					var lang = eltCx.elt.getAttribute('lang');
					eltCx.elt.removeAttribute('lang');
					return httpVueLoader.langProcessor[lang.toLowerCase()].call(this, content === null ? eltCx.getContent() : content);
				}
				return content;
			}.bind(this))
			.then(function(content) {

				if ( content !== null )
					eltCx.setContent(content);
			});
		},

		normalize: function() {

			return Promise.all(Array.prototype.concat(
				this._normalizeSection(this.template),
				this._normalizeSection(this.script),
				this.styles.map(this._normalizeSection)
			))
			.then(function() {

				return this;
			}.bind(this));
		},

		compile: function() {

			return Promise.all(Array.prototype.concat(
				this.template && this.template.compile(),
				this.script && this.script.compile(),
				this.styles.map(function(style) { return style.compile(); })
			))
			.then(function() {

				return this;
			}.bind(this));
		}
	};

	function Component(name) {

		this.name = name;
		this.template = null;
		this.script = null;
		this.styles = [];
		this._scopeId = '';
	}

	function identity(value) {

		return value;
	}

	function parseComponentURL(url) {

		var comp = url.match(/(.*?)([^/]+?)\/?(\.vue)?(\?.*|#.*|$)/);
		return {
			name: comp[2],
			url: comp[1] + comp[2] + (comp[3] === undefined ? '/index.vue' : comp[3]) + comp[4]
		};
	}

	function resolveURL(baseURL, url) {

		if (url.substr(0, 2) === './' || url.substr(0, 3) === '../') {
			return baseURL + url;
		}
		return url;
	}


	httpVueLoader.load = function(url, name) {

		return function() {

			return new Component(name).load(url)
			.then(function(component) {

				return component.normalize();
			})
			.then(function(component) {

				return component.compile();
			})
			.then(function(component) {

				var exports = component.script !== null ? component.script.module.exports : {};

				if ( component.template !== null )
					exports.template = component.template.getContent();

				if ( exports.name === undefined )
					if ( component.name !== undefined )
						exports.name = component.name;

				exports._baseURI = component.baseURI;

				return exports;
			});
		};
	};


	httpVueLoader.register = function(Vue, url) {

		var comp = parseComponentURL(url);
		Vue.component(comp.name, httpVueLoader.load(comp.url));
	};

	httpVueLoader.install = function(Vue) {

		Vue.mixin({

			beforeCreate: function () {

				var components = this.$options.components;

				for ( var componentName in components ) {

					if ( typeof(components[componentName]) === 'string' && components[componentName].substr(0, 4) === 'url:' ) {

						var comp = parseComponentURL(components[componentName].substr(4));

						var componentURL = ('_baseURI' in this.$options) ? resolveURL(this.$options._baseURI, comp.url) : comp.url;

						if ( isNaN(componentName) )
							components[componentName] = httpVueLoader.load(componentURL, componentName);
						else
							components[componentName] = Vue.component(comp.name, httpVueLoader.load(componentURL, comp.name));
					}
				}
			}
		});
	};

	httpVueLoader.require = function(moduleName) {

		return window[moduleName];
	};

	httpVueLoader.httpRequest = function(url) {

		return new Promise(function(resolve, reject) {

			var xhr = new XMLHttpRequest();
            		xhr.responseType = 'text';
			xhr.open('GET', url);

			xhr.onreadystatechange = function() {

				if ( xhr.readyState === 4 ) {

					if ( xhr.status >= 200 && xhr.status < 300 )
						resolve(xhr.responseText);
					else
						reject(xhr.status);
				}
			};

			xhr.send(null);
		});
	};

	httpVueLoader.langProcessor = {
		html: identity,
		js: identity,
		css: identity
	};

	httpVueLoader.scriptExportsHandler = identity;

	function httpVueLoader(url, name) {

		var comp = parseComponentURL(url);
		return httpVueLoader.load(comp.url, name);
	}

	return httpVueLoader;
});

使用方法(前提html是引入vue框架的)

1引入httpVueLoader.js文件。
2components注册组件前面的dr就是组件的名字随便你改。后面的地址需要用…/这种形式的。
3在html中把组件放上去其实和vue的写法基本一样。上面的@closedialog就是自定义方法你子组件可以通过$emit调用父组件的这个方法。


<!DOCTYPE html>
<html>

<head>
    <meta charset='UTF-8'>
    <!-- vue部分依赖 -->
    <link rel="stylesheet" href="/statics/vue_element/element.css">
    <script src="/statics/vue_element/vue.js"></script>
    <script src="/statics/vue_element/element.js"></script>
    <script src="/statics/vue_element/axios.js"></script>
    <!-- 引入vue类型组件 -->
    <script src="/statics/vue_element/httpVueLoader.js"></script>
    <title>导入导出功能模板</title>
</head>

<body>
    <div id="app">
            <div>
                    <dr id="dr" ref="dr" @closedialog="closedl"></dr>
            </div>
    </div>
</body>
<script>
    new Vue({
        el: '#app',
        components: {
            'dr': httpVueLoader('../../../../components/mb/dr.vue')
        },
       
    }
</script>

</html>

父子组件通信方式

由于是html的页面虽然是引入了vue的框架语法但是并不是真的变成了vue。
有些东西还是用起来不行的我试过了不行。
所以这里我使用的方法是这样的。
把原生的一些组件通信方法结合vue的一些使用。

父级拿子级的变量
子级需要定义全局变量也就是写在vue外面

document.getElementById('iframeId').contentWindow.变量名

父级调用子级的方法
子级需要定义全局方法也就是写在vue外面

document.getElementById('iframeId').contentWindow.iframeMethod(param);

子级拿父级变量
这种父级需要定义全局变量写在vue外面

window.parent.父级变量名;

子级调用父级的方法并传参
这种的父级方法要写在vue外面function那种原始写法才能调用到
但是好的一点是这种传值方法可以拿到返回值。也就是说你方法执行完了可以return出一个结果这里调用是可以接受到这个结果的

window.parent.父级方法名(item, index);

这种的可以直接调用到父级methods内的方法是通过组件自定义事件触发的。

this.$emit("closedialog", "关闭弹框");
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: vue