JavaScript異步編程之事件

更多相關內容見博客 github.com/zhuanyongxi…javascript

DOM0

html標籤中的寫法html

<image id="element" src="hello.png" onclick="alert('Hi')"/>
複製代碼

在JS中的綁定方法:vue

var element = document.getElementById("element");
element.onclick = function(e) {}
複製代碼

dom0是節點元素的私有屬性。同一個事件只能綁定一個,綁定多個,只有最後一個有效。直接寫在html節點上的也會被覆蓋。以下面的代碼,最後點擊觸發的時候只會打印3。java

var element = document.getElementById("element");
element.onclick = function(e) {console.log(1)};
element.onclick = function(e) {console.log(2)};
element.onclick = function(e) {console.log(3)};
複製代碼

因此,在使用如window.onload之類的事件的時候就須要注意了。git

DOM1

有標準,不涉及實踐。github

DOM2

addEventListener方法在節點對象的原型鏈上。綁定實名函數更好,由於能夠移除。第三個參數用於選擇在什麼階段觸發,默認false表示在冒泡階段觸發。編程

element.addEventListener('change',function(){},false)
複製代碼

與DOM0的相比,DOM2事件能夠綁定多個,以下,1和2都會被打印:設計模式

element.addEventListener('change', function() {console.log(1)}, false);
element.addEventListener('change', function() {console.log(2)}, false);
複製代碼

但是,在綁定實名函數的時候,若是事件、函數名和觸發階段徹底相同的話,最終也是隻有最後一個有效,以下,最終事件觸發的時候只會打印出一個1:api

function fn() {console.log(1)};
element.addEventListener('change', fn, false);
element.addEventListener('change', fn, false);
複製代碼

此外,addEventListener還能夠綁定DOM0中沒有的事件,如DOMContentLoaded。瀏覽器

DOM3

與DOM2的區別在於事件的種類,其餘的同樣。如keyupkeydownkeypress都是DOM3的事件,click也是DOM3級事件,具體到MDN中搜索DOM L3

事件流

簡要的說就是事件的三個階段:捕獲階段--目標階段--冒泡階段。詳細說就是以下圖。

當用戶點擊瀏覽器窗口,事件發生,捕獲階段開始:window--document--html--body--父節點--目標節點(目標階段),而後開始冒泡階段:目標節點--父節點--body--html--document--window。

幾個須要注意的api

preventDefault的做用是阻止瀏覽器默認行爲,什麼是默認行爲?除了你本身綁定的操做以外的行爲都是瀏覽器的默認行爲,如a標籤的跳轉,表單的提交,鼠標右鍵呼出菜單等等。

此外event.returnValue = false;return false;也能夠達到跟proventDefault一樣的效果。若是是a標籤,阻止跳轉,能夠href="javascript:;"href=javascript:void 0;

stopPropagation的做用是阻止事件的傳播。阻止的是其餘節點上的事件。

stopImmediatePropagation的做用也是阻止事件的傳播。它不但能阻止其餘節點上的事件,當前節點上的其餘未觸發的事件也會一併阻止。以下代碼,只打印1:

element.addEventListener('click', function(event) { 
  event.stopImmdiatePropagation();
  console.log(1);
}, false);
element.addEventListener('click', function() {console.log(2)}, false);
複製代碼

currentTarget,當前會執行的回調函數綁定的那個節點。

elementFirst.addEventListener('click', function(event) {
  console.log(event.currentTarget);		// elementFirst
}, false);
elementSecond.addEventListener('click', function(event) {
  console.log(event.currentTarget);		// elementSecond
}, false);
複製代碼

target,就是事件流中的目標階段的那個節點,也就是目標節點。須要注意的是,事件是否發生與是否綁定的操做沒有關係,即使沒有在一個節點上綁定事件的操做,事件依然會發生。target能夠在事件委託中使用。

自定義事件

var myEvent = new Event('theEvent');
theTarget.addEventlistener('theEvent', function() {doSomething()})
theTarget.dispatchEvent(myEvent);	// theTarget是一個節點,或者說是一個能夠調用addEventListener方法的對象。
複製代碼

此外customEvent作到跟Event一樣的效果,他們的區別在於,customEvent能夠加一些本身須要的數據進去,不過兼容性沒有Event好。

Event建立了實例以後,也能夠用myEvent.data = {}的方式給數據,效果是同樣的。

這有什麼用?能夠用來作全局範圍內的廣播,使模塊間解耦。在vue中有一個用於組件間通信的EventBus,自定義事件就能夠用來實現這一功能。

事件委託和代理

事件委託就是把原本應該由你來作的事情,讓別人幫忙作一下。

在實際編程中,可能會出現這樣的場景,一個節點下有多個子節點,每一個子節點都要有相應的事件綁定,這個時候咱們就能夠利用事件的冒泡,把事件綁定在父節點上,而後用event.target來區分究竟是哪一個子節點觸發的事件。當這些子節點須要動態增減的時候,使用事件委託就顯得尤其方便了,不管是寫代碼的效率仍是程序運行的效率都會更高。

侷限性:focus、blur這樣的事件沒有在冒泡機制,沒法委託。另一些消耗較高的事件如mousemove和mouseout也不適合委託。以下圖

若是咱們把B區域的mousemove事件委託到A區域,當事件在A區域發生的時候,對應的操做也會執行,若是是消耗較低的事件,就不會有太大的影響,可若是是消耗較高的事件,就會顯得有點浪費了。

觀察者模式與發佈訂閱模式

這兩種設計模式與事件很是的相似。與事件的區別在於,事件是異步的,而咱們本身實現的這兩種模式,雖然使用了回調函數,但大都是同步的。而這兩種設計模式之間的區別在於,發佈訂閱模式的事件池是統一的,觀察者模式的事件池分散在各個發佈者上面。

參考文章

相關文章
相關標籤/搜索