编辑自己的工具箱 (二) 组件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>

 

  

posted @ 2018-07-31 17:13  blurs  阅读(181)  评论(0编辑  收藏  举报