就目前三大前端主流数据驱动框架(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动态注册自定义组件的深入领会,继续努力中。。。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。