事件總括
* 1、行為本身:瀏覽器天生就賦予其行為onclick onmouseover onmouseout (onmouseenter onmouseleave不會產(chǎn)生事件冒泡) onmousemove
* onmousedown onmouseup onmousewheel onscroll onresize onload onunload onfocus onblur onkeydown onkeyup。。。
* 沒有給上述行為綁定方法,事件也存在,觸發(fā)后執(zhí)行,只是什么都不做而已
* 2、事件綁定:
* oDiv.onclick=function... DOM0級事件綁定 onclick行為定義在oDiv的私有屬性上
* oDiv.addEventListener('click',function(){},false) DOM2級事件 addEventListener這個屬性是定義在EventTarget
* 這個類的原型上
事件的傳播機制
* 捕獲階段:從里往外一次查找元素
* 目標階段:當(dāng)前事件源本身操作
* 冒泡階段:從內(nèi)到外依次觸發(fā)相關(guān)行為(最常用)

事件傳播機制.jpg
- 冒泡和捕獲
捕獲就是:爹(target)的事件觸發(fā),兒子和孫子的相同的事件也會被觸發(fā)
冒泡就是:兒子(target)觸發(fā)事件,爹和祖宗的相同的事件也會被觸發(fā)
阻止冒泡
e.stopPropagation會阻止冒泡,意思就是到我為止,我的爹和祖宗的事件就不要觸發(fā)了。
事件委托
把事件綁定到目標元素群的父元素上,通過e.target來判斷點擊的真正目標,在執(zhí)行相應(yīng)的程序
事件冒泡與默認行為
讓事件處理函數(shù)return false來阻止冒泡和默認行為, 可以認為return false做了三件事情:
1.stopPropagation();
2.preventDefault();
3.立即結(jié)束當(dāng)前函數(shù)并返回。
DOM 0級事件
- 給元素對象的某一個私有的屬性賦一個值(一個函數(shù)的值),當(dāng)事件觸發(fā)的時候找到對應(yīng)的屬性值,并且執(zhí)行
- DOM 0級事件只能給元素的某一個事件綁定一次方法,最后綁定的方法會把前面綁定的所有的方法都覆蓋掉
DOM 2級事件
- 給當(dāng)前元素的某一個事件綁定的方法都放置在事件池中,當(dāng)事件執(zhí)行的時候,會把事件池里的所有的方法依次去執(zhí)行
1.addEventListener 綁定事件
2.removeEventListener 移除事件 - DOM 2級事件可以為當(dāng)前元素的某一個事件綁定多個不同的方法,當(dāng)前事件觸發(fā)時,會到對應(yīng)的事件池中把所有的綁定的方法依次執(zhí)行。
- DOM2和DOM0事件共存,不會沖突 。
深入
- DOM2可以給元素的某一個事件行為綁定多個方法
1.事件觸發(fā)時執(zhí)行對應(yīng)的方法們,此時不管哪個方法中的this指向的都是當(dāng)前元素
2.我們按順序把順序增加到‘事件池’中,當(dāng)觸發(fā)事件時,方法按照添加的順序依次執(zhí)行
3.如果當(dāng)前的方法已經(jīng)給元素的這個行為綁定過一次了,事件池中這個方法不會重復(fù)添加 - DOM2中,我們一般綁定的都是實名函數(shù),只有這樣,當(dāng)移除的時候才知道移除誰,
在IE6-8中綁定的方法只能在冒泡階段發(fā)生。 - DOM2事件在IE6-8中兼容問題。
1.綁定的語法不一樣,IE6-8中,使用attachEvent、detachEvent
2.標準瀏覽器this指向當(dāng)前元素,IE6-8指向window
3.重復(fù)綁定問題,IE6-8 相同的方法可以重復(fù)綁定
4.順序問題,標準瀏覽器按綁定的順序執(zhí)行函數(shù),IE6-8 沒有順序
function on(ele,type,fn){
if(/^self/.test(type)){//說明是自定義的事件 都帶前綴self
if(!ele['aself'+type]){
ele['aself'+type]=[]//創(chuàng)建自定義事件的事件池
}
var a=ele['aself'+type];
for(var i=0;i<a.length;i++){
if(a[i]==fn)return;
}
a.push(fn);//如果這個函數(shù)沒有添加過事件池,那么就添加進去
}else if(ele.addEventListener){//標準瀏覽器的事件添加
ele.addEventListener(type,fn,false);
}else{//IE瀏覽器的事件添加
if(!ele['aEvent'+type]){
ele['aEvent'+type]=[];
}
var a=ele['aEvent'+type];
for(var i=0;i< a.length;i++){
if(a[i]==fn)return;
ele.attach('on'+type,function(){//提前綁定好事件,只要觸發(fā)就執(zhí)行run
run.call(ele);
})
}
a.push(fn);
}
}
function run (){
var e=e||window.event;
if(!e.target){
e.target=e.srcElement;
e.pageX=e.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft);
e.pageY= e.clientY+(document.documentElement.scrollTop||document.body.scrollTop)
}
e.stopPropagation=function(){
e.cancelBubble=true;
}
e.preventDefault=function(){
e.returnValue=false
}
var a= this['aEvent'+type];
if(a){
for(var i=0;i< a.length;i++){
var fn=a[i];
if(type fn == 'function'){
fn.call(this,e);
}else{
a.splice(i,1)
i--;
}
}
}
}
function selfRun(selfType,e){
var a=this['aSelf'+selfType];
if(a){
for(var i=0;i< a.length;i++){
var fn=a[i];
if(type fn == 'function'){
fn.call(this,e);
}else{
a.splice(i,1)
i--;
}
}
}
}
function off(ele,type,fn){
if(/^self/.test(type)){
var a=ele['aSelf'+type];
if(a){
for(var i=0;i< a.length;i++){
if(a[i]==fn){
a[i]=null;
return;
}
}
}
}
if(ele.removeEventListener){
ele.removeEventListener(type,fn,false);
}else{
var a=ele['aEvent'+type]
if(a){
for(var i=0;i< a.length;i++){
if(a[i]==fn){
a[i]=null;
return;
}
}
}
}
}
自定義事件(訂閱發(fā)布模式)
function EventEmitter(){
}
EventEmitter.prototype.on=function(type,fn){
if(!this['aEmitter'+type]){
this['aEmitter'+type]=[]
}
var a=this['aEmitter'+type];
for(var i=0i<a.length;i++){
if(a[i]==fn)return;
a.push(fn);
}
}
EventEmitter.prototype.run=function(type,e){
var a=this['aEmitter'+type];
if(a){
for(var i=0i<a.length;i++){
if(typeof a[i]=='function'){
a[i].call(this,e);
}else{
a.split(i,1);
i--;
};
}
}
}
EventEmitter.prototype.off=function(type,fn){
var a=this['aEmitter'+type];
if(a){
for(var i=0i<a.length;i++){
if(a[i]==fn){
a[i]=null;
};
}
}
}
jquery綁定
$(ele).bind() ------在新版本已經(jīng)淘汰
將會給所有匹配的元素都綁定一次事件,當(dāng)元素很多時性能會變差。 而且后來動態(tài)新增的元素不會被綁定。
可以添加自定義事件 然后用trigger來手動觸發(fā)該事件。
多個事件類型可以通過用空格隔開一次性綁定:
$('#foo').bind('mouseenter mouseleave', function() {
$(this).toggleClass('entered');
});
- 可以通過傳遞一個事件類型/處理函數(shù)的數(shù)據(jù)鍵值對映射來綁定多個事件處理程序
$('#foo').bind({
click: function() {
// do something on click
},
mouseenter: function() {
// do something on mouseenter
}
});
$(ele).delegate()
- 它將事件處理函數(shù)綁定在指定的根元素上, 由于事件會冒泡,它用來處理指定的子元素上的事件。
- 用于事件委托。
$("table").delegate("td", "click", function() {
$(this).toggleClass("chosen");
});
是等價于下面使用.on()的代碼:
$("table").on("click", "td", function() {
$(this).toggleClass("chosen");
});
$(ele).on()
- 綁定事件最通用的方法,用$(ele).off()解綁事件
- 向事件處理函數(shù)中傳入數(shù)據(jù),并且在事件處理函數(shù)中通過名字來獲取傳入的數(shù)據(jù):
function myHandler(event) {
alert(event.data.foo);
}
$("p").on("click", {foo: "bar"}, myHandler)
$(ele).one()
- 處理函數(shù)在每個元素上每種事件類型最多執(zhí)行一次
$( "#foo" ).one( "click", function() {
alert( "這個函數(shù)只會執(zhí)行一次" );
});
- 如果該方法的第一個參數(shù)包含多個用空格分隔的事件類型的話,那么每種類型的事件被觸發(fā)時,處理函數(shù)僅會被每個事件類型調(diào)用一次。
$( "#foo" ).one( "click mouseover", function( event ) {
alert( "The " + event.type + " event happened!" );
});
$(ele).trigger()
- 用來觸發(fā)事件
$('#foo').on('click', function() {
alert($(this).text());
});
$('#foo').trigger('click');//相當(dāng)于用戶點擊了該元素
- 若要觸發(fā)通過 jQuery 綁定的事件處理函數(shù),而不觸發(fā)原生的事件,使用
.triggerHandler()來代替。