摘要:指定事件處理程序指定事件處理程序主要有兩種方式級(jí)事件處理程序級(jí)事件處理程序。添加事件處理程序注意這里是哦或移除事件處理程序使用移除事件處理程序的條件與方法相同必須提供相同的參數(shù),從而添加的匿名函數(shù)也無(wú)法被移除。
今天看書又看到事件,遂決定小總結(jié)一下~
JavaScript與HTML之間的交互是通過(guò)事件實(shí)現(xiàn)的。事件,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特定的交互瞬間??梢允褂帽O(jiān)聽器(事件處理程序)來(lái)監(jiān)聽事件,以便事件發(fā)生時(shí)執(zhí)行相應(yīng)的代碼。
本文主要講事件流和事件處理程序。后續(xù)會(huì)再寫一篇文章,總結(jié)事件類型。
事件流大家都舉同心圓的栗子,我在這里也說(shuō)說(shuō)咯~想象畫在一張紙上的一組同心圓,如果把手指放在圓心上,那么手指碰觸的不是一個(gè)圓,而是紙上所有的圓。這和點(diǎn)擊HTML頁(yè)面上的元素原理是一樣的,如果頁(yè)面上有個(gè)按鈕,你點(diǎn)擊按鈕的同時(shí),也點(diǎn)擊了按鈕的容器元素,點(diǎn)擊了容器元素的容器元素……點(diǎn)擊了整個(gè)頁(yè)面。
事件流描述的是從頁(yè)面中接收事件的順序?,F(xiàn)存兩種事件流:
事件冒泡流——IE
事件捕獲流——Netscape
事件冒泡接收事件的順序是:事件由最具體的元素接收,逐級(jí)向上傳播到較為不具體的節(jié)點(diǎn)。
如果頁(yè)面中有個(gè)div,點(diǎn)擊了div之后,事件的傳播順序如下:
(1) div
(2) body
(3) html
(4) document
事件冒泡的過(guò)程如下圖:
所有現(xiàn)代瀏覽器都支持事件冒泡,而且IE9,F(xiàn)irefox、Chrome、Safari都將事件一直冒泡到window對(duì)象。
事件捕獲接收事件的順序是:事件由最不具體的元素接收,逐級(jí)向下傳播到最具體的節(jié)點(diǎn)。
如果頁(yè)面中有個(gè)div,點(diǎn)擊了div之后,事件的傳播順序如下:
(1) document
(2) html
(3) body
(4) div
事件捕獲的過(guò)程如下圖:
IE9,F(xiàn)irefox、Chrome、Safari都支持這種事件流模型,而且是從window對(duì)象開始捕獲事件的。
DOM事件流“DOM2級(jí)事件”規(guī)定事件流包含3個(gè)階段:事件捕獲階段、處于目標(biāo)階段、事件冒泡階段。
如下圖:
在DOM事件流中,捕獲階段包括1,2,3。冒泡階段包括4,5,6,7。其中4是處理目標(biāo)階段,在事件處理中被看成是冒泡階段的一部分。
雖然“DOM級(jí)事件”規(guī)范明確規(guī)定捕獲階段不涉及事件目標(biāo),但是IE9,F(xiàn)irefox、Chrome、Safari和Opera9.5及以上版本都會(huì)在捕獲階段觸發(fā)事件對(duì)象上的事件,這就意味著有兩個(gè)機(jī)會(huì)在目標(biāo)對(duì)象上面操作事件。
IE9,F(xiàn)irefox、Chrome、Safari、Opera都支持DOM事件流,IE8及更早版本不支持DOM事件流。即IE9,F(xiàn)irefox、Chrome、Safari、Opera及支持冒泡又支持捕獲,而IE8及以前版本僅支持冒泡。
需要說(shuō)明的是,在實(shí)際中,大多數(shù)都使用冒泡事件,僅在有特殊需要時(shí)才使用捕獲事件。
事件處理程序在說(shuō)事件處理程序之前,先簡(jiǎn)單介紹下事件對(duì)象。什么是事件對(duì)象呢?
在觸發(fā)DOM上的某個(gè)事件時(shí),會(huì)產(chǎn)生一個(gè)對(duì)象,這個(gè)對(duì)象中包含所有與事件有關(guān)的信息,如導(dǎo)致事件的元素、事件的類型以及其他與特定事件相關(guān)的信息,這個(gè)對(duì)象就是事件對(duì)象。所有的事件處理程序都可以訪問(wèn)事件對(duì)象,但是訪問(wèn)的方式不盡相同,一種是將事件對(duì)象作為事件處理程序的參數(shù),另一種是事件對(duì)象作為window的屬性,通過(guò)window.event來(lái)訪問(wèn)。這里就介紹到這里,先有個(gè)概念~
回歸正題,click,load,mouseover都是事件的名字,而響應(yīng)某個(gè)事件的函數(shù)就叫做事件處理程序,事件處理程序的名字以“on”開頭。
那么該怎樣為事件指定處理程序呢?主要有兩類方法:HTML事件處理程序和JavaScript指定事件處理程序。
HTML特性指定事件處理程序某個(gè)HTML元素支持的每種事件,都可以使用一個(gè)與相應(yīng)事件處理程序同名的HTML特性來(lái)指定。這個(gè)特性的值是能夠執(zhí)行的JavaScript代碼。
具體指定方式或
這種方式中,事件處理程序中的代碼在執(zhí)行時(shí),有權(quán)訪問(wèn)全局作用域中的任何代碼。
本質(zhì)這樣的事件處理程序在執(zhí)行的時(shí)候,會(huì)創(chuàng)建一個(gè)封裝著元素屬性值的函數(shù),然后執(zhí)行這個(gè)函數(shù)。就是說(shuō),
當(dāng)單擊按鈕的時(shí)候,先創(chuàng)建一個(gè)函數(shù)function () { console.log("hello"); },然后立即執(zhí)行該函數(shù)。
這個(gè)函數(shù)有以下3個(gè)特點(diǎn):
1) 函數(shù)中會(huì)有一個(gè)局部變量event,即事件對(duì)象。
注意:event是局部變量,可以在函數(shù)中直接訪問(wèn),既不用自己定義,也不是從參數(shù)列表中讀取。這點(diǎn)與后面其他指定事件處理程序的方式有所不同,記得區(qū)分。
2) 函數(shù)內(nèi)部,this值等于事件的目標(biāo)元素。
3)這個(gè)動(dòng)態(tài)創(chuàng)建的函數(shù)使用with擴(kuò)展作用域:
function () { with(document) { with(this) { // 元素屬性值,如 console.log("hello"); } } }
從而該函數(shù)可以訪問(wèn)document及該元素本身的任何成員。這也是為什么“采用這種方式指定的事件處理程序中的代碼在執(zhí)行時(shí),有權(quán)訪問(wèn)全局作用域中的任何代碼?!?,因?yàn)樽饔糜蛑杏?b>document。
取消事件默認(rèn)行為的方法實(shí)質(zhì)上就是讓動(dòng)態(tài)創(chuàng)建的函數(shù)return false,所以要這樣寫:
baidu
或
baidu
第二種方式一定要注意,return false是加在onclick屬性值里面的,如果放到show()里是不起作用的哦,因?yàn)槭且?strong>讓動(dòng)態(tài)創(chuàng)建的函數(shù)return false”
3個(gè)缺點(diǎn)時(shí)差問(wèn)題
用戶可能會(huì)在HTML元素一出現(xiàn)就在頁(yè)面上觸發(fā)相應(yīng)的事件,但當(dāng)時(shí)的事件處理程序有可能尚不具備執(zhí)行的條件,從而引發(fā)錯(cuò)誤。比如上面的show()函數(shù),如果用戶單擊按鈕的時(shí)候,function show(){}還沒(méi)有執(zhí)行,就會(huì)導(dǎo)致錯(cuò)誤。
這樣擴(kuò)展事件處理程序的作用域鏈在不同的瀏覽器中會(huì)導(dǎo)致不同的結(jié)果。
HTML與JavaScript代碼緊密耦合,所以實(shí)際中這種方法使用的比較少。
JavaScript指定事件處理程序JavaScript指定事件處理程序主要有兩種方式:DOM0 級(jí)事件處理程序、DOM2 級(jí)事件處理程序。使用JavaScript指定事件處理程序,首先必須取得對(duì)一個(gè)操作對(duì)象的引用。
DOM0 級(jí)事件處理程序每個(gè)元素(包括window和document)都有自己的事件處理程序?qū)傩?,這些屬性通常全部小寫,如onclick,將這種屬性賦值為一個(gè)函數(shù),就是DOM0 級(jí)事件處理程序的指定方式。如下:
var btn = document.getElementById("myBtn"); // 取得對(duì)操作對(duì)象的引用 btn.onclick = function () { // 為onclick賦值一個(gè)函數(shù),指定事件處理程序 console.log("hello"); }移除事件處理程序:
btn.onclick = null; // 只需將屬性置空特點(diǎn):
1)添加事件處理程序的代碼只有在運(yùn)行完之后才會(huì)為元素綁定事件處理程序,因此如果該段代碼未執(zhí)行單擊按鈕是沒(méi)有反應(yīng)的。
2)事件處理程序中的this引用當(dāng)前元素,即綁定了該事件的元素。
3)以這種方式添加的事件處理程序會(huì)在事件流的冒泡階段被處理。
4)所有的瀏覽器都支持DOM0 級(jí)事件處理程序。
“DOM2 級(jí)事件處理程序”定義了兩個(gè)方法,用來(lái)指定和刪除事件處理程序:addEventListener() 和 removeEventListener()。這兩個(gè)方法都接受3個(gè)參數(shù):要處理的事件名、作為事件處理程序的函數(shù)、一個(gè)布爾值,這個(gè)布爾值參數(shù)如果為true表示在捕獲階段調(diào)用事件處理程序,為false表示在冒泡階段調(diào)用事件處理程序,一般設(shè)為false。
添加事件處理程序:var btn = document.getElementById("myBtn"); // 取得對(duì)操作對(duì)象的引用 btn.addEventListener("click", function(){ // 注意是 click 哦~ console.log("hello"); }, false);
或
function show() { console.log("hello"); } var btn = document.getElementById("myBtn"); // 取得對(duì)操作對(duì)象的引用 btn.addEventListener("click", show, false);移除事件處理程序:
移除事件處理程序有一個(gè)要求就是:移除時(shí)傳入的參數(shù)必須與添加事件處理程序時(shí)使用相同的參數(shù)。從而通過(guò)addEventListener()添加的匿名函數(shù)將無(wú)法移除。
移除上面第二種方式綁定的事件處理程序代碼:
var btn = document.getElementById("myBtn"); // 取得對(duì)操作對(duì)象的引用 btn.removeEventListener("click", show, false);
要說(shuō)明的是:通過(guò)addEventListener添加的事件處理程序只能通過(guò)removeEventListener()來(lái)移除。
特點(diǎn)1)只有運(yùn)行完addEventListener()才為元素綁定了事件處理程序。
2)事件處理程序中的this引用當(dāng)前元素,即綁定了該事件的元素。
3)通過(guò)設(shè)置第三個(gè)參數(shù)為true或false可以設(shè)定在捕獲階段還是冒泡階段調(diào)用事件處理程序。
4)可以為同一個(gè)元素綁定多個(gè)事件處理程序,綁定的事件處理程序會(huì)按照它們添加的先后順序依次觸發(fā)。這是DOM0 級(jí)事件處理程序不支持的哦~ DOM0 級(jí)只能添加一個(gè)事件處理程序,后添加的會(huì)覆蓋先添加的。
5)IE9、Firefox、Safari、Chrome和Opera都支持DOM2 級(jí)事件處理程序。
上面特地加粗了IE9,那么IE8及以前版本怎么辦呢?IE實(shí)現(xiàn)了與DOM中類似的兩個(gè)方法:attachEvent()和detachEvent()。這兩個(gè)方法僅接受兩個(gè)參數(shù):事件處理程序名稱和事件處理程序函數(shù)。IE8及之前版本僅支持事件冒泡,所以通過(guò)attachEvent()添加的事件處理程序會(huì)在冒泡階段調(diào)用。
注:IE10及之前版本支持attachEvent()和detachEvent()方法,IE11不再支持,一般IE9及以上都使用DOM方法,這兩個(gè)方法僅對(duì)IE8及以下版本使用。
添加事件處理程序:var btn = document.getElementById("myBtn"); btn.attachEvent("onclick", function () { // 注意這里是 onclick 哦~ console.log("hello"); });
或
function show() { console.log("hello"); } var btn = document.getElementById("myBtn"); btn.attachEvent("onclick", show);移除事件處理程序:
使用detachEvent移除事件處理程序的條件與DOM方法相同——必須提供相同的參數(shù),從而添加的匿名函數(shù)也無(wú)法被移除。
var btn = document.getElementById("myBtn"); btn.detachEvent("onclick", show);
1)只有運(yùn)行完attachEvent()才為元素綁定了事件處理程序。
2)事件處理程序會(huì)在全局作用域中運(yùn)行,從而事件處理程序中的this指向全局對(duì)象window。這與之前的都不同哦~所以不能認(rèn)為this始終等于事件目標(biāo),當(dāng)使用attachEvent()的時(shí)候,this是window,不過(guò)其他時(shí)候,this是等于事件目標(biāo)的~
3)可以為同一個(gè)元素綁定多個(gè)事件處理程序,綁定的事件處理程序會(huì)按照它們添加順序的相反次序被觸發(fā),即先添加后執(zhí)行,后添加的先執(zhí)行。
是不是覺(jué)得IE太奇葩呢,如果沒(méi)有IE,前端世界會(huì)和諧很多吧~還好IE9以上都是按照DOM標(biāo)準(zhǔn)來(lái)了,不再我行我素。
事件對(duì)象event這里順便簡(jiǎn)單說(shuō)下事件對(duì)象,對(duì)比來(lái)看,會(huì)更清晰~
前面介紹過(guò)事件對(duì)象,這里不再贅述。
HTML特性指定事件處理程序
事件處理程序中會(huì)有個(gè)局部變量event,這個(gè)event就是事件對(duì)象。
JavaScript指定事件處理程序
無(wú)論指定事件處理程序采用的是DOM0 級(jí)還是DOM2 級(jí)方法,事件對(duì)象都會(huì)作為事件處理程序的參數(shù)傳入到事件處理程序中。
奇葩的IE
在使用DOM0 級(jí)方法添加事件處理程序時(shí),事件對(duì)象作為window對(duì)象的屬性存在,通過(guò)window.event訪問(wèn)。
如果使用attachEvent()添加事件處理程序,事件對(duì)象會(huì)作為參數(shù)傳入到事件處理程序中。
DOM中的事件對(duì)象(兩個(gè)方法)
preventDefault()方法用來(lái)取消事件默認(rèn)行為,stopPropagation()方法用來(lái)阻止事件進(jìn)一步捕獲或冒泡
// 假設(shè)事件對(duì)象傳入給參數(shù)event event.preventDefault(); // 取消事件默認(rèn)行為 event.stopPropagation(); // 阻止事件進(jìn)一步捕獲或冒泡
IE8及以下中的事件對(duì)象(兩個(gè)屬性)
returnValue屬性用來(lái)設(shè)置事件的默認(rèn)行為。默認(rèn)值為true,當(dāng)設(shè)置為false時(shí),就會(huì)取消事件的默認(rèn)行為。
cancelBubble屬性用來(lái)取消事件冒泡。默認(rèn)值為false,當(dāng)設(shè)置為true時(shí),就會(huì)阻止事件冒泡。
event.returnValue = false; // 取消事件的默認(rèn)行為 event.cancelBubble = true; // 阻止事件冒泡
注:這兩個(gè)屬性僅IE8及以下版本支持,IE9+使用這兩個(gè)屬性會(huì)報(bào)錯(cuò)。
終于寫完了,這篇寫得時(shí)間好長(zhǎng)……這樣整理完知識(shí)脈絡(luò)會(huì)清晰一點(diǎn)吧~
本文主要參考《js高級(jí)程序設(shè)計(jì)》事件一章。如有不妥之處,還請(qǐng)指正。謝謝!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/91516.html
摘要:指定事件處理程序指定事件處理程序主要有兩種方式級(jí)事件處理程序級(jí)事件處理程序。添加事件處理程序注意這里是哦或移除事件處理程序使用移除事件處理程序的條件與方法相同必須提供相同的參數(shù),從而添加的匿名函數(shù)也無(wú)法被移除。 今天看書又看到事件,遂決定小總結(jié)一下~ JavaScript與HTML之間的交互是通過(guò)事件實(shí)現(xiàn)的。事件,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特定的交互瞬間??梢允褂帽O(jiān)聽器(事件處...
摘要:說(shuō)明本文主要學(xué)習(xí)下的模型觀察者,把一點(diǎn)點(diǎn)經(jīng)驗(yàn)分享出來(lái)希望對(duì)別人能有幫助。模型觀察者這個(gè)功能能做很多事情,比如模型更新時(shí)發(fā)個(gè)通知。總結(jié)本篇文章主要學(xué)了下的模型觀察者,發(fā)現(xiàn)這個(gè)功能也能使代碼結(jié)構(gòu)更清晰,覺(jué)得挺好的。 說(shuō)明:本文主要學(xué)習(xí)下Laravel的Model Observer模型觀察者,把一點(diǎn)點(diǎn)經(jīng)驗(yàn)分享出來(lái)希望對(duì)別人能有幫助。同時(shí),作者會(huì)將開發(fā)過(guò)程中的一些截圖和代碼黏上去,提高閱讀效率...
摘要:與不同的是,應(yīng)該以發(fā)送的數(shù)據(jù)作為請(qǐng)求的主體。有了這些不同的事件支持,開發(fā)者可以免去檢查之類的工作,更加的方便。其中事件和事件比較重要。而事件則會(huì)為在瀏覽器接收數(shù)據(jù)期間周期性地觸發(fā)。 在上篇筆記中,我們主要談了一些概述和跨域的問(wèn)題,這一次我們聊聊請(qǐng)求和響應(yīng)的具體內(nèi)容。 向服務(wù)器發(fā)起請(qǐng)求 我們?cè)趧?chuàng)建了XHR對(duì)象后,接著需要用兩個(gè)方法來(lái)發(fā)送請(qǐng)求:open()和send(),這兩個(gè)方法有點(diǎn)像賽...
摘要:原文地址一個(gè)非常適合入門學(xué)習(xí)的博客項(xiàng)目前端掘金一個(gè)非常適合入門學(xué)習(xí)的項(xiàng)目,代碼清晰結(jié)構(gòu)合理新聞前端掘金介紹一個(gè)由編寫的新聞。深入淺出讀書筆記知乎專欄前端專欄前端掘金去年的一篇老文章,恰好今天專欄開通,遷移過(guò)來(lái)。 破解前端面試(80% 應(yīng)聘者不及格系列):從閉包說(shuō)起 - 掘金修訂說(shuō)明:發(fā)布《80% 應(yīng)聘者都不及格的 JS 面試題》之后,全網(wǎng)閱讀量超過(guò) 6W,在知乎、掘金、cnodejs ...
摘要:原文地址一個(gè)非常適合入門學(xué)習(xí)的博客項(xiàng)目前端掘金一個(gè)非常適合入門學(xué)習(xí)的項(xiàng)目,代碼清晰結(jié)構(gòu)合理新聞前端掘金介紹一個(gè)由編寫的新聞。深入淺出讀書筆記知乎專欄前端專欄前端掘金去年的一篇老文章,恰好今天專欄開通,遷移過(guò)來(lái)。 破解前端面試(80% 應(yīng)聘者不及格系列):從閉包說(shuō)起 - 掘金修訂說(shuō)明:發(fā)布《80% 應(yīng)聘者都不及格的 JS 面試題》之后,全網(wǎng)閱讀量超過(guò) 6W,在知乎、掘金、cnodejs ...
閱讀 2361·2021-11-24 11:16
閱讀 2047·2021-09-30 09:47
閱讀 2019·2021-09-10 10:51
閱讀 1330·2019-08-30 14:08
閱讀 3149·2019-08-30 13:47
閱讀 1536·2019-08-30 13:02
閱讀 3240·2019-08-29 12:29
閱讀 3212·2019-08-26 17:05