zoukankan      html  css  js  c++  java
  • Vue结合原生js实现自定义组件自动生成

      就目前三大前端主流数据驱动框架(vue,ng,react)而言,均具有创建自定义组件的api,但都是必须先做到事先写好挂载点,这个挂载点可以是原有静态元素标签也可以是自定义模板;对于多种组件通过同一数据流生成的,如果事先在页面上写好挂载点(mounted),然后通过dom操作去动态添加,会遇到类似这样一条错误提示信息:Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.(…)。这又是为何呢,下一步该怎么办?

      原因是任何dom操作的对象必须是符合W3C标准的元素,除非如下所述的,改写生成html元素对象的原型(HTMLElement.prototype)并注册自定义元素,从而实现动态生成自定义组件的效果。

      不过,大家都明白使用数据驱动框架的初衷就是尽可能避免dom操作,而如下代码中还是有一些dom操作的,就目前认知水平而言,感觉这些必要的dom操作还是避免不了的。其它不多说了,直接看代码。。。

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="Content-type" content="text/html,charset=utf-8"/>
        <meta http-equiv="X-UA-Compatible" content="IE-edge">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <link href="css/mui.min.css" rel="stylesheet">
        <link href="css/app.css" rel="stylesheet">
        <script src="js/vue.js" type="text/javascript"></script>
    </head>
    <body>
    <div id="main" class="mui-content">
    </div>
    </body>
    <script src="js/fuhao-components.js" type="text/javascript"></script>
    
    <script>
    
        var jsonData = [
            {
                "keyname": "姓名鄂然失色而热重重中之重重中之重杂志的热热",
                "type": "text",
                "key": "name11"
            }, {
                "value": "姓名鄂之重杂志的热热",
                "key": "name11"
            }, {
                "keyname": "姓名鄂然失色而热热热热是重中之重重中之重重中之重杂志的热热",
            },
            {
                "keyname": "姓名鄂然失色而热热热热是重中之重重中之重重中之重杂志的热热",
                "type": "textarea",
                "key": "name"
            },
            {
                "keyname": "性别",
                "type": "radio",
                "key": "sex",
                "values": [
                    {
                        "key": "man",
                        "value": "男辅导班"
                    },
                    {
                        "key": "women",
                        "value": "女"
                    }
                ]
            },
            {
                "keyname": "复选",
                "type": "checkbox",
                "key": "checkbox",
                "values": [
                    {
                        "key": "man",
                        "value": "男"
                    },
                    {
                        "key": "women",
                        "value": "女"
                    }
                ]
            },
            {
                "keyname": "类型",
                "type": "select",
                "key": "type1",
                "values": [
                    {
                        "key": "type1",
                        "value": "类型1"
                    },
                    {
                        "key": "type2",
                        "value": "类型2"
                    },
                    {
                        "key": "type3",
                        "value": "类型3"
                    },
                    {
                        "key": "type4",
                        "value": "类型4"
                    }
                ]
            },
            {
                "keyname": "定位",
                "type": "gps",
                "key": "btn",
                "value": "地图获取定位"
            },
            {
                "keyname": "拍照",
                "type": "photo",
                "key": "btn",
                "value": "拍照"
            }
        ];
        (function () {
            AnalyJson(jsonData);
        })();
        function AnalyJson(data) {
            if ('id' in data) {
                arguments.callee(data.values);
            } else {
                if ('name' in data) {
                    htmlname = data.name;
                    CreateInputViewer(data.name);
                    arguments.callee(data.values);
                } else {
                    if ('type' in data) {
                        CreateInputViewer(data);
                    } else {
                        for (var p in data) {
                            CreateInputViewer(data[p]);
                        }
                    }
                }
            }
        }
        function CreateInputViewer(data) {
            switch (data.type) {
                case 'text': {
                    fh_C(data, 'c-input-text' + '-' + data.key, 'fhInputText', textTpl);
                    break;
                }
                case 'textarea': {
                    fh_C(data, 'c-textarea' + '-' + data.key, 'fhInputTextarea', textareaTpl);
                    break;
                }
                case 'radio': {
                    fh_C(data, 'c-input-radio' + '-' + data.key, 'fhInputTextarea', radioTpl);
                    break;
                }
                case 'checkbox': {
                    fh_C(data, 'c-input-checkbox' + '-' + data.key, 'fhInputCheckbox', checkboxTpl);
                    break;
                }
                case 'select': {
                    fh_C(data, 'c-select' + '-' + data.key, 'fhSelect', selectTpl);
                    break;
                }
                case 'photo': {
                    fh_C(data, 'c-photo' + '-' + data.key, 'fhPhoto', photoTpl);
                    break;
                }
                case 'gps': {
                    fh_C(data, 'c-gps' + '-' + data.key, 'fhGPS', gpsTpl);
                    break;
                }
                default: {
                    fh_C(data, 'c-default' + '-' + data.key, 'fhInputDefault', defaultTpl);
                    break;
                }
    
            }
        }
        function fh_C(d, c, cn, tpl) {
            console.log(d);
            Vue.component(c, {
                template: tpl,
    //             props:['key','keyname','values','value'],
                data: function () {
                    return d
                }
            });
            new Vue({
                el: '.mui-content',
                components: {
                    cn: cn
                },
            });
            var MyElementProto = Object.create(HTMLElement.prototype);
            MyElementProto.createdCallback = function () {
                this.innerHTML = tpl
            };
            var MyComponent = document.registerElement(c, {prototype: MyElementProto});
            document.querySelector('.mui-content').appendChild(new MyComponent());
        }
    </script>
    </html>

    为了保持代码的可维护性及易读性,我将模板部分单独放在fuhao-components.js的文件里边,如下所示:


    var textTpl= '
    <div class="mui-content-padded">
    <input :type="type" :name="key" :placeholder="keyname" >
    </div>
    ';
    var textareaTpl= '
    <div class="mui-content-padded ">
    <textarea rows="5" :placeholder="keyname">
    </textarea>
    </div>
    ';
    var radioTpl= '
    <form class="mui-input-group mui-content-padded">
    <div class="mui-input-row mui-radio mui-left"v-for="value in values">
    <label>{{value.key}}</label>
    <input :name="key" :type="type" :value="key">
    </div>
    </form>
    ';
    var checkboxTpl= '
    <form class="mui-input-group mui-content-padded">
    <div class="mui-input-row mui-checkbox mui-left"v-for="value in values">
    <label>{{value.key}}</label>
    <input :name="key" :type="type" :value="key">
    </div>
    </form>
    ';
    var selectTpl= '
    <div class="mui-content-padded">
    <h5 class="mui-content-padded" v-text="keyname"></h5>
    <select class="mui-btn mui-btn-block " :name="key">
    <option value="key" v-text="value.key" v-for="value in values">{{value.key}}</option>
    </select>
    </div>
    ';
    var photoTpl= '
    <div class="mui-content-padded">
    <span v-text="keyname"></span>
    <button :name="key" onclick="takePhoto(this.name)" class="mui-btn mui-btn-primary">拍照</button>
    <img :id="key" height="70" width="100" class="img-rounded">
    </div>
    ';
    var gpsTpl= '
    <div class="mui-content col-xs-12">
    <button class="mui-btn mui-btn-primary" :id="key" onclick=" akeLocation(this.id)">
    获取定位
    </button>
    </div>
    ';
    var defaultTpl= '
    <div class="mui-content-padded " v-if="key">
    <ul class="mui-table-view">
    <li class="mui-table-view-cell mui-media">
    <span class="fuhaoKey" v-text="key"></span>
    <span class="fuhaoValue" v-text="value"></span>
    </li>
    </ul >
    </div>
    ';

    最终渲染效果如下:

    鉴于vue结合dom操作动态生成自定义组件,控制台会报一定的错误这一点bug还在努力修复中,可能需要更加深入地了解vue数据绑定及传递机制与js动态注册自定义组件的深入领会,继续努力中。。。

    谢谢阅览,不足之处还望多多指点,非常感谢。

    参考文献:1.http://www.html-js.com/article/2753

         2.http://vuejs.org/

  • 相关阅读:
    CodeForces 156B Suspects(枚举)
    CodeForces 156A Message(暴力)
    CodeForces 157B Trace
    CodeForces 157A Game Outcome
    HDU 3578 Greedy Tino(双塔DP)
    POJ 2609 Ferry Loading(双塔DP)
    Java 第十一届 蓝桥杯 省模拟赛 19000互质的个数
    Java 第十一届 蓝桥杯 省模拟赛 19000互质的个数
    Java 第十一届 蓝桥杯 省模拟赛 19000互质的个数
    Java 第十一届 蓝桥杯 省模拟赛十六进制转换成十进制
  • 原文地址:https://www.cnblogs.com/frank26/p/5986205.html
Copyright © 2011-2022 走看看