關(guān)于JavaScript與HTML的交互事件
JavaScript和HTML的交互是通過事件實(shí)現(xiàn)的。JavaScript采用異步事件驅(qū)動編程模型,當(dāng)文檔、瀏覽器、元素或與之相關(guān)對象發(fā)生特定事情時(shí),瀏覽器會產(chǎn)生事件。如果JavaScript關(guān)注特定類型事件,那么它可以注冊當(dāng)這類事件發(fā)生時(shí)要調(diào)用的句柄。
事件流
事件流描述的是從頁面中接收事件的順序,比如有兩個嵌套的div,點(diǎn)擊了內(nèi)層的div,這時(shí)候是內(nèi)層的div先出發(fā)click事件還是外層先觸發(fā)?目前主要有三種模型
IE的事件冒泡:事件開始時(shí)由最具體的元素接收,然后逐級向上傳播到較為不具體的元素
Netscape的事件捕獲:不太具體的節(jié)點(diǎn)更早接收事件,而最具體的元素最后接收事件,和事件冒泡相反
DOM事件流:DOM2級事件規(guī)定事件流包括三個階段,事件捕獲階段,處于目標(biāo)階段,事件冒泡階段,首先發(fā)生的是事件捕獲,為截取事件提供機(jī)會,然后是實(shí)際目標(biāo)接收事件,最后是冒泡句階段。
Opera、Firefox、Chrome、Safari都支持DOM事件流,IE不支持事件流,只支持事件冒泡
如有以下html,點(diǎn)擊div區(qū)域
<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Test Page</title>
</head>
<body>
<div>
Click Here</div>
</body>
</html>
事件處理程序(handler)
我們也稱之為事件偵聽器(listener),事件就是用戶或?yàn)g覽器自身執(zhí)行的某種動作。比如click、load、moseover等,都是事件類型(俗稱事件名稱),而響應(yīng)某個事件的方法就叫做事件處理程序或者事件監(jiān)聽器或者事件句柄,事件處理程序名字是:on+事件類型。
了解了這些,我們看看如何給元素添加事件處理程序
HTML事件處理程序元素支持的每個事件都可以使用一個相應(yīng)事件處理程序同名的HTML屬性指定。這個屬性的值應(yīng)該是可以執(zhí)行的JavaScript代碼,我們可以為一個button添加 click事件處理程序
<input type="button" value="Click Here" onclick="alert('Clicked!');" />
在HTML事件處理程序中可以包含要執(zhí)行的具體動作,也可以調(diào)用在頁面其它地方定義的腳本,剛才的例子可以寫成這樣
<input type="button" value="Click Here" onclick="showMessage();" />
<script type="text/javascript">
function showMessage() {
alert('Clicked!');
}
在HTML中指定事件處理程序書寫很方便,但是有兩個缺點(diǎn)。
首先,存在加載順序問題,如果事件處理程序在html代碼之后加載,用戶可能在事件處理程序還未加載完成時(shí)就點(diǎn)擊按鈕之類的觸發(fā)事件,存在時(shí)間差問題。
其次,這樣書寫html代碼和JavaScript代碼緊密耦合,維護(hù)不方便。
JavaScript指定事件處理程序通過JavaScript指定事件處理程序就是把一個方法賦值給一個元素的事件處理程序?qū)傩?。每個元素都有自己的事件處理程序?qū)傩?,這些屬性名稱通常為小寫,如onclick等,將這些屬性的值設(shè)置為一個方法,就可以指定事件處理程序,如下
<input id="btnClick" type="button" value="Click Here" />
<script type="text/javascript">
var btnClick = document.getElementById('btnClick');
btnClick.onclick = function showMessage() {
alert(this.id);
};
</script>
這樣處理,事件處理程序被認(rèn)為是元素的方法,事件處理程序在元素的作用域下運(yùn)行,this就是當(dāng)前元素,所以點(diǎn)擊button結(jié)果是:btnClick
這樣還有一個好處,我們可以刪除事件處理程序,只需把元素的onclick屬性賦為null即可
DOM2事件處理程序DOM2級事件定義了兩個方法用于處理指定和刪除事件處理程序的操作:addEventListener和removeEventListener。所有的DOM節(jié)點(diǎn)都包含這兩個方法,并且它們都接受三個參數(shù):事件類型、事件處理方法、一個布爾值。最后布爾參數(shù)如果是true表示在捕獲階段調(diào)用事件處理程序,如果是false,則是在事件冒泡階段處理。
剛才的例子我們可以這樣寫
<input id="btnClick" type="button" value="Click Here" />
<script type="text/javascript">
var btnClick = document.getElementById('btnClick');
btnClick.addEventListener('click', function() {
alert(this.id);
}, false);
</script>
上面代碼為button添加了click事件的處理程序,在冒泡階段觸發(fā),與上一種方法一樣,這個程序也是在元素的作用域下運(yùn)行,不過有一個好處,我們可以為click事件添加多個處理程序
<input id="btnClick" type="button" value="Click Here" />
<script type="text/javascript">
var btnClick = document.getElementById('btnClick');
btnClick.addEventListener('click', function() {
alert(this.id);
}, false);
btnClick.addEventListener('click', function() {
alert('Hello!');
}, false);
</script>
這樣兩個事件處理程序會在用戶點(diǎn)擊button后按照添加順序依次執(zhí)行。
通過addEventListener添加的事件處理程序只能通過removeEventListener移除,移除時(shí)參數(shù)與添加的時(shí)候相同,這就意味著剛才我們添加的匿名函數(shù)無法移除,因?yàn)槟涿瘮?shù)雖然方法體一樣,但是句柄卻不相同,所以當(dāng)我們有移除事件處理程序的時(shí)候可以這樣寫
<input id="btnClick" type="button" value="Click Here" />
<script type="text/javascript">
var btnClick = document.getElementById('btnClick');
var handler=function() {
alert(this.id);
}
btnClick.addEventListener('click', handler, false);
btnClick.removeEventListener('click', handler, false);
</script>
下面就是老生常談的IE兼容性問題了。。。
IE并不支持addEventListener和removeEventListener方法,而是實(shí)現(xiàn)了兩個類似的方法attachEvent和detachEvent,這兩個方法都接收兩個相同的參數(shù),事件處理程序名稱和事件處理程序方法,由于IE指支持事件冒泡,所以添加的程序會被添加到冒泡階段。
使用attachEvent添加事件處理程序可以如下
<input id="btnClick" type="button" value="Click Here" />
<script type="text/javascript">
var btnClick = document.getElementById('btnClick');
var handler=function() {
alert(this.id);
}
btnClick.attachEvent('onclick' , handler);
</script>
結(jié)果是undefined,很奇怪,一會兒我們會介紹到
使用attachEvent添加的事件處理程序可以通過detachEvent移除,條件也是相同的參數(shù),匿名函數(shù)不能被移除。
<input id="btnClick" type="button" value="Click Here" />
<script type="text/javascript">
var btnClick = document.getElementById('btnClick');
var handler=function() {
alert(this.id);
}
btnClick.attachEvent('onclick', handler);
btnClick.detachEvent('onclick', handler);
</script>
跨瀏覽器的事件處理程序
前面內(nèi)容我們可以看到,在不同的瀏覽器下,添加和移除事件處理程序方式不相同,要想寫出跨瀏覽器的事件處理程序,首先我們要了解不同的瀏覽器下處理事件處理程序的區(qū)別
在添加事件處理程序事addEventListener和attachEvent主要有幾個區(qū)別
1. 參數(shù)個數(shù)不相同,這個最直觀,addEventListener有三個參數(shù),attachEvent只有兩個,attachEvent添加的事件處理程序只能發(fā)生在冒泡階段,addEventListener第三個參數(shù)可以決定添加的事件處理程序是在捕獲階段還是冒泡階段處理(我們一般為了瀏覽器兼容性都設(shè)置為冒泡階段)
2. 第一個參數(shù)意義不同,addEventListener第一個參數(shù)是事件類型(比如click,load),而attachEvent第一個參數(shù)指明的是事件處理函數(shù)名稱(onclick,onload)
3. 事件處理程序的作用域不相同,addEventListener得作用域是元素本身,this是指的觸發(fā)元素,而attachEvent事件處理程序會在全局變量內(nèi)運(yùn)行,this是window,所以剛才例子才會返回undefined,而不是元素id
4. 為一個事件添加多個事件處理程序時(shí),執(zhí)行順序不同,addEventListener添加會按照添加順序執(zhí)行,而attachEvent添加多個事件處理程序時(shí)順序無規(guī)律(添加的方法少的時(shí)候大多是按添加順序的反順序執(zhí)行的,但是添加的多了就無規(guī)律了),所以添加多個的時(shí)候,不依賴執(zhí)行順序的還好,若是依賴于函數(shù)執(zhí)行順序,最好自己處理,不要指望瀏覽器
了解了這四點(diǎn)區(qū)別后我們可以嘗試寫一個瀏覽器兼容性比較好的添加事件處理程序方法
function addEvent(node, type, handler) {
if (!node) return false;
if (node.addEventListener) {
node.addEventListener(type, handler, false);
return true;
}
else if (node.attachEvent) {
node.attachEvent('on' + type, handler, );
return true;
}
return false;
}
這樣,首先我們解決了第一個問題參數(shù)個數(shù)不同,現(xiàn)在三個參數(shù),采用事件冒泡階段觸發(fā),第二個問題也得以解決,如果是IE,我們給type添加上on,第四個問題目前還沒有解決方案,需要用戶自己注意,一般情況下,大家也不會添加很多事件處理程序,試試這個方法感覺很不錯,但是我們沒有解決第三個問題,由于處理程序作用域不同,如果handler內(nèi)有this之類操作,那么就會出錯在IE下,實(shí)際上大多數(shù)函數(shù)都會有this操作。
function addEvent(node, type, handler) {
if (!node) return false;
if (node.addEventListener) {
node.addEventListener(type, handler, false);
return true;
}
else if (node.attachEvent) {
node.attachEvent('on' + type, function() { handler.apply(node); });
return true;
}
return false;
}
這樣處理就可以解決this的問題了,但是新的問題又來了,我們這樣等于添加了一個匿名的事件處理程序,無法用detachEvent取消事件處理程序,有很多解決方案,我們可以借鑒大師的處理方式,jQuery創(chuàng)始人John Resig是這樣做的
function addEvent(node, type, handler) {
if (!node) return false;
if (node.addEventListener) {
node.addEventListener(type, handler, false);
return true;
}
else if (node.attachEvent) {
node['e' + type + handler] = handler;
node[type + handler] = function() {
node['e' + type + handler](window.event);
};
node.attachEvent('on' + type, node[type + handler]);
return true;
}
return false;
}
在取消事件處理程序的時(shí)候
function removeEvent(node, type, handler) {
if (!node) return false;
if (node.removeEventListener) {
node.removeEventListener(type, handler, false);
return true;
}
else if (node.detachEvent) {
node.detachEvent('on' + type, node[type + handler]);
node[type + handler] = null;
}
return false;
}
John Resig很巧妙地利用了閉包,看起來很不錯。
事件對象
在觸發(fā)DOM上的某個事件的時(shí)候會產(chǎn)生一個事件對象event,這個對象包含著所有與事件有關(guān)的信息,包括產(chǎn)生事件的元素、事件類型等相關(guān)信息。所有瀏覽都支持event對象,但支持方式不同。
DOM中的事件對象兼容DOM的瀏覽器會產(chǎn)生一個event對象傳入事件處理程序中。應(yīng)用一下剛才我們寫的addEvent方法
var btnClick = document.getElementById('btnClick');
addEvent(btnClick, 'click', handler);
點(diǎn)擊button的時(shí)候我們可以看到彈出內(nèi)容是click的彈窗
event對象包含與創(chuàng)建它的特定事件有關(guān)的屬性和方法,觸發(fā)事件的類型不同,可用的屬性和方法也不同,但是所有事件都會包含
屬性/方法 |
類型 |
讀/寫 |
說明 |
bubbles | Boolean | 只讀 | 事件是否冒泡 |
cancelable | Boolean | 只讀 | 是否可以取消事件的默認(rèn)行為 |
currentTarget | Element | 只讀 | 事件處理程序當(dāng)前處理元素 |
detail | Integer | 只讀 | 與事件相關(guān)細(xì)節(jié)信息 |
eventPhase | Integer | 只讀 | 事件處理程序階段:1 捕獲階段,2 處于目標(biāo)階段,3 冒泡階段 |
preventDefault() | Function | 只讀 | 取消事件默認(rèn)行為 |
stopPropagation() | Function | 只讀 | 取消事件進(jìn)一步捕獲或冒泡 |
target | Element | 只讀 | 事件的目標(biāo)元素 |
type | String | 只讀 | 被觸發(fā)的事件類型 |
view | AbstractView | 只讀 | 與事件關(guān)聯(lián)的抽象視圖,等同于發(fā)生事件的window對象 |
要阻止事件的默認(rèn)行為,可以使用preventDefault()方法,前提是cancelable值為true,比如我們可以阻止鏈接導(dǎo)航這一默認(rèn)行為
document.getElementsByTagName('a').onclick = function (e) {
e.preventDefault();
}
stopPaopagation()方法可以停止事件在DOM層次的傳播,即取消進(jìn)一步的事件捕獲或冒泡。我們可以在button的事件處理程序中調(diào)用stopPropagation()從而避免注冊在body上的事件發(fā)生
var handler = function (e) {
alert(e.type);
e.stopPropagation();
}
addEvent(document.body, 'click', function () { alert('Clicked body')});
var btnClick = document.getElementById('btnClick');
addEvent(btnClick, 'click', handler);
若是注釋掉e.stopPropagation(); 在點(diǎn)擊button的時(shí)候,由于事件冒泡,body的click事件也會觸發(fā),但是調(diào)用這句后,事件會停止傳播。
IE中的事件對象訪問IE中的event對象有幾種不同的方式,取決于指定事件處理程序的方法。直接為DOM元素添加事件處理程序時(shí),event對象作為window對象的一個屬性存在
var handler = function () {
var e = window.event;
alert(e.type);
}
var btnClick = document.getElementById('btnClick');
btnClick.onclick = handler;
我們通過window.event取得了event對象,并檢測到了其類型,可是如果事件處理程序是通過attachEvent添加的,那么就會有一個event對象被傳入事件處理程序中
var handler = function (e) {
alert(e.type);
}
var btnClick = document.getElementById('btnClick');
attachEvent(btnClick, handler);
當(dāng)然這時(shí)候也可以通過window對象訪問event,方便起見,我們一般會傳入event對象,IE中所有的事件都包含以下屬性方法
屬性/方法 |
類型 |
讀/寫 |
說明 |
cancelBulle | Boolean | 讀/寫 | 默認(rèn)為false,設(shè)置為true后可以取消事件冒泡 |
returnValue | Boolean | 讀/寫 | 默認(rèn)為true,設(shè)為false可以取消事件默認(rèn)行為 |
srcElement | Element | 只讀 | 事件的目標(biāo)元素 |
type | String | 只讀 | 被觸發(fā)的事件類型 |
function getEvent(e) {
return e || window.event;
}
function getTarget(e) {
return e.target || e.scrElement;
}
function preventDefault(e) {
if (e.preventDefault)
e.preventDefault();
else
e.returnValue = false;
}
function stopPropagation(e) {
if (e.stopPropagation)
e.stopPropagation();
else
e.cancelBubble = true;
}
常用HTML事件
有一些HTML事件我們會經(jīng)常用到,這些事件不一定與用戶操作有關(guān),這里只是簡單提及,詳細(xì)用法大家就得百度谷歌了
1.load:當(dāng)頁面完全加載后在window上觸發(fā),當(dāng)圖像加載完成后在img元素上觸發(fā),或當(dāng)嵌入內(nèi)容加載完成時(shí),在object元素上觸發(fā)
2.unload:頁面完全卸載后在window上觸發(fā),或嵌入內(nèi)容卸載后在object元素觸發(fā)
3.select:用戶選擇文本框中的字符時(shí)觸發(fā)
4.change:文本框焦點(diǎn)變化后其值改變時(shí)觸發(fā)
5.submit:用戶提交表單的時(shí)候觸發(fā)
6.resize:窗口或框架大小變化的時(shí)候在window上觸發(fā)
7.scrool:用戶滾動帶滾動條的元素時(shí),在該元素上觸發(fā)
8.focus:頁面或元素獲得焦點(diǎn)時(shí)在window及相應(yīng)元素上觸發(fā)
9.blur:頁面或元素失去焦點(diǎn)時(shí)在window及相應(yīng)元素上觸發(fā)
10.beforeunload:頁面卸載前在window上觸發(fā)
11.mousewheel:不算HTML的,當(dāng)用戶通過鼠標(biāo)滾輪與頁面交互,在垂直方向滾動頁面時(shí)觸發(fā)
- JS html事件冒泡和事件捕獲操作示例
- js監(jiān)聽html頁面的上下滾動事件方法
- JS檢測頁面中哪個HTML標(biāo)簽觸發(fā)點(diǎn)擊事件的方法
- js 動態(tài)生成html 觸發(fā)事件傳參字符轉(zhuǎn)義的實(shí)例
- javascript 鍵盤事件總結(jié) 推薦
- js監(jiān)聽鍵盤事件示例代碼
- js和jquery實(shí)現(xiàn)監(jiān)聽鍵盤事件示例代碼
- js捕捉鍵盤事件和按鍵鍵值的方法
- JavaScript常見鼠標(biāo)事件與用法分析
- 關(guān)于js中的鼠標(biāo)事件總結(jié)
- javascript 鼠標(biāo)事件總結(jié)
- JavaScript(js)處理的HTML事件、鍵盤事件、鼠標(biāo)事件簡單示例
相關(guān)文章
JavaScript onkeydown事件入門實(shí)例(鍵盤某個按鍵被按下)
這篇文章主要介紹了JavaScript onkeydown事件入門實(shí)例,onkeydown事件捕捉鍵盤上某個按鍵被按下的情況,需要的朋友可以參考下2014-10-10大型JavaScript應(yīng)用程序架構(gòu)設(shè)計(jì)模式
11月中旬在倫敦舉行的jQuery Summit頂級大會上有個session講的是大型JavaScript應(yīng)用程序架構(gòu),看完P(guān)PT以后覺得甚是不錯,于是整理一下發(fā)給大家共勉。2016-06-06簡介JavaScript中POSITIVE_INFINITY值的使用
這篇文章主要介紹了簡介JavaScript中POSITIVE_INFINITY值的使用,是JS入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-06-06javascript的數(shù)據(jù)類型、字面量、變量介紹
javascript的數(shù)據(jù)類型、字面量、變量介紹,學(xué)習(xí)js的朋友可以參考下2012-05-05淺談JavaScript中的apply/call/bind和this的使用
apply/call/bind三者的聯(lián)系就在于,都可以用來改變函數(shù)中 this 指向的值,且第一個參數(shù)為要指向的 this 的值,apply的第二個參數(shù)(或 bind 與 call 的不定參數(shù))為要傳入的參數(shù)。這就不得不提及 javascript 中函數(shù)的 this 的指向了。下面我們來簡單探討下2017-02-02Javascript學(xué)習(xí)筆記之函數(shù)篇(五) : 構(gòu)造函數(shù)
javascript本身是沒有類的概念,只有函數(shù)的概念。javascript的類實(shí)際上也是一個javascript的函數(shù),在這個特殊的函數(shù)中間可以包含變量和其他javascript函數(shù)的引用。那么這個特殊的函數(shù)本身就是javascript所謂類的構(gòu)造函數(shù)。2014-11-11Web Inspector:關(guān)于在 Sublime Text 中調(diào)試Js的介紹
本篇文章小編將為大家介紹,Web Inspector:關(guān)于在 Sublime Text 中調(diào)試Js的介紹。需要的朋友可以參考一下2013-04-04