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

浙公网安备 33010602011771号