sailei1 / blog

1 stars 0 forks source link

vue 远程动态组件尝试 #35

Closed sailei1 closed 5 years ago

sailei1 commented 5 years ago

模拟json


{
  "com":"<template> <div class='test-cls' @click='change'> 列表页 {{a}} <my-component-name></my-component-name> </div> </template> <style lang=\"scss\" scoped> .test-cls{color:red;} </style> <script> export default{ data(){ return { a:1} }, props:{ }, components:{}, methods:{change(){this.a++;}}, } </script>",
  "com1":" <div> 列表页 </div>"
}

实现 一种 computed 动态组件 另外一种 异步组件 开发不太方便 放弃

const compiler = require('vue-template-compiler') const parsed = compiler.parseComponent(res.data.com, { pad: 'line'}); const template = parsed.template ? parsed.template.content : ''; let script = parsed.script ? parsed.script.content : ''; const style = parsed.style ? parsed.style.content : ''; 样式有问题, 放弃 推荐 computed 方式

<template>
    <div class="remote">
        <!--<com></com>-->
        <component :is="currentView" v-bind="$props"/>
    </div>
</template>
<script>
    import Axios from 'axios';
    import Vue from 'vue';
    import '../util/less.min';
    Vue.component('my-component-name', {
        template:'<div>组件</div>',
    })

    export default {
        props:{
            url:{
                type:String,
                default(){
                    return null;
                }
            }
        },
        data(){
            return {
                resData:null,
                cssId:null,
            }
        },
        components:{
        },
        computed:{
            currentView(){
                if(!this.resData)return {template:"<div class='remoteInfo'>正在加载中。。。</div>"};
                const tplData = this.resolveStr(this.resData);
                let ponentObj = new Function(`return ${tplData.sctipts.slice(tplData.sctipts.indexOf('{'),tplData.sctipts.lastIndexOf('}')+1)}`)();
                ponentObj.template = tplData.templates;
                this.$el.setAttribute('class',`remote css${this.cssId}`);
                if(!document.querySelector(`style[id=css${this.cssId}]`)){//防止重复创建
                    let cssStr = `
                    .css${this.cssId}{
                        ${tplData.styles}
                    }
                `;
                    this.resolveCss(cssStr);
                }
                return ponentObj;
            }
        },
        watch:{
            url(){
                this.getData();
            }
        },
        mounted(){
            this.getData();
        },
        methods:{
            getId() {
                var d = new Date().getTime();
                var uid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                    var r = (d + Math.random()*16)%16 | 0;
                    d = Math.floor(d/16);
                    return (c=='x' ? r : (r&0x3|0x8)).toString(16);
                });
                return uid;
            },
            resolveCss(lessInput){
                less.render(lessInput).then(function(output) {
                    let style = document.createElement("style");
                    style.setAttribute("type", "text/css");
                    style.setAttribute("id",'css' + this.cssId);
                    if(style.styleSheet)// IE
                        style.styleSheet.cssText = output.css;
                    else {// w3c
                        var cssText = document.createTextNode(output.css);
                        style.appendChild(cssText);
                    }
                    var heads = document.getElementsByTagName("head");
                    if(heads.length)
                        heads[0].appendChild(style);
                    else
                        document.documentElement.appendChild(style);
                }.bind(this));
            },
            resolveStr(str){
                return {
                    templates:str.match(/<template>([\s\S]*)<\/template>/)[1],
                    sctipts:str.match(/<script.*>([\s\S]*)<\/script>/)[1],
                    styles:str.match(/<style.*>([\s\S]*)<\/style>/)[1],
                }
            },
            async getData(){
                 let url='http://127.0.0.1:9999/tpl';
                    const res = await Axios.get(url);
                    this.cssId = this.getId();
                    this.resData = res.data.com;

            }
        }
    }

    // import Axios from 'axios';
    // import Vue from 'vue'
    // import '../util/less.min';
    // Vue.component('my-component-name', {
    //     template:'<div>组件</div>',
    // })
    // let me=this;
    // export default {
    //     components: {
    //         com: resolve => {
    //             let url = 'http://127.0.0.1:9999/tpl';
    //
    //             Axios.get(url).then(res => {
    //
    //
    //
    //                 let resolveStr= function (str){
    //                             return {
    //                                 templates:str.match(/<template>([\s\S]*)<\/template>/)[1],
    //                                 sctipts:str.match(/<script.*>([\s\S]*)<\/script>/)[1],
    //                                 styles:str.match(/<style.*>([\s\S]*)<\/style>/)[1],
    //                             }
    //                         };
    //
    //                 let tplData=resolveStr(res.data.com);
    //                 let ponentObj = new Function(`return ${tplData.sctipts.slice(tplData.sctipts.indexOf('{'),tplData.sctipts.lastIndexOf('}')+1)}`)();
    //                 ponentObj.template = tplData.templates;
    //
    //
    //                  debugger;//远程组件的方式 不太方便 放弃
    //
    //                 less.render(tplData.styles).then(function(output) {
    //                     let style = document.createElement("style");
    //                     style.setAttribute("type", "text/css");
    //                     let css_text=`.remote-v { ${output.css}}`;
    //                     if(style.styleSheet)// IE
    //                         style.styleSheet.cssText = css_text;
    //                     else {// w3c
    //                         var cssText = document.createTextNode(css_text);
    //                         style.appendChild(cssText);
    //                     }
    //                     var heads = document.getElementsByTagName("head");
    //                     if(heads.length)
    //                         heads[0].appendChild(style);
    //                     else
    //                         document.documentElement.appendChild(style);
    //                 }.bind(this));
    //
    //                 resolve(ponentObj);
    //             });
    //
    //             // require(['../components/ad.vue'],resolve)
    //         },
    //     },
    // }

</script>