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 锚点跳转滚动条平滑滚动一句话代码
Apr 30 Javascript
再谈javascript图片预加载技术(详细演示)
Mar 12 Javascript
jQuery对html元素取值与赋值的方法
Nov 20 Javascript
js仿百度贴吧验证码特效实例代码
Jan 16 Javascript
60个很实用的jQuery代码开发技巧收集
Dec 15 Javascript
jQuery中prepend()方法用法实例
Dec 25 Javascript
基于JavaScript实现移动端TAB触屏切换效果
Oct 20 Javascript
js判断输入字符串是否为空、空格、null的方法总结
Jun 14 Javascript
浅谈jQuery效果函数
Sep 16 Javascript
jQuery实现DIV响应鼠标滑过由下向上展开效果示例【测试可用】
Apr 26 jQuery
vue中$set的使用(结合在实际应用中遇到的坑)
Jul 10 Javascript
vue-router二级导航切换路由及高亮显示的实现方法
Jul 10 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断点续传之如何分割合并文件
2014/03/22 PHP
Yii2 GridView实现列表页直接修改数据的方法
2016/05/16 PHP
详解json在php中的应用
2018/09/30 PHP
js利用Array.splice实现Array的insert/remove
2009/01/13 Javascript
某人初学javascript的时候写的学习笔记
2010/12/30 Javascript
JavaScript Memoization 让函数也有记忆功能
2011/10/27 Javascript
Javascript页面添加到收藏夹的简单方法
2013/08/07 Javascript
jQuery把表单元素变为json对象
2013/11/06 Javascript
javascript 弹出的窗口返回值给父窗口具体实现
2013/11/23 Javascript
JS实现的生成随机数的4个函数分享
2015/02/11 Javascript
使用AngularJS处理单选框和复选框的简单方法
2015/06/19 Javascript
使用requestAnimationFrame实现js动画性能好
2015/08/06 Javascript
JS右下角广告窗口代码(可收缩、展开及关闭)
2015/09/04 Javascript
快速学习JavaScript的6个思维技巧
2015/10/13 Javascript
基于jQuery实现的双11天猫拆红包抽奖效果
2015/12/01 Javascript
jQuery mobile 移动web(6)
2015/12/20 Javascript
JavaScript 定时器 SetTimeout之定时刷新窗口和关闭窗口(代码超简单)
2016/02/26 Javascript
jQuery无刷新上传之uploadify3.1简单使用
2016/06/18 Javascript
JS中判断某个字符串是否包含另一个字符串的五种方法
2018/05/03 Javascript
微信小程序的tab选项卡的实现效果
2019/05/15 Javascript
vue实现井字棋游戏
2020/09/29 Javascript
如何使用原生Js实现随机点名详解
2021/01/06 Javascript
详细解读Python中解析XML数据的方法
2015/10/15 Python
pandas 层次化索引的实现方法
2019/07/06 Python
Django实现celery定时任务过程解析
2020/04/21 Python
Pytorch 卷积中的 Input Shape用法
2020/06/29 Python
Django路由层URLconf作用及原理解析
2020/09/24 Python
python爬虫用scrapy获取影片的实例分析
2020/11/23 Python
JOSEPH官网:英国奢侈时尚品牌
2018/01/31 全球购物
旧时光糖果:Old Time Candy
2018/02/05 全球购物
如何将无状态会话Bean发布为WEB服务,只有无状态会话Bean可以发布为WEB服务?
2015/12/03 面试题
普罗米修斯教学反思
2014/02/06 职场文书
2014年幼儿园重阳节活动方案
2014/09/16 职场文书
银行先进个人总结
2015/02/15 职场文书
郭明义观后感
2015/06/08 职场文书
JavaScript中isPrototypeOf函数
2021/11/07 Javascript