编辑自己的工具箱 (二) 组件component框架开发
!function(){ var componentFunction = function(){ var component = function( element ){ this.constructor = function(element,option = {}){ this.name = 'Component'+ component.data.length; //对option进行处理 this.handleOption = this.sethandleOption(option); //创建存储数据的对象 this.__data = []; // 存储关联事件 this._attr_data = [] //视图对应的element对象 this.__element; //记录hide隐藏之前的element的显示类型 this.__element__oldDisplay; //属性响应 this.__element_attribute_response = this.__element_attribute_response_.concat(option.response || []); //响应click的属性名 this.__element_click_responseName = 'v_click'; //绑定element this.setElement(element); //开始解析整个组件元素 this.bindEvent(this.__element); //绑定点击事件委托 this.clickEventCommission(this.__element); //记录了组件的循环组件 this.plugin = []; //记录变化回调事件 this.attrChange = option.update || new Function; } component.data.push(this); this.constructor.apply(this,arguments); } component.prototype.setPlugin = function(plugin){ this.plugin.push(plugin) } component.prototype.sethandleOption = function(option){ this.option = option; // 处理attr属性 this.sethandleAttr(option.attr); } component.prototype.sethandleAttr = function(attr){ for( let i in attr ){ let it = attr[i] if( typeof it !== "object" ){ var b = Object.defineProperty( attr , i , { set :(v)=>{ it = v; this.attrChange(v,i); this._attr_data .filter((e)=>{ return e.name === i; }) .forEach((e)=>{ e.fn(it,e); }) }, get (){ return it; } } ) }else{ } } } component.prototype._attr_addEvent = function(name,fn){ this._attr_data.push({ id : parseInt(Math.random() * 1000)+ (new Date())*1 , name, fn }); } component.data = []; /*-------------------视图部分------------------*/ //关于绑定的组件视图 component.prototype.setElement = function(element){ if( typeof element === "string" ) { var div = document.createElement("div"); div.innerHTML = element; element = div.children[0]; } this.__element = element; element.addEventListener("change",this._element_change.bind(this)); }; component.prototype._element_change = function(event){ var name = event.target.getAttribute("v-bind"); this.option.attr[name] = this._getDomValue(event.target); }, component.prototype.getElement = function(element){ return this.__element; }; component.prototype.show = function(){ var el = this.getElement(); if( el ){ el.style.display = this.__element__oldDisplay || 'block'; } } component.prototype.hide = function(){ var el = this.getElement(); this.__element__oldDisplay = el.style.display; el.style.display = 'none'; } //关于绑定的组件事件 component.prototype.bindEvent = function(element){ var this_el; var attribute_response = this.__element_attribute_response.sort(function(a,b){ return a.index < b.index; }); var responseName = this.__element_attribute_responseName; try{ this_el = element; this.bindEventElement(this_el,attribute_response); this.bindEvent(this_el.children[0]); this.bindEvent(this_el.nextElementSibling); }catch(e){ } }; // component.prototype.bindEvent = function(element){ // var el = element.getElementsByTagName('*'); // el = Array.prototype.slice.call(el); // var this_el; // var attribute_response = this.__element_attribute_response.sort(function(a,b){ return a.index < b.index; }); // var responseName = this.__element_attribute_responseName; // var _rp; // for( var i = 0 ; i < el.length ; i++ ){ // try{ // this_el = el[i]; // this.bindEventElement(this_el,attribute_response); // }catch(e){ // } // } // }; component.prototype.bindEventElement = function(element,attribute_response){ attribute_response || ( attribute_response = this.__element_attribute_response.sort(function(a,b){ return a.index < b.index; }) ) for( var _i in attribute_response ){ _rp = element.getAttribute(attribute_response[_i].name); // if( !_rp ){ // var a = Array.prototype.slice.apply(element.attributes); // var regExp = new RegExp(attribute_response[_i].name); // _rp = a.find( (e)=>{ return regExp.test(e) } ); // } if( _rp ){ attribute_response[_i].event.call(this,element,_rp); } } } component.prototype.__element_attribute_response_ = []; component.prototype._add_attribute_response = function(attr,func,index = 0){ var v = this.__element_attribute_response_.find(function(e){return e.name == attr}); if (v) { console.log(attr +'已存在'); } this.__element_attribute_response_.push({name:attr,event:func,index:index}); } component.prototype.add_attribute_response = function(attr,func,index=0){ var v = this.__element_attribute_response.find(function(e){return e.name == attr}); if (v) { console.log(attr +'已存在'); } this.__element_attribute_response.push({name:attr,event:func,index:index}); } //点击事件委托 component.prototype.clickEventCommission = function(element){ var elem = element || this.__element; var v_click = this.__element_click_responseName; elem.addEventListener('click',function(e){ var _this = e.target; for( ; ; ){ if( !_this || !_this.parentElement ) break; if( _this[v_click] ) { _this[v_click](e,); break; } if( _this == this ){ break; } _this = _this.parentElement; } }); } /*-------------------数据部分------------------*/ component.dataType = { 'json': function(data){ this.data = data; this.set = function(data){ this.data = data; } this.get = function(){ return this.data; } } }; component.prototype.get = function(){ return this.__data; }; component.prototype.create = function(name, data , type = 'json'){ return this.get()[name] = new Data.dataType[type](); }; component.prototype.set = function(name,data,cover = false){ if( name ) return; var _d = this.find(name); if( !_d ) _d = this.create(name); if( _d && !cover ){ //如果存在数据 不允许覆盖 return _d; }else{ _d = data; } }; component.prototype.find = function(name){ return this.get().find(function(e){ return e.name == name; }); }; component.prototype.getData = function(name){ var data = this.get(); if( !name ) return data; else return data.find(function(e){ return e.name == name; }) || data; }; //创建数据模块 component.prototype.createData = function(name,data){ this.create(name,data); }; component.prototype.setData = function(name,data){ this.set(name,data,true); }; /*-------------------扩展化 组件------------------*/ var __plugin_v_for = component.prototype.__plugin_v_for = function(option){ this.element = option.element; this.for_elements = option.for_elements; this.component = option.component; } __plugin_v_for.prototype.getAttrName = function(){ return this.element.getAttribute('v-for'); } __plugin_v_for.prototype.getData = function(){ return this.component.option.attr[this.getAttrName()]; } __plugin_v_for.prototype.refresh = function(vfor){ var len = this.for_elements.length; if( len == 0 ) return; this.for_elements[this.for_elements.length-1].after(this.element); for(;this.for_elements.length != 0;) this.for_elements.pop().remove(); vfor && this.element.setAttribute('v-for',vfor); this.component.bindEventElement(this.element); } /*-------------------扩展属性属性部分 (包括函数 和 属性)------------------*/ component.prototype._add_attribute_response( 'v-click' , function(element,value){ element[this.__element_click_responseName] = this.option.event[value] } ) component.prototype._add_attribute_response( 'v-show' , function(element ,value){ var attr = this.option.attr; var v = attr[value]; if( value.indexOf("=") > -1 ){ var fn = value; // 从中找到关联的字段 value = value.replace(/\s{1,}/g,"").split("=")[0]; v = attr[value]; eval("var "+ value+"= v;v =" + fn) if( v ){ element.style.display = element.oldDisplay || "block"; }else{ element.oldDisplay = element.style.display; element.style.display = "none"; } }else{ if( v ){ element.style.display = element.oldDisplay || "block"; }else{ element.oldDisplay = element.style.display; element.style.display = "none"; } this._attr_addEvent(value,function(v){ if( v ){ element.style.display = element.oldDisplay || "block"; }else{ element.oldDisplay = element.style.display; element.style.display = "none"; } }) } } ) component.prototype._v_bind_array = []; component.prototype._add_attribute_response( 'v-bind' , function(element,value){ var attr = this.option.attr; var _value = 'innerText'; if( element.tagName === 'INPUT' || element.tagName === 'SELECT' ){ _value = 'value'; } var fn = value; if( value.indexOf("=") > -1 ){ // 从中找到关联的字段 value = value.replace(/\s{1,}/g,"").split("=")[0]; this._getDomValue(element,eval("var "+value+"= attr['"+value+"'];" + fn)); this._attr_addEvent(value,(v)=>{ eval("var "+value+"= v; v =" + fn); this._getDomValue(element,v) }) }else{ if( !attr[value] ) return; this._getDomValue(element,attr[value]); this._attr_addEvent(value,(v)=>{ this._getDomValue(element,v) }) } }) component.prototype._getDomValue = function(element,value){ var tag = element.tagName; if( tag === "SELECT" || tag === "INPUT" ){ if( element.type === "checkbox" || element.type === "radio" ){ return value !== undefined ? element.checked = value : element.checked; } return value !== undefined ? element.value = value : element.value; }else{ return value !== undefined ? element.innerText = value : element.innerText; } } component.prototype._add_attribute_response( 'v-for' , function(element,value){ var attr = this.option.attr; var data = attr[value]; var name = element.getAttribute('v-for-name'); if( !name ) { name = 'vfor'+parseInt( Math.random() * 100000 ); element.setAttribute('v-for-name',name); } if(element.parentElement) element.parentElement.style.display = 'none'; var _elements = []; for( var i in data ){ var elem = element.cloneNode(true); elem.removeAttribute('v-for'); var elemHtml = elem.innerHTML; for( var ii in data[i] ){ elemHtml = elemHtml.replace(new RegExp("{"+ii+"}","g"),data[i][ii]); } elem.innerHTML = elemHtml; element.after(elem); _elements.push(elem); } if(element.parentElement) element.parentElement.style.display = 'block'; element.remove(); this.for_plugin || (this.for_plugin = {}); if( this.for_plugin[name] ){ this.for_plugin[name].for_elements = _elements; }else{ this.for_plugin[name] = new __plugin_v_for({ element : element , for_elements : _elements ,component : this , attrName : value }); }; } , 999 ) component.prototype._add_attribute_response( '/^:[a-zA-z]{1,}/' , function(element,value){ }) return component; } typeof define === 'undefined' && ( window.component = componentFunction()) || define([],componentFunction) }()
核心源码
设想过很多情况 继承 和 扩展 还有插件 等等情况
初步实现了简单的功能
v-bind
可以和配置 attr属性中的参数做绑定
v-click
可以和配置event中的function事件做绑定
v-for
可以和配置 attr属性中的参数(array)做绑定
v-for-name
指定vfor的名称, 可以在component中for-plugin属性集合里找到对于的遍历对象, 对象里面包含了简单的操作函数 比如 getAttrName getData refresh 等等
例子如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script type="text/javascript" src="component.js" ></script> </head> <body> <div id='liao'> <div v-click='testClick' v-ss='ddd' v-bind='test'> liaoweizhong </div> <input type='text' v-bind='liao'> <div v-for-name='ll' v-for='array' > <span>{text}</span> </div> </div> </body> <script> var a = new component(document.getElementById('liao'),{ //绑定属性 attr : { liao : "2", test : '231232', array : [ { text: '123' , index : 9 }, { text: '12322' , index : 9 } ], array1 : [ { text: 'abc' , index : 9 }, { text: 'abcdx' , index : 9 } ] }, //绑定事件 event : { testClick : function(e){ debugger; } }, //扩展响应事件 response : [ { name : 'v-ss' , event : function(element,value){ element.innerText = value; } } ] }) </script> </html>