通常經過以下的方法對元素添加監聽事件html
target.addEventListener(type, listener[, options]); target.addEventListener(type, listener[, useCapture]);
當第3個參數是object時,能夠有下面的參數瀏覽器
Boolean
值,代表監聽函數在捕獲階段觸發Boolean
值,代表監聽函數在觸發一次以後,就會自動從監聽事件的列表中移除(至關於removeEventListener)Boolean
值,代表在監聽函數內部不會使用 preventDefault()
來取消瀏覽器的默認行爲。即便調用 preventDefault()
也沒有任何效果關於 passive
的介紹能夠看 這篇文章異步
首先,如今的瀏覽器基本都支持 冒泡+捕獲 的事件流模型,這裏就不在多加介紹函數
對事件對象來講: window
> document
> body
> 父類元素 > 事件目標網站
對註冊類型來講: 內聯事件 優先於 經過代碼註冊的事件(內聯事件也就是寫在html元素標籤屬性上的事件,如 <a onclick='...'></a>)spa
對事件觸發階段來講: 捕獲 優先於 冒泡線程
對註冊事件的順序來講: 先註冊的先調用code
經過實際例子檢驗一下:htm
<div id='div1'> <div id='div2'> <div id='div3'> <button type='button' onclick='console.log("inline onclick")'>Test</button> <p>11111111111111</p> </div> </div> </div>
function x(e){ //用 eventPhase 來檢測當前事件的處理階段 return e.eventPhase==3 ? 'bubbles':'capture ' } window.addEventListener('click',(e)=>{ console.log('window click 0 in '+ x(e),e) }); window.addEventListener('click',(e)=>{ console.log('window click 1 in '+ x(e),e) }); window.addEventListener('click',(e)=>{ console.log('window click 2 in '+ x(e),e) },true); document.addEventListener('click',(e)=>{ console.log('document click in ' + x(e) ,e) }) document.addEventListener('click',(e)=>{ console.log('document click in ' + x(e) ,e) },true) document.querySelector('#div2').addEventListener('click',(e)=>{ console.log('----start------') console.log('event in ' + x(e),e) console.log('target',e.target) console.log('current target',e.currentTarget) console.log('----end------') }) document.querySelector('button').addEventListener('click',(e)=>{ console.log('----start------') console.log('event in ' + x(e),e) console.log('target',e.target) console.log('current target',e.currentTarget) console.log('----end------') },true)
點擊按鈕,咱們能夠看一下控制檯是如何輸出的對象
通常是使用下方兩個方法中斷事件流的傳播(注意,阻止事件傳播不是銷燬event對象,event依然會返回給瀏覽器)
event.stopPropagation() // 阻止event往其餘事件目標傳播,可是當前事件目標其餘的監聽函數會依次調用 event.stopImmediatePropagation() // 當即阻止event傳播,不會調用其餘的監聽函數
阻止事件執行瀏覽器的默認行爲(調用以後沒法恢復)
event.preventDefault()
有些事件的觸發機制是連續性的,好比 click
事件須要 mousedown
和 mouseup
這兩個前置事件的觸發(鼠標按鍵按下而後彈起纔算是一個完整的點擊),若是在mouseup
裏用event.preventDefault()
阻止mouseup的默認行爲,click
事件也所以沒法觸發。 相似的有 keypress
須要 keydown
和keyup
,還有其餘。
這裏有一個簡單的應用:好比一個網站使用這樣的代碼document.addEventListener('copy',(e)=>{e.preventDefault()})
讓用戶不能複製頁面上的內容。 要突破複製限制,通常的解決方法是用 removeEventListener
,但是這裏行不通,由於監聽函數是一個匿名函數,而你又沒法獲得這個函數的引用。 替代的方案是window.addEventListener('copy',(e)=>{e.stopImmediatePropagation()})
這裏利用了監聽函數執行的優先順序,提早終止了事件的傳播,讓網站阻止複製的代碼沒法執行。
Event
接口表明了DOM中全部事件,是全部事件的父類。在DOM中事件的種類很是多(連接),他們的初始化參數也比較複雜,不可能一一列舉,這裏只介紹幾種用代碼的方式自動義事件的例子(不推薦使用 document.createEvent的方式構建事件)
event = new Event(typeArg, eventInit);
typeArg
表示這個事件的名稱,能夠按照本身的需求定義。若是名稱定義爲瀏覽器內置事件的名稱,這個事件是沒有實際效果的,由於這些事件都有屬於他們本身的構造函數,如 click
對應 new MouseEvent
。
eventInit
對象有3個參數
Boolean
值,代表事件是否須要冒泡階段Boolean
值,代表事件是否能夠取消Boolean
值,跟 Shadow DOM 有關,暫時不瞭解做用eventInit
只有3個參數,基本沒什麼用處,也不能傳遞數據,因此經過Event
構造函數建立的事件只有簡單的通知做用,告訴你有某個事件被觸發了,而後就沒了。
event = new MouseEvent(typeArg, mouseEventInit);
mouseEventInit 可用的參數比較多,選擇幾個重要的說明一下
mouseEventInit = { button: 0, // 鼠標事件的按鈕,0是左鍵,1是中鍵,2是右鍵 ctrlKey: false, shiftKey: false, altKey: false, // 對應於鍵盤上的三個控制鍵是否被按下 screenX: 0, screenY: 0, // 對應事件觸發時鼠標在用戶屏幕上的座標 clientX: 0, clientY:0, // 對應事件觸發時鼠標在用戶瀏覽器界面上的座標 }
建立一個鼠標事件能夠這樣
var event = new MouseEvent('click',{}) // 對,什麼都不要,由於參數都有默認值
或者正規一點
var event = new MouseEvent('click', { button: 1, view: window, bubbles: true, cancelable: true });
event = new CustomEvent(typeArg, customEventInit);
CustomEvent顧名思義,就是自定義事件,它可讓咱們把數據放在事件對象裏面,而且隨着事件的傳播而傳播(終於有一個實用的了),而上面兩個事件通常都由瀏覽器根據用戶的行爲觸發
var event = new CustomEvent('cat', { detail: { // 數據放在 detail 下面,支持任何類型的數據,好比這裏的數據類型是一個對象 data: 'balabalalalala', getMySalary: function(){ return 20000; } } });
要建立瀏覽器自帶事件,並用代碼來模擬事件的觸發,須要選擇正確構造函數和正確的構造參數來建立事件。這些參數都在 MDN 上有詳細的介紹,想對事件深刻理解的話不妨認真閱讀。
我我的瞭解到的總共有這3種觸發方式
這三種方法的觸發是相互影響的,並不能徹底獨立開來。
「原生」事件如瀏覽器本身觸發事件在執行監聽函數時是異步執行的,可是 element.dispatchEvent(event)
是同步執行的,也就是說,dispatchEvent調用後,當前的JS運行線程會阻塞在這裏,直到全部的監聽函數被執行並結束。
鑑別是瀏覽器派發的事件仍是經過JS代碼的方式手動觸發的事件,只需檢測 event
裏的isTrused
屬性,爲true
就是瀏覽器觸發的,false
則是代碼觸發的,這個屬性沒法用初始化參數進行初始化