JavaScript 事件
什麼是JavaScript事件
事件(Event)是JavaScript應用跳動的心髒,也是把所有東西粘在一起的膠水,當我們與瀏覽器中Web頁麵進行某些類型的交互時,事件就發生了;通過使用JavaScript,你可以監聽特定事件的發生,並規定讓某些事件發生以對這些事件做出響應
事件對象是用來記錄一些事件發生時的相關信息的對象,但事件對象隻有事件發生時才會產生,並且隻能是事件處理函數內部訪問,在所有事件處理函數運行結束後,事件對象就被銷毀
事件流
事件流就是描述了頁麵中接受事件的順序,在瀏覽器發展的初期,兩大瀏覽器廠商IE和Netscape互掐,出現了一個坑爹的情況,那就是他們對事件流的解釋出現了兩中截然相反的定義。也就是我們所熟悉的:IE的事件冒泡,Netscape的事件捕獲
事件冒泡
事件冒泡即事件最開始由最具體的元素(文檔中嵌套層次最深的那個節點)接收,然後逐級向上傳播至最不具體的節點(文檔)
事件捕獲
事件捕獲即事件最早由不太具體的節點接收,而最具體的節點最後接收到事件
Javascript事件處理程序的3種方式
內聯形式
耦合度高,不利於維護
<button >點擊這個按鈕</button>
HTML事件處理程序
即我們直接在HTML代碼中添加事件處理程序,如下麵這段代碼:
<input value="按鈕" type="button" >
<script>
function showmsg(){
alert("HTML添加事件處理");
}
</script>
從上麵的代碼中我們可以看出,事件處理是直接嵌套在元素裏頭的,這樣有一個毛病:就是html代碼和js的耦合性太強,如果哪一天我想要改變js中showmsg,那麼我不但要在js中修改,還需要到html中修改,一兩處的修改我們能接受,但是當你的代碼達到萬行級別的時候,修改起來就需要勞民傷財了,所以,這個方式我們並不推薦使用
屬性綁定(DOM0級事件)
隻能綁定一個函數,在元素處於目標時觸發該事件
即為指定對象添加事件處理,看下麵的一段代碼
<input value="按鈕" type="button">
<script>
var btn2= document.getElementById("btn2");
btn2.onclick=function(){
alert("DOM0級添加事件處理");
}
btn.onclick=null;//如果想要刪除btn2的點擊事件,將其置為null即可
</script>
從上麵的代碼中,我們能看出,相對於HTML事件處理程序,DOM0級事件,html代碼和js代碼的耦合性已經大大降低;但是,聰明的程序員還是不太滿足,期望尋找更簡便的處理方式
事件監聽函數(DOM2級事件)
當addEventListener的最後參數為false時,是在冒泡階段觸發。如果是true的話是在捕獲階段出發。attachEvent始終是冒泡階段觸發
element.addEventListener(<event-name>, <callback>, <use-capture>);
element.removeEventListener(<event-name>, <callback>, <use-capture>);
element.attachEvent(event, callback)(IE11以後用addEventLisener);
element.detachEvent(event, callback)(IE11以後用addEventLisener);
DOM2也是對特定的對象添加事件處理程序,但是主要涉及到兩個方法,用於處理指定和刪除事件處理程序的操作:addEventListener()和removeEventListener()
它們都接收三個參數:要處理的事件名、作為事件處理程序的函數和一個布爾值(是否在捕獲階段處理事件),看下麵的一段代碼:
<input value="按鈕" type="button">
<script>
var btn3=document.getElementById("btn3"); btn3.addEventListener("click",showmsg,false);//這裏我們把最後一個值置為false,即不在捕獲階段處理,一般來說冒泡處理在各瀏覽器中兼容性較好
function showmsg(){
alert("DOM2級添加事件處理程序");
}
btn3.removeEventListener("click",showmsg,false);//如果想要把這個事件刪除,隻需要傳入同樣的參數即可
</script>
這裏我們可以看到,在添加刪除事件處理的時候,最後一種方法更直接,也最簡便。但是需要注意的是,在刪除事件處理的時候,傳入的參數一定要跟之前的參數一致,否則刪除會失效!
當同一個對象觸發多個方法的時候,後一個方法會把前一個方法覆蓋掉,也就是說,在對象的事件發生時,隻會執行最後綁定的方法。而用事件監聽則不會有覆蓋的現象,每個綁定的事件都會被執行
事件代理
原理:使用事件委托技術能讓你避免對特定的每個節點添加事件監聽器;相反,事件監聽器是被添加到它們的父元素上,利用冒泡的原理,把事件加到父級上,觸發執行效果
在父元素上綁定事件,監聽子元素的事件;主要用於子元素是新建元素或者子元素個數很多的情況下;這種方法可以提高性能,同時避免提前綁定元素事件而導致新建元素的事件沒有生效的結果
<ul> <li>11111111111111111111</li> </ul>
document.addEventListener('click', function (e) {
console.log('document currentTarget: ' + e.currentTarget.nodeName);
console.log('document target: ' + e.target.nodeName);
if (e.target.nodeName === 'LI') {
console.log('dom delegate: ' + e.eventPhase);
}
console.log(this);
}, true);
使用事件委托對於web應用程序帶來的幾個優點:
1.可以大量節省內存占用,減少事件注冊
2.可以方便地動態添加和修改元素,不需要因為元素的改動而修改事件綁定
3.JavaScript和DOM節點之間的關聯變少了,這樣也就減少了因循環引用而帶來的內存泄漏發生的概率
缺點:
不是所有的事件都能冒泡的。blur、focus、load和unload不能像其它事件一樣冒泡。事實上blur和focus可以用事件捕獲而非事件冒泡的方法獲得(在IE之外的其它瀏覽器中)
在管理鼠標事件的時候有些需要注意的地方;如果你的代碼處理mousemove事件的話你遇上性能瓶頸的風險可就大了,因為mousemove事件觸發非常頻繁。而mouseout則因為其怪異的表現而變得很難用事件代理來管理。
事件冒泡和事件捕獲的流程與區別
DOM2級事件規定事件包括三個階段:
1、事件捕獲階段;
2、處於目標階段;
3、事件冒泡階段。
首先是捕獲,然後處於目標階段(即來到事件的發出位置),最後才是冒泡
DOM2級事件規定事件包括三個階段:
首先是捕獲,然後處於目標階段(即來到事件的發出位置),最後才是冒泡
這裏為什麼沒有布爾值呢?因為ie8以及更早的版本隻支持事件冒泡,所以最後一個參數默認的相當於false來處理
事件的傳播是可以阻止的:
在W3c中,使用stopPropagation()方法
在IE下設置cancelBubble = true;
在捕獲的過程中stopPropagation();後麵的冒泡過程也不會發生了~
阻止事件的默認行為,例如click 後的跳轉~
在W3c中,使用preventDefault()方法;
在IE下設置window.event.returnValue = false;
自定義事件
DOM3級還定義了自定義事件,自定義事件不是由DOM原生觸發的,它的目的是讓開發人員創建自己的事件。要創建的自定義事件可以由createEvent("CustomEvent");
返回的對象有一個initCustomEvent()方法接收如下四個參數
1)type:字符串,觸發的事件類型,自定義。例如 “keyDown”,“selectedChange”;
2)bubble(布爾值):標示事件是否應該冒泡
3)cancelable(布爾值):標示事件是否可以取消
4)detail(對象):任意值,保存在event對象的detail屬性中
可以像分配其他事件一樣在DOM中分派創建的自定義事件對象
最後更新:2017-04-29 00:00:48