zoukankan      html  css  js  c++  java
  • 普通html网站引用Vue单文件组件

    本篇中,Insus.NET创建一个vue单文件组件,然后在普通的html网站中去引用这个组件。

    把下面代码,存储为一个名为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(/
    ?
    /g, '
    ');
                    var lineNumber = vueFileData.substr(0, vueFileData.indexOf(script)).split('
    ').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.open('GET', url);
                xhr.responseType = 'text';
    
                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;
    });
    Source Code

    创建一个 vue组件:

    其中,组件的Htm代码:

    <template>
        <div>
    
            <div>
                <fieldset>
                    <legend>User</legend>
                    <div>
                        <label>Name:</label>{{prop_object.name}}
                    </div>
                    <div>
                        <label>Age:</label>{{prop_object.age}}
                    </div>
                    <div>
                        <label>Email:</label>{{prop_object.email}}
                    </div>
                </fieldset>
            </div>
            <hr />
            <div>
                <fieldset>
                    <legend>Data</legend>
                    <ul>
                        <li v-for="pa in prop_array">
                            <span>{{pa.data}}</span>
                        </li>
                    </ul>
                </fieldset>
            </div>
    
        </div>
    </template>
    Source Code

    javascript代码:

     module.exports = {   
            
            props: {
                prop_object: {
                    type: Object,
                    default: function () {
                        return {}
                    }
                },
                prop_array: {
                    type: Array,
                    default: function () {
                        return []
                    }
                }
            }
        };
    Source Code

    样式:

    <style>
    
    
    </style>

    以上组件准备完毕,下面是html网页,将引用以上vue组件:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title>communicate</title>
    </head>
    <body>
        <div id="comm">
            <insus-component :prop_object="obj" :prop_array="arr"></insus-component>
        </div>
    </body>
    </html>
    Html Source Code
     Vue.config.productionTip = false;
        Vue.config.devtools = false;
    
        Vue.use(httpVueLoader);
    
        var vue_app = new Vue({
            el: '#comm',
            data() {
                return {
                    obj: null,
                    arr: null
                };
            },
            mounted: function () {
                this.init();
            },
            methods: {
                init: function () {               
                    this.obj = { name: 'Insus.NET', age: '100', email: 'insus@163.com' }
                    this.arr = [{ data: 'a' }, { data: 'b' }, { data: 'c' }, { data: 'd' }, { data: 'e' }, { data: 'f' }]
                },
            },
            components: {
                'insus-component': 'url:/VueComponents/zc.vue'
            }
        })
    JS Source Code

    运行结果:

  • 相关阅读:
    HDU 4325 Contest 3
    HDU 4324 Contest 3
    HDU 4323 Contest 3
    HDU 4321 Contest 3
    HDU 4320 Contest 3
    HDU 4314 Contest 2
    HDU 4313 Contest 2
    HDU 4318 Contest 2
    12-----简单认识下margin
    11-----broder(边框)
  • 原文地址:https://www.cnblogs.com/insus/p/14434217.html
Copyright © 2011-2022 走看看