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 相关文章推荐
jquery 图片截取工具jquery.imagecropper.js
Apr 09 Javascript
基于jquery的多彩百分比 动态进度条 投票效果显示效果实现代码
Aug 28 Javascript
DOM操作和jQuery实现选项移动操作的简单实例
Jun 07 Javascript
基于Bootstrap和jQuery构建前端分页工具实例代码
Nov 23 Javascript
通过sails和阿里大于实现短信验证
Jan 04 Javascript
使用smartupload组件实现jsp+jdbc上传下载文件实例解析
Jan 05 Javascript
Javascript继承机制详解
May 30 Javascript
原生js中ajax访问的实例详解
Sep 19 Javascript
微信小程序实现跑马灯效果
Oct 21 Javascript
微信小程序使用npm包的方法步骤
Aug 13 Javascript
vue 中几种传值方法(3种)
Nov 12 Javascript
js观察者模式的弹幕案例
Nov 23 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概述.
2006/10/09 PHP
php curl 伪造IP来源的实例代码
2012/11/01 PHP
ThinkPHP中的常用查询语言汇总
2014/08/22 PHP
PHP制作百度词典查词采集器
2015/01/29 PHP
php多重接口的实现方法
2015/06/20 PHP
php ucwords() 函数将字符串中每个单词的首字符转换为大写(实现代码)
2016/05/12 PHP
PHP简单验证码功能机制实例详解
2019/03/27 PHP
网页里控制图片大小的相关代码
2006/06/13 Javascript
在IE中调用javascript打开Excel的代码(downmoon原作)
2007/04/02 Javascript
Cookie 注入是怎样产生的
2009/04/08 Javascript
JS实现可自定义大小,可双击关闭的弹出层效果
2015/10/16 Javascript
Javascript中的Prototype到底是什么
2016/02/16 Javascript
一览画面点击复选框后获取多个id值的方法
2016/05/30 Javascript
html5+CSS 实现禁止IOS长按复制粘贴功能
2016/12/28 Javascript
vue日期组件 支持vue1.0和2.0
2017/01/09 Javascript
Java与JavaScript中判断两字符串是否相等的区别
2017/03/13 Javascript
JavaScript定义函数的三种实现方法
2017/09/23 Javascript
使用 Vue 绑定单个或多个 Class 名的实例代码
2018/01/08 Javascript
vux uploader 图片上传组件的安装使用方法
2018/05/15 Javascript
微信小程序自定义对话框弹出和隐藏动画
2018/07/19 Javascript
图解javascript作用域链
2019/05/27 Javascript
jQuery实现每日秒杀商品倒计时功能
2019/09/06 jQuery
Vue切换div显示隐藏,多选,单选代码解析
2020/07/14 Javascript
[05:10]2014DOTA2国际邀请赛 通往胜利之匙赛场探秘之旅
2014/07/18 DOTA
Python运算符重载用法实例
2015/05/28 Python
Python的Django中django-userena组件的简单使用教程
2015/05/30 Python
Python 操作MySQL详解及实例
2017/04/30 Python
selenium python 实现基本自动化测试的示例代码
2019/02/25 Python
Python内置random模块生成随机数的方法
2019/05/31 Python
pandas之分组groupby()的使用整理与总结
2020/06/18 Python
Python 实现键盘鼠标按键模拟
2020/11/18 Python
Michael Kors加拿大官网:购买设计师手袋、手表、鞋子、服装等
2019/03/16 全球购物
岗位竞聘报告范文
2014/11/06 职场文书
2014年中班下学期工作总结
2014/12/11 职场文书
铁人观后感
2015/06/16 职场文书
Python Socket编程详解
2021/04/25 Python