Vue结合原生js实现自定义组件自动生成示例


Posted in Javascript onJanuary 21, 2017

就目前三大前端主流数据驱动框架(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结合原生js实现自定义组件自动生成示例

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 无符号右移赋值操作
Apr 17 Javascript
JS刷新当前页面的几种方法总结
Dec 24 Javascript
JavaScript制作的可折叠弹出式菜单示例
Apr 04 Javascript
Angular.js 实现数字转换汉字实例代码
Jul 14 Javascript
浅析Javascript ES6新增值比较函数Object.is
Aug 24 Javascript
整理关于Bootstrap警示框的慕课笔记
Mar 29 Javascript
微信小程序 循环及嵌套循环的使用总结
Sep 26 Javascript
Vue.js实现可配置的登录表单代码详解
Mar 29 Javascript
详解Vue结合后台的列表增删改案例
Aug 21 Javascript
微信小程序地图(map)组件点击(tap)获取经纬度的方法
Jan 10 Javascript
JavaScript indexOf()原理及使用方法详解
Jul 09 Javascript
用几道面试题来看JavaScript执行机制
Apr 30 Javascript
jQuery基于正则表达式的表单验证功能示例
Jan 21 #Javascript
一篇文章搞定JavaScript类型转换(面试常见)
Jan 21 #Javascript
超全面的JavaScript开发规范(推荐)
Jan 21 #Javascript
Mongoose学习全面理解(推荐)
Jan 21 #Javascript
ng-options和ng-checked在表单中的高级运用(推荐)
Jan 21 #Javascript
vue实现添加标签demo示例代码
Jan 21 #Javascript
微信小程序 数据交互与渲染实例详解
Jan 21 #Javascript
You might like
php长字符串定义方法
2012/07/12 PHP
ThinkPHP函数详解之M方法和R方法
2015/09/10 PHP
PHP+JS三级菜单联动菜单实现方法
2016/02/24 PHP
Javascript 八进制转义字符(8进制)
2011/04/08 Javascript
jQuery AjaxQueue改进步骤
2011/10/06 Javascript
javascript遍历控件实例详细解析
2014/01/10 Javascript
Javascript让DEDECMS告别手写Tag
2014/09/01 Javascript
javascript实现表单提交后,提交按钮不可用的方法
2015/04/18 Javascript
javascript实时显示当天日期的方法
2015/05/20 Javascript
个人总结的一些JavaScript技巧、实用函数、简洁方法、编程细节
2015/06/10 Javascript
jquery validate demo 基础
2015/10/29 Javascript
Jquery对新插入的节点 绑定Click事件失效的解决方法
2016/06/02 Javascript
ajax +NodeJS 实现图片上传实例
2017/06/06 NodeJs
实例解析ES6 Proxy使用场景介绍
2018/01/08 Javascript
把vue-router和express项目部署到服务器的方法
2018/02/21 Javascript
利用js实现前后台传送Json的示例代码
2018/03/29 Javascript
JS实现的Object数组去重功能示例【数组成员为Object对象】
2019/02/01 Javascript
jquery操作checkbox的常用方法总结【附测试源码下载】
2019/06/10 jQuery
JavaScript实现PC端横向轮播图
2020/02/07 Javascript
使用 Vue-TCB 快速在 Vue 应用中接入云开发的方法
2020/02/10 Javascript
[03:52]DOTA2英雄基础教程 酒仙
2013/12/23 DOTA
python中while循环语句用法简单实例
2015/05/07 Python
django2+uwsgi+nginx上线部署到服务器Ubuntu16.04
2018/06/26 Python
python七夕浪漫表白源码
2019/04/05 Python
在pyqt5中QLineEdit里面的内容回车发送的实例
2019/06/21 Python
Django 中自定义 Admin 样式与功能的实现方法
2019/07/04 Python
pandas基于时间序列的固定时间间隔求均值的方法
2019/07/04 Python
python中watchdog文件监控与检测上传功能
2020/10/30 Python
欧洲顶级体育电子商务网站:SportsShoes.com
2018/03/27 全球购物
美国厨房和园艺工具网上商店:Nestneed
2019/08/24 全球购物
GafasWorld西班牙:购买太阳镜、眼镜和隐形眼镜
2019/09/08 全球购物
JDK安装目录下有哪些内容
2014/08/25 面试题
赔偿协议书范本
2014/04/15 职场文书
投标文件签署授权委托书范本
2014/10/12 职场文书
2014全年工作总结
2014/11/27 职场文书
大学生自我评价范文
2015/03/03 职场文书