就目前三大前端主流数据驱动框架(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/

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

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

    使用原生js创建自定义标签 效果图 代码 <!DOCTYPE html> <html lang="en"> <head> <meta ch ...

  2. 自定义Mybatis自动生成代码规则

    前言 大家都清楚mybatis-generate-core 这个工程提供了获取表信息到生成model.dao.xml这三层代码的一个实现,但是这往往有一个痛点,比如需求来了,某个表需要增加字段,肯定需 ...

  3. 原生js实现自定义alert风格和实现

    2018年6月29 最新更新 添加函数节流,解决多次点击问题,添加单例模式,提高代码性能. <!DOCTYPE html> <html lang="en"> ...

  4. vue使用原生js实现滚动页面跟踪导航高亮

    需要使用vue做一个专题页面. 滚动页面指定区域导航高亮. BetterScroll:可能是目前最好用的移动端滚动插件 如何自定义CSS滚动条的样式? 监听滚动页面事件,对比当前页面的位置与元素的位置 ...

  5. 原生js+css3实现图片自动切换,图片轮播

    运用CSS3transition及opacity属性 制作图片轮播动画 自己这两天根据用js来控制触发CSS3中transition属性,从而写出来的以CSS3动画为基础,js控制过程的图片轮播 运用 ...

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

    1.创建组件components > zj-roll > index.vue <template> <div> <slot></slot> ...

  7. 原生 JS 实现 VS Code 自动切换输入法状态!这次没有AHK

    上一篇文章:使用 AHK 在 VS Code 中根据上下文自动切换输入法状态 给出一个使用 ahk 在 VSCode 自动切换输入法的方法.不过这个方法实际上很蹩脚,一点都不优(zhuang)雅(bi ...

  8. Vue文件 引入.js文件 的组件

    Vue.component('remote-script', { render: function (createElement) { var self = this; return createEl ...

  9. 浅谈pipreqs组件(自动生成需要导入的模块信息)

    简介 pipreqs的作用 一起开发项目的时候总是要搭建环境和部署环境的,这个时候必须得有个python第三方包的list,一般都叫做requirements.txt. 如果一个项目使用时virtua ...

随机推荐

  1. JQuery学习五

    获取样式attr("myclass")移除样式removeClass("myclass")增加样式addClass("myclass")to ...

  2. java 反射和new的区别

    关于java 反射和new的区别,在这里我不做多讲,因为网上有大把资料,描述得很详细. 今天我只讲一点,为什么要用反射?直接用new不行么?干嘛弄得那么麻烦! 1.基本上效果差不多,但是new对象,无 ...

  3. nginx 安装 lua-nginx-module

    nginx增加lua模块 yum install -y gcc g++ gcc-c++ zlib zlib-devel openssl openssl-devel pcre pcre-devel wg ...

  4. Windows/Linux javac/java编译运行引入所需的jar包

    > Windows 假设要引用的jar放在D:/test目录下,名字为t1.jar, java源文件放在D:/test/src目录下,名字为t2.java. 编译: javac  -cp  d: ...

  5. 【BZOJ】1914: [Usaco2010 OPen]Triangle Counting 数三角形

    [题意]给定坐标系上n个点,求能构成的包含原点的三角形个数,n<=10^5. [算法]极角排序 [题解]补集思想,三角形个数为C(n,3)-不含原点三角形. 将所有点极角排序. 对于一个点和原点 ...

  6. 【转载】Quick-Cocos2d-x文件结构分析

    在上一章我们讲过了Quick-Cocos2d-x中的环境搭建,这章我们分析下quick中的文件结构吧!打开quick的文件夹,可以看到如下的这些目录和文件: bin:存放各种与引擎相关的脚本 comp ...

  7. D题 hdu 1412 {A} + {B}

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1412 {A} + {B} Time Limit: 10000/5000 MS (Java/Others ...

  8. DesignPattern

    目录

  9. 探索ReactNative应用

    本篇文章是我看AC2016腾讯前端技术交流大会后写的.写的不好,大家见谅啊. 一,什么是ReactNative? 简单来说就是可以用javascript来写APP了,而且性能还不错. 用JS写的话已经 ...

  10. vue路由-动态路由和嵌套路由

    一.动态路由 我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件.例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染.那么,我们可以在 vue-route ...