一:事件流
事件流描述的是從頁面中接收事件的順序,IE和Netscape提出來差不多完全相反的事件流的概念,IE事件流是事件冒泡流,Netscape事件流是事件捕獲流。
事件冒泡
IE的事件流叫做事件冒泡,即事件開始時由最具體的元素(文件中巢狀最深的那個節點)接收,然後逐級向上(一直到文件);如下程式碼:
1 2 3 4 5 |
<div id = "div"> <span id="span"> <a id="aTag">事件測試</a> </span> </div> |
JS如下:
1 2 3 4 5 6 7 8 9 10 11 12 |
document.getElementById("aTag").addEventListener('click',aTag); document.getElementById("span").addEventListener('click',span); document.getElementById("div").addEventListener('click',div); function aTag(e) { alert("點選的是a標籤"); } function span(e) { alert("點選的是span標籤"); } function div(e) { alert("點選的是div標籤"); } |
當單擊 “事件測試”文字後,那麼click事件會按照如下順序傳播;
1)先列印出:點選的是a標籤
2) 再列印出:點選的是span標籤
3) 最後列印出:點選的是div標籤
4) 最後肯定是document文件。
所有現代瀏覽器都支援事件冒泡。
事件捕獲:
事件捕獲與事件冒泡事件流正好相反的順序,事件捕獲的事件流是最外層逐級向內傳播,也就是先document,然後逐級div標籤 , span標籤 , a標籤;
上面的JS程式碼改成如下:
1 2 3 |
document.getElementById("div").addEventListener('click',div,true); document.getElementById("aTag").addEventListener('click',aTag,true); document.getElementById("span").addEventListener('click',span,true); |
第三個引數設定為true,即為捕獲事件,預設為false;否則的話,事件流還是和上面的一樣,因為不管是在IE還是標準瀏覽器下,事件冒泡瀏覽器都支援的。
DOM事件流
DOM2級事件規定的事件流包括三個階段,分別是:事件捕獲階段,處於目標階段和事件冒泡階段。示意圖就不畫了,具體的可以看看書。
DOM0級事件處理程式
如下程式碼是DOM0級事件處理程式:
1 2 3 4 |
var btn = document.getElementById("btn"); btn.onclick = function(){ alert("Clicked"); }; |
使用DOM0級方法指定的事件處理程式被認為是元素的方法,處理程式是在元素的作用域進行的,程式中this是引用的是當前元素。
1 2 3 4 5 |
<div id="btn">btn</div> var btn = document.getElementById("btn"); btn.onclick = function(){ alert(this.id); // 彈出btn } |
單擊元素btn後,通過this.id取得元素的屬性id,還可以通過this訪問元素的任何屬性和方法,以這種方式新增的事情處理程式在事件流的冒泡階段處理。
也可以刪除通過DOM0級方法指定的事件處理程式,只要將事件處理程式的屬性值設定為null即可。
btn.onclick = null; // 刪除事件處理程式;
如下JS程式碼改成如下:
1 2 3 4 5 |
var btn = document.getElementById("btn"); btn.onclick = function(){ alert(this.id); } btn.onclick = null; |
再單擊btn後,沒有任何反應;
DOM2級事件處理程式
DOM2級事件定義了2個方法,用於處理指定和刪除事件處理程式的操作;
addEventListener()和removeEventListener()。所有DOM節點都包含這兩個方法,他們包含三個引數,第一個引數為事件型別;第二個引數為事件函式,第三個引數為布林值,如果是true的話,說明是事件流是捕獲事件,如果是false的話,那麼事件流是冒泡事件;
比如如上的btn程式碼,我們改成如下:
1 2 3 4 |
var btn = document.getElementById("btn"); btn.addEventListener('click',function(e){ alert(this.id); },false); |
上面的點選事件是在冒泡階段被觸發,與DOM0級方法一樣,這裡新增的事件處理程式也是在其依副的元素作用域中執行,使用DOM2級新增事件處理程式的好處是可以新增多個事件處理程式,如下程式碼:
1 2 3 4 5 6 7 |
var btn = document.getElementById("btn"); btn.addEventListener('click',function(e){ alert(this.id); },false); btn.addEventListener('click',function(e){ alert("我是來測試的"); },false); |
上面的程式碼被彈出2次對話方塊,而在DOM0級是不可以的;它永遠是執行最後一次的。
addEventListener新增的事件只能使用removeEventListener來刪除相對應的事件,那麼如上的JS不能按照上面的方式來編寫哦!需要給定義一個函式;如下:
1 2 3 4 |
btn.addEventListener('click',handler,false); function handler(e){ alert(this.id); } |
可以使用如下方式對click事件刪除;如下程式碼:
btn.removeEventListener(‘click’,handler);
上面的是在標準瀏覽器下處理的事件,下面我們來看看在IE下處理的事件;
IE事件處理的程式
IE實現了與DOM類似的2個方法,分別是attachEvent()和detachEvent(),這兩個方法只接受2個引數,第一個引數是事件名稱,第二個引數是要處理的函式;由於IE8及更早版本只支援事件冒泡,所以通過attachEvent()新增的事件處理程式會被新增到冒泡階段;
下面是IE事件處理程式的程式碼如下:
1 2 3 4 |
btn.attachEvent('onclick',handler); function handler(e){ alert(this); // window } |
注意:attachEvent的事件名稱是onclick,而addEventListener的事件名稱是click,且IE中使用的attachEvent()與使用DOM0級方法的的主要區別在於事件處理程式的作用域,在使用dom0級情況下,事件處理程式在其所屬元素的作用域內執行,在使用attachEvent()方法的情況下,事件處理程式在全域性作用域下執行,其中的this等於window。
與addEventListener一樣,attachEvent也可以註冊多個點選click事件,如下程式碼:
1 2 3 4 5 6 |
btn.attachEvent('onclick',function(e){ alert("1"); }); btn.attachEvent('onclick',function(e){ alert("2"); }); |
但是與Dom方法不同的是,這些事件處理程式不是以新增他們的順序執行,而是以相反的順序觸發,比如如上程式碼,會先彈出2,然後彈出1對話方塊;
使用attachEvent註冊的事件只能使用detachEvent()方法來移除;
下面我們可以來編寫跨瀏覽器的事件處理程式;程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
var EventUtil = { addHandler: function(element,type,handler) { if(element.addEventListener) { element.addEventListener(type,handler,false); }else if(element.attachEvent) { element.attachEvent("on"+type,handler); }else { element["on" +type] = handler; } }, removeHandler: function(element,type,handler){ if(element.removeEventListener) { element.removeEventListener(type,handler,false); }else if(element.detachEvent) { element.detachEvent("on"+type,handler); }else { element["on" +type] = null; } } }; |
下面我們可以使用這個封裝的函式程式碼來測試之前的程式碼了,程式碼改成如下所示:
1 2 3 4 |
function handler(){ alert(1); } EventUtil.addHandler(btn,'click',handler); |
在IE或者標準瀏覽器下都會彈出1;如果我們需要移除click事件的話,我們可以使用如下程式碼:
EventUtil.removeHandler(btn,’click’,handler);
然後在標準瀏覽器下或者IE下點選btn元素都沒有反應;
事件物件:
在觸發DOM上的某個事件時,會產生一個事件物件event,這個物件中包含著所有與事件有關的資訊;包括導致事件的元素,事件的型別以及其他與特定事件相關的資訊。我們來看看dom0級和dom2級的事件物件Event;
比如如下程式碼:
1 2 3 4 |
var btn = document.getElementById("btn"); btn.onclick = function(e){ console.log(e); } |
列印如下:
下面我們來看看最基本的成員的含義吧;如下:
屬性/方法 | 型別 | 含義 |
bubbles | Boolean | 事件是否冒泡 |
cancelable | Boolean | 是否可以取消事件的預設行為 |
currentTarget | Boolean | 事件處理程式當前正在處理事件的那個元素 |
defaultPrevented | Boolean | 為true 表示已經呼叫了preventDefault() |
detail | Integer | 與事件相關的細節資訊 |
eventPhase | Integer | 呼叫事件處理程式的階段:1表示捕獲階段,2表示“處於目標”,3表示冒泡階段 |
preventDefault() | Function | 取消事件的預設行為。如果cancelable是true,則可以使用這個方法 |
stopImmediatePropagation() | Function | 取消事件的進一步捕獲或冒泡,同時阻止任何事件處理程式被呼叫 |
stopPropagation() | Function | 取消事件的進一步捕獲或冒泡。如果bubbles為true,則可以使用這個方法 |
target | Element | 事件的目標 |
type | String | 被觸發的事件的型別 |
view | AbstractView | 與事件關聯的抽象檢視。等同於發生事件的window物件 |
理解currentTarget與target
在事件處理程式內部,this始終等於currentTarget值,即currentTarget是指當前被觸發或者說正在處理事件的那個元素,而target是指當前的目標元素;比如如下程式碼,對btn按鈕觸發點選事件,那麼e.currentTraget指向了this,e.target也指向了this;如下程式碼:
1 2 3 4 5 |
var btn = document.getElementById("btn"); btn.onclick = function(e){ console.log(e.currentTarget == this); // true console.log(e.target == this); // true } |
但是如果我對document.body觸發點選的話,那麼e.currentTarget就指向了document.body了,那麼e.target 指向與 btn那個元素了,如下程式碼:
1 2 3 4 5 |
document.body.onclick = function(e){ console.log(e.currentTarget === document.body); // true console.log(document.body === this); // true console.log(e.target === document.getElementById("btn")); //true }; |
現在應該能理解currentTarget與target的區別吧!currentTarget就是指被點選的那個元素,但是target是當前點選的目標元素,如上程式碼,由於btn上並沒有註冊事件,結果click事件就冒泡到了document.body,在那裡事件才得到了處理。
理解標準瀏覽器下的事件物件與IE下的事件物件
標準瀏覽器下的事件物件是event,比如btn點選後;如下程式碼:
1 2 3 4 5 6 7 8 9 10 |
var btn = document.getElementById("btn"); btn.onclick = function(){ console.log(event); //標準瀏覽器下列印事件物件 console.log(event.type);//'click' } btn.onclick = function(){ // IE下列印的事件物件window.event console.log(window.event); console.log(window.event.type); // 'click' } |
上面的寫法是在DOM0級上註冊事件,如果我們在Dom2級上註冊事件的話,那麼就會有一個事件物件event作為引數傳入事件到函式中,如下:
1 2 3 4 |
var btn = document.getElementById("btn"); EventUtil.addHandler(btn,'click',function(e){ console.log(e); }); |
理解特定事件的預設行為事件
在標準瀏覽器下,在阻止特定事件的預設行為,可以使用preventDefault()方法,比如如下,我點選一個連線,按道理是開啟一個新連線視窗,但是我使用preventDefault()方法可以阻止預設行為,阻止開啟新視窗;如下程式碼:
1 2 3 4 5 6 7 |
HTML:<a href="http://www.baidu.com" id="alink" target="_blank">開啟新連線</a> JS如下: var alink = document.getElementById("alink"); alink.onclick = function(e){ console.log(e) e.preventDefault(); } |
就可以阻止頁面進行跳轉了~ 這是標準瀏覽器下處理方式,下面我們來看看IE是如何處理預設事件的;
IE下使用returnValue屬性來取消給定事件的預設行為,只要將returnValue屬性值設定為false即可,就可以阻止瀏覽器的預設行為,如下程式碼:
1 2 3 4 |
alink.onclick = function(){ console.log(window.event) window.event.returnValue = false; } |
標準瀏覽器下與IE下的事件目標的區別
標準瀏覽器下使用e.target來指定當前被點選的目標元素,如下程式碼所示:
1 2 3 4 5 |
var btn = document.getElementById("btn"); btn.onclick = function(){ console.log(event); console.log(event.target); // 列印事件目標元素 } |
IE下是使用event.srcElement來指定當前的目標元素,如下程式碼:
1 2 3 4 |
btn.onclick = function(){ console.log(event); console.log(window.event.srcElement); } |
理解標準瀏覽器與IE下阻止事件傳播的區別
在標準瀏覽器下我們可以使用stopPropagation()方法來停止事件在DOM層次中的傳播,即取消事件中的冒泡或者捕獲。從而避免觸發註冊在document.body上面的事件處理程式,如下所示:
1 2 3 4 5 6 7 8 |
var btn = document.getElementById("btn"); btn.onclick = function(e){ alert(1); e.stopPropagation(); } document.body.onclick = function(){ alert(2); } |
如上程式碼,如果我不使用stopPropagation()阻止冒泡事件的話,那麼在頁面中會先彈出1,然後彈出2,如果使用stopPropagation()方法的話,只會在頁面上彈出1,就不會冒泡到body上面去;
IE下停止冒泡的話,我們可以使用cancelBubble屬性,我們只要將此屬性設定為true,即可阻止事件通過冒泡觸發document.body中的註冊事件。但是IE是不支援捕獲事件的,但是stopPropagation()即支援捕獲事件又支援冒泡事件的。如下程式碼:
1 2 3 4 5 6 7 |
btn.onclick = function(e){ alert(1); window.event.cancelBubble = true; } document.body.onclick = function(){ alert(2); } |
如果不設定window.event.cancelBubble 為true的話,就會先彈出1,然後彈出2,如果加上的話,就只會彈出1對話方塊。
理解了上面的區別後,我們現在可以往EventUtil物件裡面新增跨瀏覽器的方法了;
跨瀏覽器的事件物件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
var EventUtil = { addHandler: function(element,type,handler) { if(element.addEventListener) { element.addEventListener(type,handler,false); }else if(element.attachEvent) { element.attachEvent("on"+type,handler); }else { element["on" +type] = handler; } }, removeHandler: function(element,type,handler){ if(element.removeEventListener) { element.removeEventListener(type,handler,false); }else if(element.detachEvent) { element.detachEvent("on"+type,handler); }else { element["on" +type] = null; } }, getEvent: function(event) { return event ? event : window.event; }, getTarget: function(event) { return event.target || event.srcElement; }, preventDefault: function(event){ if(event.preventDefault) { event.preventDefault(); }else { event.returnValue = false; } }, stopPropagation: function(event) { if(event.stopPropagation) { event.stopPropagation(); }else { event.cancelBubble = true; } } }; |
事件型別:
DOM3級事件規定了以下幾類事件;如下:
UI事件: 當使用者與頁面上的元素互動時觸發;
load事件:當頁面載入完後(包括所有影像,所有javascript檔案,css檔案等外部資源),就會觸發window上面的load事件,如下程式碼是載入圖片的:
HTML程式碼:<img src = “event.png” id=”img”/>
JS程式碼如下:
1 2 3 4 5 |
var img = document.getElementById("img"); EventUtil.addHandler(img,'load',function(event){ var event = EventUtil.getEvent(event); alert(EventUtil.getTarget(event).src); }); |
當圖片載入完後,就會彈出圖片的url地址了;
如果在建立新的img元素時,可以為其指定一個事件處理程式,以便影像載入完成後給出提示,此時,最重要的是在指定src屬性之前先指定事件;如下程式碼所示:
1 2 3 4 5 6 7 8 9 |
EventUtil.addHandler(window,'load',function(){ var img = document.createElement("img"); EventUtil.addHandler(img,'load',function(e){ e = EventUtil.getEvent(e); alert(EventUtil.getTarget(e).src); }); document.body.appendChild(img); img.src = "event.png"; }); |
在影像載入完成後,會彈出圖片地址了;
同樣的功能,我們可以使用DOM0級的Image物件來實現,在DOM出現之前,開發人員經常使用Image物件在客戶端預載入影像,如下程式碼:
1 2 3 4 5 6 7 |
EventUtil.addHandler(window,'load',function(){ var img = new Image(); EventUtil.addHandler(img,'load',function(e){ alert(1); }); img.src ="event.png"; }); |
Script元素也支援load事件,但是IE8及以下不支援,在IE9+,Firefox,Opera,chrome及Safari3+都支援,以便開發開發人員確定動態載入的javascript檔案是否載入完畢;比如我們動態建立script標籤後,通過load事件判斷動態建立的script標籤是否載入完畢,程式碼如下:
1 2 3 4 5 6 7 8 |
EventUtil.addHandler(window,'load',function(){ var script = document.createElement("script"); EventUtil.addHandler(script,'load',function(e){ alert(1); }); script.src = "a.js"; document.body.appendChild(script); }); |
焦點事件:當元素獲得或失去焦點時觸發;
有:blur:在元素失去焦點時觸發,這個事件不會冒泡,所有瀏覽器都支援。
foucs:在元素獲得焦點時觸發,這個事件不會冒泡,所有瀏覽器都支援。
滑鼠事件:當使用者通過滑鼠在頁面操作時觸發;
- click事件:在使用者單擊滑鼠按鈕或者按下Enter鍵觸發;
- dblclick事件:在使用者雙擊滑鼠按鈕時被觸發;
- mousedown事件:在使用者按下了任意滑鼠按鈕時被觸發,不能通過鍵盤觸發這個事件。
- mouseenter事件:在滑鼠游標從元素外部移動到元素範圍之內被觸發;這個事件不冒泡;
- mousemove事件:當滑鼠指標在元素內部移動時重複地觸發。
- mouseout事件:使用者將其移入另一個元素內被觸發。
- mouseover事件:滑鼠指標在元素外部,使用者將移入另一個元素的邊界時觸發,感覺和mouseenter事件類似;
- mouseup事件:使用者釋放滑鼠按鈕時觸發;
頁面上所有的元素都支援滑鼠事件,除了mouseenter和mouseleave,所有滑鼠事件都會冒泡,也可以被取消,而取消滑鼠事件將會影響瀏覽器的預設行為。
理解客戶區座標位置
含義是:滑鼠指標在可視區中的水平clientX和垂直clientY座標;
如下圖所示:
程式碼如下:
1 2 3 4 |
EventUtil.addHandler(btn,'click',function(e){ e = EventUtil.getEvent(e); console.log("可視區X軸座標為:"+e.clientX + " "+ "可視區Y軸座標為:"+e.clientY); }); |
注意:客戶區座標位置不包含滾動條滾動的位置,因此這個位置不代表滑鼠在頁面上的位置;
理解頁面座標位置pageX和pageY:
pageX與pageY是指頁面座標的位置,與clientX和clientY的區別是:它包含頁面滾動條的位置,如下圖所示:
程式碼如下:
1 2 3 4 |
EventUtil.addHandler(btn,'click',function(e){ e = EventUtil.getEvent(e); console.log("頁面X軸座標為:"+e.pageX + " "+ "頁面Y軸座標為:"+e.pageY); }); |
在頁面沒有滾動條的情況下,pageX與clientX相等,同理pageY與clientY相等。
但是IE8及更早的版本不支援pageX與pageY,不過我們可以使用客戶區座標(client,clientY)和滾動座標計算出來;因此我們需要用到document.body(混雜模式下)或 document.documentElement(標準模式下)中的scrollLeft和scrollTop屬性;
對此我們可以封裝程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 |
EventUtil.addHandler(btn,'click',function(e){ e = EventUtil.getEvent(e); var pageX = e.pageX, pageY = e.pageY; if(!pageX) { pageX = e.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft); } if(!pageY) { pageY = e.clientY + (document.body.scrollTop || document.documentElement.scrollTop); } console.log("頁面X軸座標為:"+pageX + " "+ "頁面Y軸座標為:"+pageY); }); |
理解螢幕座標的位置
螢幕橫座標screenX和垂直座標screenY屬性是相對於整個螢幕的。如下圖所示:
如下程式碼測試:
1 2 3 4 |
EventUtil.addHandler(btn,'click',function(e){ e = EventUtil.getEvent(e); console.log("螢幕X軸的座標為:"+e.screenX + " "+"螢幕Y軸的座標為:"+e.screenY); }); |
理解滑鼠滾輪事件:
IE6首先實現了mousewheel事件,此後opera,chrome和safari也都實現了這個事件,當使用者通過滑鼠滾輪與頁面互動,在垂直方向上滾動頁面時(無論向上還是向下),就會觸發mousewheel事件,這個事件可以在任何元素上觸發,最終會冒泡到document(IE8)或window(IE9,Opera,Chrome,Safari)物件,與mousewheel事件對應的event物件外,還有一個屬性wheelDelta屬性,當使用者向前滾動滑鼠滾輪時,wheelDelta是120的倍數,當使用者向後滾動滑鼠滾輪時,wheelDelta是-120的倍數。
將mousewheel事件給頁面任何元素或document物件,即可處理滑鼠滾輪操作;如下程式碼:
1 2 3 4 |
EventUtil.addHandler(btn,'mousewheel',function(e){ e = EventUtil.getEvent(e); alert(e.wheelDelta); }); |
如上程式碼,我不是在document物件或者window物件上,而是在頁面btn元素上觸發的;但是我們要注意,在Opera9.5之前的版本中,wheelDelta值的正負號是顛倒的,如果我們要支援Opera9.5版本之前的話,那麼我們需要瀏覽器檢測技術來檢測下;如下程式碼
1 2 3 4 5 6 |
EventUtil.addHandler(document, "mousewheel", function(event){ event = EventUtil.getEvent(event); // var delta = (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta); var delta = event.wheelDelta; alert(delta); }); |
但是client.engine.opera 這句程式碼執行下會報錯,因為目前還沒有封裝這個方法,所以等下一個部落格我會研究代理檢測封裝下這個方法;所以先不考慮opera9.5,先註釋掉這句程式碼;
但是FireFox支援一個為DOMMouseScroll的事件,也是在滑鼠滾輪滾動時觸發,與mousewheel事件一樣,但是他的有關滑鼠滾輪資訊儲存在detail屬性中,當滑鼠向前滾動時,這個屬性值是-3的倍數,當滑鼠滾輪向後滾動時,這個屬性值是3的倍數;也可以給DOMMouseScroll事件使用在任何元素上,且這個事件會冒泡到window物件上,因此我們可以這樣新增滾輪資訊的程式碼如下:
1 2 3 4 |
EventUtil.addHandler(document, "DOMMouseScroll", function(event){ event = EventUtil.getEvent(event); alert(event.detail); }); |
我們現在可以給跨瀏覽器下的滾輪事件;程式碼如下:
1 2 3 4 5 6 7 8 |
function getWheelDelta (event) { if(event.wheelDelta) { // return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta); return event.wheelDelta; }else { return -event.detail * 40 } } |
getWheelDelta方法首先檢測了事件物件是否包含了wheelDelta屬性,如果包含則返回屬性值,如果不包含,那麼我們就當作是firefox瀏覽器,那麼假設相應的值儲存在detail屬性中,有了上面的方法後,我們現在可以將相同的事件指定給mousewheel事件和DOMMouseScroll事件了;
1 2 3 4 5 6 7 |
EventUtil.addHandler(document, "DOMMouseScroll", handleMouseWheel); EventUtil.addHandler(document, "mousewheel", handleMouseWheel); function handleMouseWheel(event) { event = EventUtil.getEvent(event); var delta = EventUtil.getWheelDelta(event); alert(delta); } |
滾輪向上滾動是正數120,向下滾動是負數-120,所以根據是否大於0,可以判斷是向下滾動還是向上滾動;
理解字元編碼charCode
IE9+,firefox,chrome和safari的event物件都支援一個charCode屬性,這個屬性只有在發生keypress事件時才包含值,而且這個值是按下的那個鍵所代表字元的ASCLL編碼,但是IE8及之前或者opera不支援這個屬性,但是我們可以使用keyCode這個屬性代替.在取得了字元編碼之後,就可以使用String.fromCharCode()將其轉換成實際的字元。
如下程式碼:
1 2 3 4 5 6 7 |
getCharCode: function(event) { if(typeof event.charCode == 'number') { return event.charCode; }else { return event.keyCode; } } |
我們現在可以給EventUtil新增事件了,如下程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
var EventUtil = { addHandler: function(element,type,handler) { if(element.addEventListener) { element.addEventListener(type,handler,false); }else if(element.attachEvent) { element.attachEvent("on"+type,handler); }else { element["on" +type] = handler; } }, removeHandler: function(element,type,handler){ if(element.removeEventListener) { element.removeEventListener(type,handler,false); }else if(element.detachEvent) { element.detachEvent("on"+type,handler); }else { element["on" +type] = null; } }, getEvent: function(event) { return event ? event : window.event; }, getTarget: function(event) { return event.target || event.srcElement; }, preventDefault: function(event){ if(event.preventDefault) { event.preventDefault(); }else { event.returnValue = false; } }, stopPropagation: function(event) { if(event.stopPropagation) { event.stopPropagation(); }else { event.cancelBubble = true; } }, getRelatedTarget: function(event){ if (event.relatedTarget){ return event.relatedTarget; } else if (event.toElement){ return event.toElement; } else if (event.fromElement){ return event.fromElement; } else { return null; } }, getWheelDelta: function(event) { if(event.wheelDelta) { return event.wheelDelta; }else { return -event.detail * 40 } }, getCharCode: function(event) { if(typeof event.charCode == 'number') { return event.charCode; }else { return event.keyCode; } } }; |
我們現在可以做一個demo如下:
1 2 3 4 5 6 7 8 |
如下程式碼: var inputDiv = document.getElementById("inputDiv"); EventUtil.addHandler(inputDiv,'keypress',function(event){ event = EventUtil.getEvent(event); var code = EventUtil.getCharCode(event); alert(EventUtil.getCharCode(event)); // 彈出字元編碼 alert(String.fromCharCode(code)); // 彈出字元 }); |
HTML5事件
1. contextmenu事件
contextmenu事件在windows作業系統下,我們是使用右鍵就可以自定義右鍵彈出選單,但是我們使用右鍵的時候會有預設的選單,因此我們需要使用阻止預設事件這個方法來阻止掉;此事件也是屬於滑鼠事件,因此此事件包含與游標位置中所有的屬性,比如我們右鍵如下圖所示:
1 2 3 4 5 6 7 8 9 |
HTML程式碼如下: <div id="myDiv">Right click or Ctrl+click me to get a custom context menu.Click anywhere else to get the default context menu. </div> <ul id="myMenu" style="position:absolute;visibility:hidden;background-color: silver"> <li><a href="http://www.nczonline.net">Nicholas’ site</a></li> <li><a href="http://www.wrox.com">Wrox site</a></li> <li><a href="http://www.yahoo.com">Yahoo!</a></li> </ul> |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
JS程式碼如下: var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "contextmenu", function(event){ event = EventUtil.getEvent(event); EventUtil.preventDefault(event); var menu = document.getElementById("myMenu"); menu.style.left = event.clientX + "px"; menu.style.top = event.clientY + "px"; menu.style.visibility = "visible"; }); EventUtil.addHandler(document, "click", function(event){ document.getElementById("myMenu").style.visibility = "hidden"; }); |
如上,我們是通過右鍵的clientX和clientY來確定選單的位置;當我點選文件document的時候 就隱藏該選單;
瀏覽器支援有:IE,Firefox,Safari,chrome和Opera11+
beforeunload事件
此事件是給頁面在解除安裝之前,給使用者一個提示,是否需要解除安裝頁面提示給使用者,為了顯示這個對話方塊,對IE和firefox而言,必須將event.returnValue的值設定為要顯示給使用者的字串;但是對於safari和chrome而言,可以返回此字串即可;
如下程式碼:
1 2 3 4 5 6 |
EventUtil.addHandler(window, "beforeunload",function(event){ event = EventUtil.getEvent(event); var message = "I'm really going to miss you if you go."; event.returnValue = message; return message; }); |
當使用者關閉遊覽器的時候,會彈出如下視窗給使用者提示,如下:
點選離開此頁按鈕 即關閉視窗,點選留在此頁按鈕 即留在當前頁面,但是當我按F5重新整理頁面的時候,同樣會彈出視窗提示,如下:
瀏覽器支援:IE,firefox,chrome和safari都支援,但是Opera11及之前的版本不支援;
理解hashchange事件
HTML5中新增加了hashchange事件,以便在URL的引數列表(url中的#號後面的所有引數發生改變時通知開發人員),在Ajax應用中,開發人員經常使用url引數列表儲存狀態或導航資訊;
我們必須把hashchange事件新增到window物件中,然後當url引數列表只要發生變化就會呼叫此事件,此事件物件event包含2個屬性,oldURL和newURL,這兩個屬性分別儲存著URL變化前後的完整URL;
支援的瀏覽器有:IE8+,firefox3.6+,safari5+,chrome和opera10.6+
在這些瀏覽器中,只有firefox3.6+,chrome和opera支援oldURL和newURL屬性;
如下程式碼:
1 2 3 |
EventUtil.addHandler(window, "hashchange", function(event){ alert("Old URL: " + event.oldURL + "\nNew URL: " + event.newURL); }); |
當我第一次#號引數後面是aa,現在改成aaaa,就會觸發此事件,如下所示:
有些瀏覽器並不支援oldURL和newURL,因此我們可以使用location.hash來儲存當前的引數列表,如下程式碼:
1 2 3 4 5 |
EventUtil.addHandler(window, "hashchange", function(event){ alert(location.hash); }); |
當#號後面我改成bbb引數時候,會彈出如下所示:
可以使用如下程式碼來檢測瀏覽器是否支援hashchange事件;
1 2 |
var isSupported = ("onhashchange" in window); alert(isSupported); |
如果IE8 是在IE7 文件模式下執行,即使功能無效它也會返回true。為解決這個問題,可以使用
以下這個更穩妥的檢測方式:
1 |
var isSupported = ("onhashchange" in window) && (document.documentMode === undefined || document.documentMode > 7); |
裝置事件中的—orientationchange事件
蘋果公司為移動safari新增的orientationchange事件是能讓使用者確定何時將裝置由橫向檢視模式切換到縱向模式觸發的事件;此屬性中包含三個值,0表示肖像模式;90表示向左旋轉的橫向模式(主螢幕按鈕在右側),-90表示向右旋轉的橫向模式(主螢幕按鈕在左側),如下圖所示:
只要使用者改變了裝置的檢視模式,就會觸發orientationchange事件,
使用IOS裝置即可演示效果:程式碼如下:
1 2 3 4 5 6 7 |
EventUtil.addHandler(window, "load", function(event){ var div = document.getElementById("myDiv"); div.innerHTML = "Current orientation is " + window.orientation; EventUtil.addHandler(window, "orientationchange", function(event){ div.innerHTML = "Current orientation is " + window.orientation; }); }); |
理解移動端的事件—觸控與手勢事件
有以下幾個觸控事件:
- touchstart: 當手指觸控螢幕時觸發,即使是一個手指放在螢幕上也會觸發。
- touchmove:當手指在螢幕上滑動時連續地觸發,這個事件發生期間,我們可以使用preventDefault()事件可以阻止滾動。
- touchend: 當手指從螢幕上移開時觸發。
- touchcancel: 當系統停止跟蹤觸控時觸發。
上面幾個事件都屬於冒泡事件,我們可以對此進行取消事件,每個觸控的event物件都提供了在滑鼠中常見的屬性;
bubbles, cancelable,view,clientX, clientY ,screenX, screenY,detail, altKey, shiftKey, ctrlKey, metaKey,
除了常見的DoM屬性外,觸控事件還包含下列三個用於跟蹤觸控的屬性;
touches: 表示當前跟蹤的觸控操作的Touch物件陣列;
targetTouches: 特定與事件目標的Touch物件陣列;
changeTouches: 表示自上次觸控以來發生了什麼改變的Touch物件陣列;