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="\takeLocation(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/

时间: 2024-12-28 00:29:07

Vue结合原生js实现自定义组件自动生成的相关文章

使用原生js创建自定义标签

使用原生js创建自定义标签 效果图 代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA

Render函数(2):使用原生js替代自定义指令、修饰符、slot

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" con

vue获取验证码倒计时,自定义组件点击事件不生效的问题

说明:部分组件使用的是element-ui 子组件 <template> <div class="count-down"> <el-button type="primary" size="small" style="width:80px;" :disabled="disabled || time > 0"> {{ text }} </el-button>

vue 上拉加载自定义组件,超好用哦

1.创建组件components > zj-roll > index.vue <template> <div> <slot></slot> <div class='bottom' v-if='(!lastPage.total && lastPage.empty!=0)'>---------- <span >我也是有底线的</span> ----------</div> <div

使用vscode,新建.vue文件,tab(enter)自动生成vue代码模板

第一步: 新建模板并保存 文件 --> 首选项 --> 用户代码片段 --> 输入vue,选择创建模板 填写vue.json -->复制 第三步中的模板内容中内容保存 第二步: 添加配置,让vscode允许自定义的代码片段提示出来 文件 --> 首选项 --> 设置 ---> 添加这2项 // Specifies the location of snippets in the suggestion widget "editor.snippetSugges

vue中自定义组件(插件)

vue中自定义组件(插件) 原创 2017年01月04日 22:46:43 标签: 插件 在vue项目中,可以自定义组件像vue-resource一样使用Vue.use()方法来使用,具体实现方法: 1.首先建一个自定义组件的文件夹,比如叫loading,里面有一个index.js,还有一个自定义组件loading.vue,在这个loading.vue里面就是这个组件的具体的内容,比如: <template> <div> loading.............. </div

Vue 使用use、prototype自定义自己的全局组件

使用Vue.use()写一个自己的全局组件. 目录如下: 然后在Loading.vue里面定义自己的组件模板 <template> <div v-if="loadFlag"> Loading... </div> </template> <script> export default { name: "MyLoading",//组件名称 props: ['loadFlag'], } </script&g

vue2.0学习笔记之自定义组件

step one:    推荐结构 step two:    Loading.vue <template> <h3>{{msg}}</h3> </template> <script> export default { data(){ return { msg: "loading" } } } </script> <style scoped> h3 { color: #699; } </style&

小程序自定义组件

要做自定义组件,我们先定一个小目标,比如说我们在小程序中实现一下 WEUI 中的弹窗组件,基本效果图如下. Step1 我们初始化一个小程序(本示例基础版本库为 1.7 ),删掉里面的示例代码,并新建一个 components 文件夹,用于存放我们以后开发中的所用组件,今天我们的目的是实现一个 弹框 组件,因此,我们在 components 组件中新建一个 Dialog 文件夹来存放我们的弹窗组件,在 Dialog 下右击新建 Component 并命名为 dialog 后,会生成对应的 jso