详解js的事件代理(委托)
JavaScript事件代理(委托)一般用于以下情况:
1.事件注册在祖先级元素上,代理其子级元素。可以减少事件注册数量,节约内存开销,提高性能。
2.对js动态添加的子元素可自动绑定事件。
之前一直用各种js库的事件代理,如jQuery,非常方便实用。今天尝试用原生js实现该功能。
varaddEvent=(function(){
if(document.addEventListener){
returnfunction(element,type,handler){
element.addEventListener(type,handler,false);
};
}elseif(document.attachEvent){
returnfunction(element,type,handler){
element.attachEvent('on'+type,function(){
handler.apply(element,arguments);
});
};
}else{
returnfunction(element,type,handler){
element['on'+type]=function(){
returnhandler.apply(element,arguments);
};
};
}
})(),
getClassElements=function(parentElement,classname){
varall,element,classArr=[],classElements=[];
if(parentElement.getElementsByClassName){
returnparentElement.getElementsByClassName(classname);
}else{
all=parentElement.getElementsByTagName('*');
for(vari=0,len=all.length;i<len;i++){
element=all[i];
classArr=element&&element.className&&element.className.split('');
if(classArr){
for(varj=0;j<classArr.length;j++){
if(classArr[j]===classname){
classElements.push(element);
}
}
}
}
returnclassElements;
}
},
delegate=function(){//参数:element,type,[selector,]handler
varargs=arguments,
element=args[0],
type=args[1],
handler;
if(args.length===3){
handler=args[2];
returnaddEvent(element,type,handler);
}
if(args.length===4){
selector=args[2];
handler=args[3];
returnaddEvent(element,type,function(event){
varevent=event||window.event,
target=event.target||event.srcElement,
quickExpr=/^(?:[a-zA-Z]*#([\w-]+)|(\w+)|[a-zA-Z]*\.([\w-]+))$/,
match,
idElement,
elements,
tagName,
count=0,
len;
if(typeofselector==='string'){
match=quickExpr.exec(selector);
if(match){
//#IDselector
if(match[1]){
idElement=document.getElementById(match[1]);
tagName=match[0].slice(0,match[0].indexOf('#'));
//tagselector
}elseif(match[2]){
elements=element.getElementsByTagName(selector);
//.classselector
}elseif(match[3]){
elements=getClassElements(element,match[3]);
tagName=match[0].slice(0,match[0].indexOf('.'));
}
}
if(idElement){
if(tagName?tagName===idElement.nodeName.toLowerCase()&&target===idElement:target===idElement){
returnhandler.apply(idElement,arguments);
}
}elseif(elements){
for(len=elements.length;count<len;count++){
if(tagName?tagName===elements[count].nodeName.toLowerCase()&&target===elements[count]:target===elements[count]){
returnhandler.apply(elements[count],arguments);
}
}
}
}
});
}
};
主要是用apply改变this的指向
handler.apply(idElement,arguments); handler.apply(elements[count],arguments);
测试一下:
<style>
#outer{padding:50px;background-color:lightpink;}
#inner{padding:30px;background-color:aliceblue;}
#paragraph1,#paragraph3{background-color:cadetblue}
</style>
<divid="outer">outer <divid="inner">inner <pid="paragraph1"class="parag1">paragraph1</p> <pid="paragraph2"class="parag">paragraph2</p> <span>span</span> <pid="paragraph3"class="parag">paragraph3</p> </div> </div>
varouter=document.getElementById('outer');
delegate(outer,'click',function(){
console.log(this.id);//outer
});
delegate(outer,'click','p',function(){
console.log(this.id);//点击paragraph1元素,输出其id为"paragraph1"
});
模仿jQuery的风格,优化代码:
(function(){
var$=function(element){
returnnew_$(element);
};
var_$=function(element){
this.element=element&&element.nodeType===1?element:document;
};
_$.prototype={
constructor:_$,
addEvent:function(type,handler,useCapture){
varelement=this.element;
if(document.addEventListener){
element.addEventListener(type,handler,(useCapture?useCapture:false));
}elseif(document.attachEvent){
element.attachEvent('on'+type,function(){
handler.apply(element,arguments);
});
}else{
element['on'+type]=function(){
returnhandler.apply(element,arguments);
};
}
returnthis;
},
getClassElements:function(classname){
varelement=this.element,all,ele,classArr=[],classElements=[];
if(element.getElementsByClassName){
returnelement.getElementsByClassName(classname);
}else{
all=element.getElementsByTagName('*');
for(vari=0,len=all.length;i<len;i++){
ele=all[i];
classArr=ele&&ele.className&&ele.className.split('');
if(classArr){
for(varj=0;j<classArr.length;j++){
if(classArr[j]===classname){
classElements.push(ele);
}
}
}
}
returnclassElements;
}
},
delegate:function(){//参数:type,[selector,]handler
varself=this,
element=this.element,
type=arguments[0],
handler;
if(arguments.length===2){
handler=arguments[1];
returnself.addEvent(type,handler);
}elseif(arguments.length===3){
selector=arguments[1];
handler=arguments[2];
returnself.addEvent(type,function(event){
varevent=event||window.event,
target=event.target||event.srcElement,
quickExpr=/^(?:[a-zA-Z]*#([\w-]+)|(\w+)|[a-zA-Z]*\.([\w-]+))$/,
match,
idElement,
elements,
tagName,
count=0,
len;
if(typeofselector==='string'){
match=quickExpr.exec(selector);
if(match){
//#IDselector
if(match[1]){
idElement=document.getElementById(match[1]);
tagName=match[0].slice(0,match[0].indexOf('#'));
//tagselector
}elseif(match[2]){
elements=element.getElementsByTagName(selector);
//.classselector
}elseif(match[3]){
elements=self.getClassElements(match[3]);
tagName=match[0].slice(0,match[0].indexOf('.'));
}
}
if(idElement){
if(tagName?tagName===idElement.nodeName.toLowerCase()&&target===idElement?target===idElement){
returnhandler.apply(idElement,arguments);
}
}elseif(elements){
for(len=elements.length;count<len;count++){
if(tagName?tagName===elements[count].nodeName.toLowerCase()&&target===elements[count]:target===elements[count]){
returnhandler.apply(elements[count],arguments);
}
}
}
}
});
}
}
};
window.$=$;
return$;
}());
使用如下:
varouter=document.getElementById('outer');
$(outer).delegate('click','.parag',function(event){
console.log(this.id);
});
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持毛票票!