事件類型
Web瀏覽器可能發(fā)生的事件類型有很多。不同的事件類型具有不同的信息,而“DOM3級事件“規(guī)定了以下幾類事件。
- UI(User Interface,用戶界面)事件,當用戶與頁面上的元素交互時觸發(fā);
- 焦點事件,當元素獲得或失去焦點時觸發(fā);
- 鼠標事件,當用戶通過鼠標在頁面執(zhí)行操作時觸發(fā);
- 滾輪事件,當使用鼠標滾輪(或類似設置)時觸發(fā);
- 文本事件,當在文檔中輸入文本時觸發(fā);
- 鍵盤事件,當用戶通過包租在頁面上執(zhí)行操作時觸發(fā);
- 合成事件,當為IME(Input MethodEditor,輸入法編輯器)輸入字符時觸發(fā);
- 變動(mutation)事件,當?shù)讓覦OM結構發(fā)生變化時觸發(fā);
- 變動名稱事件,當元素或屬性名變動時觸發(fā)。此類事件已經被廢棄,沒有任何瀏覽器實現(xiàn)它們,因此本章不做介紹。
除了這幾類事件之外,HTML5也定義了一組事件,而有此瀏覽器還會在DOM和BOM中實現(xiàn)其他專有事件。這些專有的事件一般都是根據開發(fā)人員需求定制的。沒有什么規(guī)范,因此不同瀏覽器的實現(xiàn)有可能不一致。
DOM2級事件模塊在DOM2級事件模塊基礎上重新這些事件,也添加了一些新事件。包括IE9在內的所有主流瀏覽器都支持DOM2級事件。IE9也支持DOM3級事件。
UI事件
UI事件 批的是那些不一定與用戶操作有關的事件。這些事件在DOM規(guī)范出現(xiàn)之前,都是以這種或那種形式存在的。而在DOM規(guī)范中保留是為了向后兼容。現(xiàn)有的UI的事件如下.
- DOMActivate:表示元素已經被用戶操作(通過鼠標或鍵盤)激活。這個事件在DOM3級事件中被廢棄,但FireFox2+和Chrome支持它。考慮到不同瀏覽器實現(xiàn)的差異 ,不建議使用這個事件。
- load:當頁面完全加載后在window上面觸發(fā),當所有框架都加載完畢時在框架集上面觸發(fā),當圖像加載完畢時在
<img>
元素上面觸發(fā)?;蛘弋斍度氲膬热菁虞d完畢時在元素上面觸發(fā)。 - unload:當頁面完全卸載后在window上面觸發(fā),當所有框架都卸載后在框架集上面觸發(fā),或者當嵌入的內容卸載完畢后在元素上面觸發(fā)。
- abort:在用戶停止下載過程時,如果嵌入的內容沒有加載完,則在元素上面觸發(fā)。
- error: 當發(fā)生JavasScript錯誤時在window上面觸發(fā),當無法加載圖片時在
<img>
元素上面觸發(fā),當元素加載嵌入內容時在元素上面觸發(fā),或者當有一或多個框架無法加載時在框架集上面觸發(fā)。 - select: 當用戶選擇文本框( or )中的一個可多個字符時觸發(fā)。
- resize: 當窗口或框架的大小變化時在window或框架上面觸發(fā);
- scroll:當用戶流動帶有流動條的元素中的內容時,在該元素上面觸發(fā)。元素中包含所加載頁面的流動條。
多數(shù)這些事件都與window對象或表彰控件相關。
除了DOMActivate之外,其他事件都在DOM2級事件中都歸為HTML事件(DOMActivate在DOM2級中仍然屬于UI事件)。在確定瀏覽器是否支持DOM2級事件規(guī)定的HTML事件,可以使用如下代碼:
var isSupported = document.implementation.hasFeature('HTMLEvents',"2.0");
注意,只有根據“DOM2級事件”實現(xiàn)這此事件的瀏覽器才會返回true。而以非標準方式支持這些事件的瀏覽器則會返回false。要確定瀏覽器是否支持“DOM3級事件”定義的事件,可以使用如下代碼:
var isSupported = document.implementation.hasFeature('HTMLEvents',"3.0");
1、load事件
JavaScript中最常用的一個事件就是load。當頁面完全載后(包括所有圖像、JavasScript文件、CSS文件等外部資源),就會觸發(fā)window上面的load事件。有二種定義onload事件處理程序的方式。
第一種方式是使用如下所示的JavasScript代碼:
EventUtil.addHandler(window,'load', function(event){
alert("Loaded");
})
//注意EventUtil對象是自定義封裝的一個對象
這是通過JavasScript來指定事件處理程序的方式,使用了本章前面定義的跨瀏覽器的EventUtil對象。與添加其他事件一樣,這里也給事件處理程序傳入了一個event對象。這個event對象中不包含有關這個事件的任何附加信息,但兼容DOM的瀏覽器中,event.target屬性的值會被設置為document.而IE并不會為這個事件設置srcElement屬性。
第二種指定onload事件處理程序的方式是為元素添加一個onload特性,如下面例子所示:
<body onload="alert('Loaded')">
</body>
一般來說,在window上面發(fā)生的任何事件都可以在元素中通過相應的特性來指定。因為在HTML中無法訪問window元素。初階上,這只是為了保證向后兼容的一種權宜之計,但所有瀏覽器都能很好地支持這種方式。我們建議讀者盡可能使用javascript方式。
根據“DOM2級事件”規(guī)范,應該在document而非window上面觸發(fā)load事件,但是,所有瀏覽器都在window上面實現(xiàn)了該事件,以確保向后兼容。
圖像上面也可以觸發(fā)load事件,無論是在DOM中的圖像還是HTML中的圖像元素。 可以在HTML中為任何圖像指定onload事件處理程序,例如:
<img src="smile.gif" onload="alert('Image loaded')">
這樣,當例子中的圖像加載完畢后就會顯示一個警告框。同樣的功能也可以使用JavasScript來實現(xiàn),例如:
var image = document.getElementById('myImage');
EventUtil.addHandler(img,'load', function(evnet){
event = EventUtil.getEvent(event);
alert(EventUtil.getTarget(event).src);
})
這里,使用JavasScript指定了onload事件處理程序。同時民傳入了event對象,盡管它也不包含什么有用的信息。不過,事件的目標是<img>元素。可以通過src屬性訪問并顯示該 信息。
在創(chuàng)建新的<img>元素時,可以為其指定一個事件處理程序,以便圖像加載完畢后給出提示。此時,最重要在指定src屬性之前先指定事件,如下面的例子所示。
EventUtil.addHandler(window,'load', function(){
var image = document.getElementById('myImage');
EventUtil.addHandler(img,'load', function(){
event = EventUtil.getEvent(event);
alert(EventUtil.getTarget(event).src);
});
document.body.appendChild(image);
image.src = 'smile.gif';
})
在這個例子中,首先為window指定了onload事件處理程序。原因在于,我們是想向DOM中添加一個新元素,所以必須確定頁面已經加載完畢——如果在頁面加載前操作document.body會導致錯誤。然后,創(chuàng)建了一個新的圖像元素,并設置了其onload事件處理程序。最后又將這個圖片添加到頁面中,還設置了它的src屬性。這里有一點需要格外注意:新圖像元素不一定要從添加到文檔后才開始下載,只要設置了src屬性就會開始下載。
同樣的功能也可以通過使用DOM0級的Image對象實現(xiàn)。在DOM出現(xiàn)之前,開發(fā)人員經常使用Image對象在客戶端預先加載圖像??梢韵袷褂?code><img>一樣使用Image對象,只不過無法將其添加到DOM樹中。下面看一個例子:
EventUtil.addHandler(window,'load', function(){
var image = new Image();
EventUtil.addHandler(img,'load', function(){
alert("Image loaded!");
});
image.src = 'smile.gif';
})
在此,我們使用Image構造函數(shù)創(chuàng)建了一個新圖像的實例,然后又為它指定了事件處理程序。有的瀏覽器將Image對象實現(xiàn)了<img>
元素,但并非所有瀏覽器都如此,所以最好將它們區(qū)別對待。
在不屬于DOM文檔的圖像(包括未添加到文檔的元素和Image對象)上觸發(fā)load事件時,IE8及之前版本不會生成event對象。IE9修復了這個問題
還有一些元素也以非標準的方式支持load事件。在ie9+ foxfire Opera Chrome和Safari3+及更高版本中。<script>
元素也會觸發(fā)load事件,以便 開發(fā)人員確定動態(tài)加載的JavasScript文件是否加載完畢。 與圖像不同,只有在設置了<script>
元素的src屬性并將該元素添加到文檔后,才會開始下載JavasScript文件。換句放說,對于元素而言,指定src屬性和指定事件處理程序的先后順序就不重要了,所有代碼展示了怎樣為<script>
元素指定事件處理程序。
EventUtil.addHandler(window,'load', function(){
var script = document.createElement('script');
EventUtil.addHandler(script,'load', function(){
alert('Loaded');
});
script.src = "examplte.js";
document.body.appendChild(script);
})
這個例子使用了跨瀏覽器的EventUtil對象為新創(chuàng)建的<script>元素指定了onload事件處理程序。此時,大多數(shù)瀏覽器中event對象的target屬性引用的都是<script>節(jié)點,而Foxfire3之前的版本中,引用的則是document。IE8及更早版本不支持<script>元素上的load元素。
IE和Opera還支持<link>元素上的load事件,以便開發(fā)人員確定樣式表是否加載完畢。例如:
EventUtil.addHandler(window,'load', function(){
var link = document.createElement('link');
link.type="text/css";
link.rel="stylesheet";
EventUtil.addHandler(link,'load', function(){
alert('css Loaded');
});
link.src = "examplte.css";
document.getElementsByTagName('head')[0].appendChild(link);
})
與<script>
節(jié)點類似,在未指定href屬性并將<link>
元素添加到文檔之前也不會開始下載樣式表。
2、unload事件
與load事件對應的是 unload事件,這個事件在文檔被完全卸載后觸發(fā)。只要用戶從一個頁面切換到另一個頁面,就會發(fā)生unload事件。而利用這個事件最多的情況是清除引用,以避免內在泄漏。與load事件類似,也兩種指定onunload事件處理程序方式。第一種方式是使用JavasScript,如下所示:
EventUtil.addHandler(window,'unload', function(){
alert('Unloaded');
})
此時生成的event對象在兼容DOM的瀏覽器中只包含target屬性(值為document)。IE8及之前版本則為這個事件對象提供了srElement屬性。
指定事件處理程序的第二種方式,民是為<body>元素添加一個特性(與load事件相似),如下面的例子所示:
<body onunload="alert("Unloaded")"></body>
無論使用哪種方式,都要小心編寫onunload事件處理程序中的代碼。既然unload事件是在一切都被卸載后才觸發(fā) ,那么在頁面加載后存在的那些對象,此時就不一定存在了。此時,操作DOM節(jié)點或元素的樣式就會導致錯誤。
根據“DOM2級事件”,應該在<body>元素而非window對象上面觸發(fā)unload事件。不過所有瀏覽器都在window上實現(xiàn)了unload事件,以確保向后兼容。
3、resize事件
當瀏覽器窗口被調整到一個新的高度或寬度時,就會觸發(fā)resize事件。這個事件在window(窗口)上面觸發(fā),因此可以通過JavasScript或者<bdoy>
元素中的onresize特性來指定事件處理程序。如前所述,我們還是推薦使用如下所示的JavasScript方式:
EventUtil.addHandler(window,'resize', function(){
alert('Resizeed');
})
與其他發(fā)生在window上的事件類似,在兼容DOM的瀏覽器中,傳入事件處理程序中event對象有一個target屬性,值為document;而IE8及之前版本則未提供任何屬性。
關于何時會觸發(fā)resize事件,不同瀏覽器有不同的機制。IE Safari Chrome 和 Opera會在瀏覽器窗口變化了1像素時就觸發(fā) resize事件,然后隨著變化不斷重復觸發(fā)。FIrefox則只會在用戶停止調整窗口變化時才會觸發(fā) resize事件。由于 存在這個差別,應該注意不要在這個事件的處理程序中加入大計算的代碼。因為這些代碼有可能被頻繁執(zhí)行,從而導致瀏覽器反應明顯變慢。
瀏覽器窗口最小化或最大化時也會觸發(fā) resize事件
4、scroll事件
雖然scroll事件是在window對象上發(fā)生的,但它實際表示的則是頁面中相應元素的變化。在混雜模式下,可以通過 <body>元素的scrollLeft和scrollTop來監(jiān)控到這一變化;而在標準 模式下,除Safari之外的所有瀏覽器都會通過<html>元素來反映這一變化(Safari仍然基于<body>跟蹤滾動位置),如下面的例子所示:
EventUtil.addHandler(window,'scroll', function(){
if(documnent.compatMode == 'CSS1Compat') {
alert(document.documentElement.scrollTop);
} else {
alert(document.body.scrollTop);
}
})
以上代碼指定的事件處理程序會輸出頁面的垂直滾動位置—–根據呈現(xiàn)模式不同使用了不同的元素。 由于 Safari3.1之前的版本不支持document.compatMode,因此舊版本的瀏覽器就不會滿足第二個條件。
與resize事件類似,scroll事件也會在文檔被滾動期間重復被觸發(fā),所以有必要盡量保持事件處理程序的代碼簡單。