搜尋
首頁web前端js教程javascript事件绑定学习要点_基础知识

事件绑定分为两种:一种是传统事件绑定(内联模型,脚本模型),一种是现代事件绑定(DOM2级模型)。现代事件绑定在传统绑定上提供了更强大更方便的功能。

一 传统事件绑定的问题

传统事件绑定中的内联模型不做讨论,基本很少去用。先来看一下脚本模型,脚本模型将一个函数赋值给一个事件处理函数。传统绑定如:

window.onload=function(){
 var box=document.getElementById('box');
 box.onclick = function(){
  alert('Lee');
 };
};



问题一:一个事件处理函数触发两次事件

如果一个页面有两个或者多个js,并且第一个js是第一个程序开发的,第二个js是第二个程序员开发的。第一个window.onload被覆盖了,如

window.onload=function(){
 alert('Lee');
};

window.onload=function(){
 alert('Mr.lee');
} 

结果只是打印了 Mr.lee

其实是有办法解决这个问题的,看下面这两种形式。
a:

alert(window.onload);//一开始没有注册window.onload,那么就是null

window.onload=function(){
 alert('Lee');
};

alert(window.onload);//如果已经有window.onload,打印的是函数function

window.onload=function(){
 alert('Mr.lee');
} 

b:

alert(typeof window.onload);//一开始没有window.onolad,旧版火狐显示undefined,新版显示object,

window.onload=function(){
 alert('Lee');
};

alert(typeof window.onload);//如果已经有window.onload,所有浏览器都会显示function

window.onload=function(){
 alert('Mr.lee');
}

所以解决办法有了。

 window.onload=function(){
 alert('Lee');
};

if(typeof window.onload=='function'){
 var saved=null;//保存上一个事件对象
 saved=window.onload;
}

//saved 就是window.onload,saved()相当于window.onload(),但是window.onload()不能执行的
//所以saved()相当于window.onload=function(){}

window.onload=function(){
 if(saved){
  saved();//执行上一个事件 window.onload=function(){}
 }
 alert('Mr.lee'); //执行本事件
}

问题二:事件切换器
切换一个id为box的div,让里面的背景red与blue直接切换,并且切换之前弹框一次,如:

window.onload=function(){
 var box=document.getElementById('box');
 box.className="red";
 box.onclick=function(){
  alert('Lee'); //只执行了一次
  blue.call(this);//通过匿名函数执行某一函数,那么里面的this就是代表的window,所以可以通过call传递
 };
}

function blue(){
 this.className="blue";
 this.onclick=red;
 
}

function red(){
 this.className="red";
 this.onclick=blue;
}

上面的代码虽然实现了切换功能,但是弹框只执行了一次。

//添加事件函数
//obj相当于window
//type相当于onload
//fn相当于function(){}
function addEvent(obj,type,fn){
 //用于保存上一个事件
 var saved=null;
 if(typeof obj['on'+type]=='function'){
  saved=obj['on'+type];//保存上一个事件
 }
 obj['on'+type]=function(){
  if(saved){
   saved();
  }
  fn.call(this);
 }
 
}
addEvent(window,'load',function(){
 var box=document.getElementById("box");
 //addEvent(box,'click',function(){ //目的达到,每次都执行了,没有被覆盖
 // alert('ss');
 //});
 addEvent(box,'click',blue);
});

function red(){
 this.className="red";
 addEvent(box,'click',blue);
}

function blue(){
 this.className="blue";
 addEvent(box,'click',red);
}

//当不停的切换的时候,浏览器突然卡死,并且报错:too much recursion,太多的递归
//因为积累了太多的保存的事件
//解决方案,就是用完的事件,就立刻移除掉

按照上面的代码出现了注释中的错误,解决的办法如下:

//添加事件函数
//obj相当于window
//type相当于onload
//fn相当于function(){}
function addEvent(obj,type,fn){
 //用于保存上一个事件
 var saved=null;
 if(typeof obj['on'+type]=='function'){
  saved=obj['on'+type];//保存上一个事件
 }
 obj['on'+type]=function(){
  if(saved){
   saved();
  }
  fn.call(this);
 }
 
}


//当不停的切换的时候,浏览器突然卡死,并且报错:too much recursion,太多的递归
//因为积累了太多的保存的事件
//解决方案,就是用完的事件,就立刻移除掉


//移除事件函数
function removeEvent(obj,type){
 if(obj['on'+type]){
  obj['on'+type]=null;
 }
}


addEvent(window,'load',function(){
 var box=document.getElementById("box");
 //addEvent(box,'click',function(){ //目的达到,每次都执行了,没有被覆盖
 // alert('ss');
 //});
 addEvent(box,'click',blue);
});

function red(){
 this.className="red";
 removeEvent(this,'click');
 addEvent(box,'click',blue);
}

function blue(){
 this.className="blue";
 removeEvent(this,'click');
 addEvent(box,'click',red);
}

二 W3C事件处理函数
addEventListener()与removeEventListener()
W3C事件处理函数两个,addEventListener()与removeEventListener()。

//W3C自带的两个添加事件和删除事件
1.覆盖问题,解决

window.addEventListener('load',function(){
 alert('Lee');
},false);

window.addEventListener('load',function(){
 alert('Mr.Lee');
},false);

window.addEventListener('load',function(){
 alert('Mrs.Lee');
},false);

2.相同函数屏蔽的问题,解决

window.addEventListener('load',init,false);
window.addEventListener('load',init,false);
window.addEventListener('load',init,false);
function init(){
 alert('Lee');
}

3.是否可以传递this,解决
例子1:

window.addEventListener('load',function(){
 var box=document.getElementById('box');
 box.addEventListener('click',function(){
  alert(this);
 },false);
},false);

例子2:

window.addEventListener('load',function(){
 var box=document.getElementById('box');
 box.addEventListener('click',blue,false);
},false);

function red(){
 this.className="red";
 this.removeEventListener('click',red,false);
 this.addEventListener('click',blue,false);
}

function blue(){
 this.className="blue";
 this.removeEventListener('click',blue,false);
 this.addEventListener('click',red,false);
}

4.添加一个额外的方法,会不会被覆盖,或者只能执行一次,解决

window.addEventListener('load',function(){
 var box=document.getElementById('box');
 box.addEventListener('click',function(){
  alert('Lee');
 },false);
 box.addEventListener('click',blue,false);
},false);

综上所述:W3C是比较完美的解决了这些问题,非常好用,但是IE8和之前的浏览器并不支持,而是采用了自己的事件,当然IE9已经完全支持了W3C的这两个事件处理函数。

W3C可以设置冒泡和捕获方式。

支持W3C标准的浏览器在添加事件时用addEventListener(event,fn,useCapture)方法,基中第3个参数useCapture是一个Boolean值,用来设置事件是在事件捕获时执行,还是事件冒泡时执行。而不兼容W3C的浏览器(IE)用attachEvent()方法,此方法没有相关设置,不过IE的事件模型默认是在事件冒泡时执行的,也就是在useCapture等于false的时候执行,所以把在处理事件时把useCapture设置为false是比较安全,也实现兼容浏览器的效果。

事件捕获阶段:事件从最上一级标签开始往下查找,直到捕获到事件目标(target)。
事件冒泡阶段:事件从事件目标(target)开始,往上冒泡直到页面的最上一级标签。
事件的传播是可以阻止的:
在W3c中,使用stopPropagation()方法
在IE下设置cancelBubble = true;

三.IE事件处理函数

attachEvent()和detachEvent()
IE实现了与DOM中类似的两个方法:attachEvent()和detachEvent()。这两个方法接受相同的参数:事件名称和函数。

在使用这两组函数的时候,先把区别说一下:1.IE不支持捕获,只支持冒泡;2.IE添加事件不能屏蔽重复的函数;3.IE中的this指向的是window而不是DOM对象。4.在传统事件上,IE是无法接受到event对象的,但使用了attchEvent却可以,但有些区别。

1.覆盖问题,解决了,但有不同,结果是Mrs.Lee,Mr.Lee,最后是Lee

window.attachEvent('onload',function(){
 alert('Lee');
});

window.attachEvent('onload',function(){
 alert('Mr.Lee');
});
window.attachEvent('onload',function(){
 alert('Mrs.Lee');
});

2.相同函数屏蔽的问题,未解决。

window.attachEvent('onload',init);
window.attachEvent('onload',init);

function init(){
 alert('Lee');
}

3.是否可以传递this,不能,this指的是window。需要用call方法。

window.attachEvent('onload',function(){
 var box=document.getElementById('box');
 box.attachEvent('onclick',function(){
  //alert(this===box);
  alert(this===window); //true
 });
});

下面还有办法就是通过window.event.srcElement。代码如下:

window.attachEvent('onload',function(){
 var box=document.getElementById('box');
 box.attachEvent('onclick',blue);
});

function red(){
 var that=window.event.srcElement;
 that.className="red";
 that.detachEvent('onclick',red);
 that.attachEvent('onclick',blue);
}

function blue(){
 var that=window.event.srcElement;
 that.className="blue";
 that.detachEvent('onclick',blue);
 that.attachEvent('onclick',red);
}

4.添加一个额外的方法,会不会被覆盖,或者只能执行一次,解决。

在传统绑定上,IE是无法像W3C那样通过传参接受event对象,但是使用attachEvent()却可以。

 window.attachEvent('onload',function(){
 var box=document.getElementById('box');
 box.onclick=function(evt){ //传统方法IE无法通过参数获取evt
  alert(evt);//undefined
 }
 box.attachEvent('onclick',function(evt){
  alert(evt);//object
  alert(evt.type);//click
  alert(evt.srcElement.tagName);//DIV
  alert(window.event.srcElement.tagName);//DIV
 });
});

跨浏览器的兼容

跨浏览器添加事件

function addEvent(obj,type,fn){
 if(obj.addEventListener){
  obj.addEventListener(type,fn,false);
 }else if(obj.attachEvent){
  obj.attachEvent('on'+type,fn);
 }
}

跨浏览器移除事件

function removeEvent(obj,type,fn){
 if(obj.removeEventListener){
  obj.removeEventListener(type,fn,false);
 }else if(obj.detachEvent){
  obj.detachEvent('on'+type,fn);
 }
}

跨浏览器获取目标对象

function getTarget(evt){
 if(evt.target){
  return evt.target;
 }else if(window.event.srcElement){
  return window.event.srcElement;
 }
}

调用方式:

addEvent(window,'load',function(){
 var box=document.getElementById('box');
 addEvent(box,'click',blue);
});


function red(evt){
 var that=getTarget(evt);
 that.className="red";
 removeEvent(that,'click',red);
 addEvent(that,'click',blue);
}

function blue(evt){
 var that=getTarget(evt);
 that.className="blue";
 removeEvent(that,'click',blue);
 addEvent(that,'click',red);
}

四.事件对象的其他补充

relatedTarget事件

w3c中的一个relatedTarget事件。
例如:

addEvent(window,'load',function(){
 var box=document.getElementById('box');
 addEvent(box,'mouseover',function(evt){
  alert(evt.relatedTarget); //得到移入box最近的那个DOM对象
 });
 
 addEvent(box,'mouseout',function(evt){
  alert(evt.relatedTarget); //从box移出最近的那个DOM对象
 });
});

IE提供了两组分别用于移入移出的属性fromElement和toElement,分别对应mouseover和mouseout。

addEvent(window,'load',function(){
 var box=document.getElementById('box');
 addEvent(box,'mouseover',function(){
  alert(window.event.fromElement.tagName); //得到移入box最近的那个DOM对象
 });
 
 addEvent(box,'mouseout',function(){
  alert(window.event.toElement.tagName); //从box移出最近的那个DOM对象
 });
});

PS:fromElement和toElement如果分别对应相反的鼠标事件,没有任何意义。

剩下要做的就是跨浏览器兼容操作:

function getTarget(evt){
 var e=evt || window.event;
 if(e.srcElment){ //IE
  if(e.type=='mouseover'){
   return e.fromElement.tagName;
  }else if(e.type="mouseout"){
   return e.toElement.tagName;
  }
 }else if(e.relatedTarget){ //w3c
  return e.relatedTarget;
 }
}

屏蔽跳转操作

取消事件的默认行为有一种不规范的做法,就是返回false。

link.onclick=function(){
 alert('Lee');
 return false;
}

PS:虽然return false;可以实现这个功能,但是有漏洞。
第一:必须写到最后,这样导致中奖的代码执行后,有可能执行不到return false;
第二:return false 写到最前那么之后的自定义操作就失效了。
所以最好的办法应该是在最前面就阻止默认行为,并且后面的代码还可以执行。

link.onclick=function(evt){
 evt.preventDefault;//w3c,阻止默认行为
 alert('Lee');
}

link.onclick=function(evt){
 window.event.returnValue=false;//IE,阻止默认行为
 alert('Lee');
}

那么跨浏览器的兼容:

function preDef(evt){
 var e=evt || window.event;
 if(e.preventDefault){
  e.preventDefault();
 }else{
  e.returnValue=false;
 }
}

右键菜单contextmenu
兼容:

function preDef(evt){
 var e=evt || window.event;
 if(e.preventDefault){
  e.preventDefault();
 }else{
  e.returnValue=false;
 }
}

addEvent(window,"load",function(){
 var body=document.getElementsByTagName('body')[0];
 addEvent(body,'contextmenu',function(evt){
  preDef(evt);
 })
});

PS:contextmenu事件很常用,这直接导致浏览器兼容性较为稳定。

卸载前事件:beforeunload
这个事件可以帮助在离开本页的时候给出相应的提示,“离开”或者“返回”操作。

addEvent(window,'beforeonload',function(){
 preDef(evt);
});

鼠标滚轮(mousewheel)和DOMMouseScroll
用于获取鼠标上下滚轮的距离

addEvent(document,'mousewheel',function(evt){ //非火狐
 alert(getWD(evt));
});

addEvent(document,'DOMMouseScroll',function(evt){ //火狐
 alert(getWD(evt));
});

function getWD(evt){
 var e=evt|| window.event;
 if(e.wheelDelta){
  return e.wheelDelta;
 }else if(e.detail){ //火狐
  return -evt.detail*30;
 }
}

PS:通过浏览器检测可以确定火狐只执行DOMMouseScroll。

DOMContentLoaded事件和readystatechange事件

DOMContentLoaded事件和readystatechange事件,有关DOM加载方面的事件。

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
Python vs. JavaScript:學習曲線和易用性Python vs. JavaScript:學習曲線和易用性Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python vs. JavaScript:社區,圖書館和資源Python vs. JavaScript:社區,圖書館和資源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C到JavaScript:所有工作方式從C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

如何使用Next.js(前端集成)構建多租戶SaaS應用程序如何使用Next.js(前端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:22 AM

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript:探索網絡語言的多功能性JavaScript:探索網絡語言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器