Javascript事件總結

來源:互聯網
上載者:User
文章目錄
  • Dean Edwards的方案:addEvent/removeEvent庫
  • 事件冒泡

    • 事件的不同階段
    • 取消事件冒泡
    • 重載瀏覽器預設行為
  • 常見事件對象
    • this
    • 事件對象
  • 事件綁定
    • 傳統Dom綁定
    • W3C標準綁定
    • IE綁定
  • 牛人們的解決方案
一、事件冒泡1.1 事件的不同階段

Javascript事件在2個階段執行:捕獲與冒泡。

如的Dom結構中如果指向錨點#1.1的連結被點擊,則依次會觸發document > body > ul > li > ul > li > a 的Click處理函數。至此完成捕獲階段。當這階段完成,開始冒泡階段,中向上箭頭的順序。事件處理函數全部觸發。有興趣可以移步這裡,可以看到動態過程。

我們對上述代碼稍加更改,假如alert,因為那個demo中的效果切換太快了,我們慢一點洗洗體會。【註:這裡訂閱的事件都是冒泡階段的,也是最常用的,因為IE並不支援訂閱捕獲階段的時間。比較特殊的還有Opera,常常遇到有些特性向Firefox系,偶爾會有個別特性像IE】。這篇文章也助於加深理解

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"</p><p> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"></p><p><html xmlns="http://www.w3.org/1999/xhtml" lang="zh" xml:lang="zh"></p><p><head></p><p><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /></p><p><meta name="developer" content="Realazy" /></p><p><title>Bubble in JavaScript DOM</title></p><p><style type="text/css" media="screen"></p><p> div * {display:block; margin:4px; padding:4px; border:1px solid white;}</p><p> textarea {width:20em; height:2em;}</p><p></style></p><p><script type="text/javascript"></p><p> //<![CDATA[</p><p> function init(){</p><p> var log = document.getElementsByTagName('textarea')[0];</p><p> var all = document.getElementsByTagName('div')[0].getElementsByTagName('*');</p><p> for (var i = 0, n = all.length; i < n; ++i){</p><p> all[i].onmouseover = function(e){<br />alert('滑鼠現在進入的是: ' + this.nodeName);<br /> this.style.border = '1px solid red';</p><p> log.value = '滑鼠現在進入的是: ' + this.nodeName;</p><p> };</p><p> all[i].onmouseout = function(e){<br />alert('滑鼠現在移出的是: ' + this.nodeName);<br /> this.style.border = '1px solid white';</p><p> };</p><p> }</p><p> var all2 = document.getElementsByTagName('div')[1].getElementsByTagName('*');</p><p> for (var i = 0, n = all2.length; i < n; ++i){</p><p> all2[i].onmouseover = function(e){</p><p> this.style.border = '1px solid red';</p><p> if (e) //停止事件冒泡</p><p> e.stopPropagation();</p><p> else</p><p> window.event.cancelBubble = true;</p><p> log.value = '滑鼠現在進入的是: ' + this.nodeName;</p><p> };</p><p> all2[i].onmouseout = function(e){</p><p> this.style.border = '1px solid white';</p><p> };</p><p> }</p><p> }</p><p> window.onload = init;</p><p> //]]></p><p></script></p><p></head></p><p><body></p><p><h1>Bubble in JavaScript DOM</h1></p><p><p>DOM樹的結構是:</p></p><p><pre><code></p><p>UL</p><p> - LI</p><p> - A</p><p> - SPAN</p><p></code></pre></p><p><div></p><p> <ul></p><p> <li><a href="#"><span>Bubbllllllllllllllle</span></a></li></p><p> <li><a href="#"><span>Bubbllllllllllllllle</span></a></li></p><p> </ul></p><p></div></p><p><textarea></textarea></p><p><p>滑鼠進入UL的任何一個子項目,如果不停止冒泡,我們從UL到SPAN都定義了滑鼠移至上方(<code>mouseover</code>)事件,這個事件會上升了UL,從而從滑鼠所進入的元素到UL元素都會有紅色的邊。</p></p><p><div></p><p> <ul></p><p> <li><a href="#"><span>Bubbllllllllllllllle</span></a></li></p><p> <li><a href="#"><span>Bubbllllllllllllllle</span></a></li></p><p> </ul></p><p></div></p><p><p>如果停止冒泡,事件不會上升,我們就可以擷取精確的滑鼠進入元素。</p></p><p></body></p><p></html>

1.2 取消事件冒泡

其實1.1的代碼中已經包含了取消事件冒泡的代碼。這裡我們專門提出來寫,使其具有更好的相容性與美觀。

1 function stopBubble(e) {
2 if (e && e.stopPropagation) {
3 e.stopPropagation(); //因為傳入了事件對象e,並且支援W3C標準的stopPropagation()
4 } else {
5 window.event.cancelBubble = true; //For IE
6 }
7 }

          

【注】:我們不能簡單的看到傳入了事件對象就判斷為非IE瀏覽器,因為有時候我們使用3.1的方式來綁定事件,此時極有可能也會傳入一個window.event的引用。

1.3 重載瀏覽器預設行為

對於a標籤等具有預設行為(如跳轉到某URL)的HTML元素,我們可能想要部分a表現的有特色些,點擊某a就是不跳轉,可以重載其預設行為。

function stopDetault(e) {
if (e&&e.preventDetault) {
e.preventDefault();
} else {
window.event.returnValue = false;
}
return false;
}

使用方法:

document.getElementById("##").onclick = function (e) {
//do sth.
return stopDetault(e);
}

我們也常用下面的方式阻止預設行為,所以阻止事件處理函數本身return false也就可以理解了。

<a href="javascript:alert('clicked');return false;">a link without redirect action</a>

  

《Pro Javascript Techniques》[美 John Resig]一書中提到95%的情況中防止預設行為都有效,但是偶爾也會失效,因為該行為是由瀏覽器決定的,尤其是在文本域中防止敲擊和iframe內的行為。除此之外,都應該無大礙。這是一本學習javascript的好書。推薦。

二、 常見事件對象2.1 this

this 關鍵字是javascript中提供對當前對象引用的變數。綁定事件時this通常指的是當前元素,但是也有例外!!初接觸javascript覺得這個this有點變換莫測,難以捉摸。

如果你的感覺也是這樣,可以看看下邊的文章:

  • Javascript this關鍵字流量分析
  • [圖解] 你不知道的 JavaScript - “this”

通常在綁定事件時可以這樣使用this

document.getElementById("input1").onclick = function(e){
this.style.color="Red";
};

  

2.2 事件對象

通過對下面的代碼調試我們可以看到,事件對象通常包含當前鍵碼等事件相關資訊。值得一提的是IE的實現把事件對象放在一個全域變數window.event變數中儲存,而其他遵從W3C標準瀏覽器則作為一個參數傳進處理函數。

 

三、 事件綁定

各瀏覽器雖然支援的方式都不太一樣,但是相比混亂的CSS,事件綁定還是有章可循的。IE有自己的實現方式,並且各版本統一,其他現代瀏覽器都按照W3C標準來實現。

3.1 傳統Dom綁定

這種方式最簡單,最有效。而且this關鍵詞指向的是當前元素。但是缺點也不少,他們是:

1.只能綁定一次。假如我們引用的多個類庫中都對window.onload事件進行綁定,則前邊的綁定將會被後邊的覆蓋,並且常常難以察覺。

2.只支援訂閱冒泡階段事件。

3.事件參數只支援非IE,雖然事件對象參數僅支援非IE瀏覽器,但是我們可以使用下邊這種方式解決。

<a onclick="handle(event)" href="#">link</a>
3.2 W3C標準綁定

這個是最開心的方式了,除IE以外的現代瀏覽器都支援,我們可以直接使用每個dom元素的addEventListener(eventName,handleFunc,trueOrFalse),第一個參數為訂閱的事件名稱,如click(沒有on),第二個參數為時間處理函數,第三個參數為是否訂閱事件捕獲階段。

下面是使用addEventListener的例子

document.getElementById("linkA").addEventListener('click', function (e) {
alert('i am clicked!');
return stopDetault(e);
}, false);

優點:

1.支援冒泡與捕獲階段。

2.在處理函數內部,this關鍵字引用當前元素。

3.可以為同一元素的同一時間綁定多個處理函數,不會覆蓋。

缺點:

1.IE不支援

3.3 IE綁定

既然上邊提到IE不支援addEventListener,那麼肯定要找個解決方案幫幫IE小兄弟,那就是attachEvent,雖然有很多缺點,但也夠用。

下面是attachEvent的例子

document.attachEvent("onload", function () {
alert("i am load");
});

  

優點:

1.當然這個優點是和第一種綁定方式相比的:),同一元素支援多次綁定。

缺點:

1.僅支援IE事件的冒泡階段。

2.事件處理函數內部this關鍵字引用了window對象。要解決這個問題請繼續往下看。

3.事件名前必須加on,當然這個只是叫法不同,也沒什麼大礙。

4.只支援IE啊,這個很痛啊。

四、 牛人們的解決方案Dean Edwards的方案:addEvent/removeEvent庫

這個方案比較特別。詳細請移步這裡

特點:
1 it performs no object detection
2 it does not use the addeventListener/attachEvent methods
3 it keeps the correct scope (the this keyword)
4 it passes the event object correctly
5 it is entirely cross-browser (it will probably work on IE4 and NS4)
6 and from what I can tell it does not leak memory

  

源碼:

function handleEvent(event) {
var returnValue = true;
// grab the event object (IE uses a global event object)
event = event || fixEvent(window.event);
// get a reference to the hash table of event handlers
var handlers = this.events[event.type];
// execute each event handler
for (var i in handlers) {
this.$$handleEvent = handlers[i];
if (this.$$handleEvent(event) === false) {
returnValue = false;
}
}
return returnValue;
};

function fixEvent(event) {
// add W3C standard event methods
event.preventDefault = fixEvent.preventDefault;
event.stopPropagation = fixEvent.stopPropagation;
return event;
};
fixEvent.preventDefault = function() {
this.returnValue = false;
};
fixEvent.stopPropagation = function() {
this.cancelBubble = true;
};

  

【注】:這個方案有一個致命的東西,千萬不要這樣做這樣會覆蓋之前綁定的處理函數

<body onload="alert('hi');"></body>

  

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.