js的事件處理

事件就是用戶或?yàn)g覽器自身執(zhí)行的某種動(dòng)作遍愿。比如說 click奔滑,mouseover耙考,都是事件的名字谜喊。而相應(yīng)某個(gè)事件的函數(shù)就叫事件處理程序(或事件偵聽器)。為事件指定處理程序的方式有好幾種倦始。

事件的作用范圍

//html
<div id="wrap">
    <div id="outer">
      <div id="inner"></div>
    </div>
  </div>
//css
#wrap {
  width: 200px;
  height: 200px;
  background: pink;
}
#outer {
  position: relative;
  top: 50px;
  left: 50px;
  width: 100px;
  height: 100px;
  background: #eeddff;
}
#inner {
  position: relative;
  top: 25px;
  left:25px;
  width: 50px;
  height: 50px;
  background: #44ddff;
}
//js
var wrap = document.getElementById('wrap');
wrap.addEventListener('click',function(){
  alert('789');
},false);
效果圖

當(dāng)點(diǎn)擊粉色塊和粉色外淺藍(lán)色部分的時(shí)候,都彈出了789,而淺藍(lán)色部分是嵌套在wrap元素之內(nèi)的元素,故可得出結(jié)論,當(dāng)元素注冊(cè)了事件,此事件的作用范圍為:1.元素自己所占頁面空間部分加嵌套元素所占空間范圍(若嵌套元素覆蓋在容器元素上斗遏,則事件的作用范圍為容器元素自身所占空間大小)

事件流

事件流描述的是從頁面中接受事件的順序。IE的事件流是事件冒泡流鞋邑,而Netscape Communicator的事件流是事件捕獲流最易。

冒泡事件

IE的事件流叫做事件冒泡(event bubbing)怒坯,即事件右最具體的元素接受,然后逐級(jí)向上傳播到不具體的元素藻懒,以下面的代碼為例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <input type="button" value='click me' id='myBtn'>
</body>
</html>

如果你單擊了#myBtn剔猿,那么在IE的頁面中,這個(gè)事件會(huì)如下傳播:

input->body->html->document

可以看到嬉荆,事件首先在input上發(fā)生归敬,input就是我們單擊的元素。然后事件沿著DOM樹向上傳播鄙早,一直到document對(duì)象汪茧。
所有的現(xiàn)代瀏覽器都支持事件冒泡。IE9限番,F(xiàn)irefox舱污,Chrome和Safari則將事件一直冒泡到window對(duì)象。

事件捕獲

Netscape團(tuán)隊(duì)提出的另一種事件流叫事件捕獲弥虐,事件捕獲的思想是不太具體的節(jié)點(diǎn)應(yīng)該更早接收到事件扩灯,而最具體的節(jié)點(diǎn)應(yīng)該最后接收到事件。以上面的代碼作為例子霜瘪,那么單擊div的時(shí)候會(huì)按照與冒泡相反的順序觸發(fā)事件珠插。

document->html->body->input

在這個(gè)過程中,document對(duì)象先接收到click事件颖对,然后事件沿著DOM樹依次向下捻撑,一直傳遞到目標(biāo)元素。
IE9缤底,F(xiàn)irefox顾患,Chrome和Safari都支持事件捕獲「鲞螅“DOM2級(jí)事件”規(guī)范要求事件應(yīng)該從document對(duì)象開始傳播描验,但實(shí)際上這些瀏覽器都是從window對(duì)象開始捕獲事件。

DOM事件流

規(guī)定的事件流包括三個(gè)階段:事件捕獲階段==>處于目標(biāo)階段==>事件冒泡階段坑鱼。首先發(fā)生的是事件捕獲階段膘流,為截獲事件提供了機(jī)會(huì)。然后是實(shí)際的目標(biāo)接收事件鲁沥。最后一個(gè)階段是冒泡階段呼股。

DOM事件流

事件處理程序

HTML事件處理程序
<script type="text/javascript">   
function show(){   
alert('hello world!');   
}   
</script>   
<input type="button" value="click me" onclick="show()"/>  

在 html 中指定事件處理程序有兩個(gè)缺點(diǎn)。

  • 存在一個(gè)時(shí)差問題画恰。就本例子來說彭谁,假設(shè) show()函數(shù)是在按鈕下方,頁面的最底部定義的允扇,如果用戶在頁面解析 show()函數(shù)之前就單擊了按鈕缠局,就會(huì)引發(fā)錯(cuò)誤则奥;
  • html 與 javascript 代碼緊密耦合。如果要更換時(shí)間處理程序狭园,就要改動(dòng)兩個(gè)地方:html 代碼和 javascript 代碼读处。
Javascript 指定事件處理程序

1.DOM0事件處理程序

var btn=document.getElementById("myBtn");   //獲得對(duì)象元素的引用
btn.onclick=function(){
    alert("Clicked!");
}

要使用JavaScript指定事件處理程序,必須先獲得對(duì)象元素的引用唱矛,然后為其指定事件處理程序的函數(shù)罚舱。
事件處理程序是在元素的作用域中運(yùn)行的,也就是說程序中的this指向的是當(dāng)前元素绎谦。

var btn=document.getElementById("myBtn");   //獲得對(duì)象元素的引用
btn.onclick=function(){
    alert(this.id); //mybtn
}

通過將事件處理程序?qū)傩缘闹翟O(shè)置成null就可以刪除事件處理程序管闷。

btn.onclick = null;

2.DOM2級(jí)事件處理程序

“DOM2級(jí)事件”規(guī)定了兩個(gè)方法用于操作事件處理程序:addEventListener()和removeEventListener()。所有的節(jié)點(diǎn)都包含這兩個(gè)方法窃肠,接收三個(gè)參數(shù):要處理的事件名包个,作為事件處理程序的函數(shù)和一個(gè)布爾值。最后的參數(shù)如果是true冤留,表示在事件捕獲階段調(diào)用事件處理程序碧囊,如果是false,表示在事件冒泡階段調(diào)用事件處理程序搀菩。

var btn=document.getElementById("myBtn");   
btn.addEventListener("click",function(){
    alert(this.id);
},false);

DOM0級(jí)事件處理程序只能為一個(gè)元素添加唯一的某一個(gè)事件的處理程序呕臂。如果為一個(gè)元素添加了兩個(gè)click的處理程序破托,后定義的程序會(huì)覆蓋掉之前定義的程序肪跋,其實(shí)也就是給變量a多次賦值一樣。使用DOM2級(jí)事件處理程序的好處之一就是:可以添加多個(gè)添加多個(gè)事件處理程序土砂。

var btn = document.getElementById('mybtn');
           btn.addEventListener('click',function () {
               alert('click me');
           },false)
            btn.addEventListener('click',function () {
                alert(this.id)
            },false);

這兩個(gè)事件處理程序會(huì)按照添加的順序觸發(fā)州既。

通過addEventListener()添加的事件處理程序只能使用removeEventListener()來移除。通過addEventListener()添加的匿名函數(shù)無法移除萝映,因?yàn)橐瞥莻魅氲膮?shù)與添加處理程序時(shí)使用的參數(shù)必須相同吴叶。

function handle() {
            alert('hello world')
}
btn.addEventListener('click',handle,false);
btn.removeEventListener('click',handle,false);

大多數(shù)情況下,都是就事件處理程序添加到事件流的冒泡階段序臂,這樣可以最大限度的兼容各種瀏覽器蚌卤。

IE中的事件處理程序

IE中有類似于DOM的兩個(gè)方法:attachEvent()和detachEvent()。這兩個(gè)方法接受兩個(gè)參數(shù):事件處理程序名稱和事件處理程序函數(shù)奥秆。attachEvent()添加的事件處理程序都會(huì)添加到冒泡階段逊彭。

var btn=document.getElementById("myBtn");
btn.attachEvent("onclick",function(){
    alert("click me");
});

需要注意的是,這里傳入的是‘onclick’而不是‘click’构订。
前面說到侮叮,在DOM0級(jí)事件中,事件處理程序的作用域是元素的作用域悼瘾,而在使用attachEvent()時(shí)囊榜,作用域變成了全局作用域审胸,此時(shí)this等于window

var btn=document.getElementById("myBtn");
btn.attachEvent("onclick",function(){
    alert(this==widnow);//"true"
});

與addEventListener()一樣,attachEvent()也可以用來為一個(gè)元素添加多個(gè)事件處理程序卸勺,不過與DOM方法不同的是砂沛,事件處理程序不是按照添加的順序執(zhí)行,而是以相反的順序執(zhí)行孔庭。
可以使用detachEvent()移除使用attachEvent()添加的事件處理程序尺上。與DOM方法一樣必須提供相同的參數(shù),添加的匿名函數(shù)不能被移除圆到。

因此怎抛,跨域?yàn)g覽器的事件處理程序可以這樣寫:

var EventUtil = {   
addHandler: function(element, type, handler){ // 該方法接受 3 個(gè)參數(shù):要操作的元素,事件名稱和事件處理程序函數(shù)   
if (element.addEventListener){ // 檢查傳入的元素是否存在 DOM2 級(jí)方法   
element.addEventListener(type, handler, false); // 若存在芽淡,則使用該方法   
} else if (element.addEvent){ // 如果存在的是 IE 的方法   
element.attachEvent("on" + type, handler); // 則使用 IE 的方法马绝,注意,這里的事件類型必須加上 "on" 前綴挣菲。   
} else { // 最后一種可能是使用 DOM0 級(jí)   
element["on" + type] = hander;   
}   
},   

removeHandler: function(element, type, handler){ // 該方法是刪除之前添加的事件處理程序   
if (element.removeEventListener){ // 檢查傳入的元素是否存在 DOM2 級(jí)方法   
element.removeEventListener(type, handler, false); // 若存在富稻,則使用該方法   
} else if (element.detachEvent){ // 如果存在的是 IE 的方法   
element.detachEvent("on" + type, handler); // 則使用 IE 的方法,注意白胀,這里的事件類型必須加上 "on" 前綴椭赋。   
} else { // 最后一種可能是使用 DOM0 及方法 (在現(xiàn)代瀏覽器中,應(yīng)該不會(huì)執(zhí)行這里的代碼)   
element["on" + type] = null;   
}   
}   
};  
var btn =document.getElementById("mybtn");   
var hander= function(){   
alert("clicked");   
};   
 
EventUtil.addHandler(btn,"click",hander);   
 
EventUtil.removeHandler(btn,"click",hander); // 移除之前添加的事件處理程序  

參考資料:
https://segmentfault.com/a/1190000003497939
http://wiki.jikexueyuan.com/project/brief-talk-js/event-handlers.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末或杠,一起剝皮案震驚了整個(gè)濱河市哪怔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌向抢,老刑警劉巖认境,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異挟鸠,居然都是意外死亡叉信,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門艘希,熙熙樓的掌柜王于貴愁眉苦臉地迎上來硼身,“玉大人,你說我怎么就攤上這事覆享〖阉欤” “怎么了?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵淹真,是天一觀的道長(zhǎng)讶迁。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么巍糯? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任啸驯,我火速辦了婚禮,結(jié)果婚禮上祟峦,老公的妹妹穿的比我還像新娘罚斗。我一直安慰自己,他們只是感情好宅楞,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布针姿。 她就那樣靜靜地躺著,像睡著了一般厌衙。 火紅的嫁衣襯著肌膚如雪距淫。 梳的紋絲不亂的頭發(fā)上窒升,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天产场,我揣著相機(jī)與錄音蛉迹,去河邊找鬼赖晶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛晦款,可吹牛的內(nèi)容都是我干的惨篱。 我是一名探鬼主播固翰,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼筒饰,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼缴啡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瓷们,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤业栅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后换棚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體式镐,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡反镇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年固蚤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片歹茶。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡夕玩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惊豺,到底是詐尸還是另有隱情燎孟,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布尸昧,位于F島的核電站揩页,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏烹俗。R本人自食惡果不足惜爆侣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一萍程、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧兔仰,春花似錦茫负、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至榕吼,卻和暖如春饿序,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背羹蚣。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工嗤堰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人度宦。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓踢匣,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親戈抄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子离唬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 以下文章為轉(zhuǎn)載,對(duì)理解JavaScript中的事件處理機(jī)制很有幫助划鸽,淺顯易懂输莺,特分享于此。 什么是事件裸诽? 事件(E...
    jxyjxy閱讀 3,035評(píng)論 1 10
  • JavaScript 程序采用了異步事件驅(qū)動(dòng)編程模型嫂用。在這種程序設(shè)計(jì)風(fēng)格下,當(dāng)文檔丈冬、瀏覽器嘱函、元素或與之相關(guān)的對(duì)象發(fā)...
    劼哥stone閱讀 1,256評(píng)論 3 11
  • 聲明:本文來源于http://www.webzsky.com/?p=731我只是在這里作為自己的學(xué)習(xí)筆記整理一下(...
    angryyan閱讀 7,006評(píng)論 1 6
  • 本章內(nèi)容 理解事件流 使用事件處理程序 不同的事件類型 JavaScript 與 HTML 之間的交互是通過事件實(shí)...
    悶油瓶小張閱讀 282評(píng)論 0 0
  • 一往弓、問答 1. dom對(duì)象的innerText和innerHTML有什么區(qū)別? innerHTML: 也就是從對(duì)象...
    饑人谷_羅偉恩閱讀 596評(píng)論 0 2