亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

深入分析原生JavaScript事件

2019-11-20 13:34:28
字體:
來源:轉載
供稿:網友

 JQuery這種Write Less Do More的框架,用多了難免會對原生js眼高手低。

     小菜其實不想寫這篇博客,貌似很初級的樣子,但是看到網絡上連原生js事件綁定和解除都說不明白,還是決定科普一下了。

     首先聲明,小菜懂的也不是很多,只是把我的思路和大家分享一下。

DOM0事件模型

     事件模型在不斷發展,早期的事件模型稱為DOM0級別。

     DOM0事件模型,所有的瀏覽器都支持。

     直接在dom對象上注冊事件名稱,就是DOM0寫法,比如:

復制代碼 代碼如下:

document.getElementById("test").onclick = function(e){};

     意思就是注冊一個onclick事件。當然,它和這種寫法是一個意思:

復制代碼 代碼如下:

document.getElementById("test")["onmousemove"] = function(e){};

     這沒什么,只不過是兩種訪問js對象屬性的方法,[]的形式主要是為了解決屬性名不是合法的標識符,比如:object.123肯定報錯,但是object["123"]就避免了這個問題,與此同時,[]的寫法,也把js寫活了,用字符串表示屬性名稱,可以在運行時動態綁定事件。

     言歸正傳,事件被觸發時,會默認傳入一個參數e,表示事件對象,通過e,我們可以獲取很多有用的信息,比如點擊的坐標、具體觸發該事件的dom元素等等。

     基于DOM0的事件,對于同一個dom節點而言,只能注冊一個,后邊注冊的同種事件會覆蓋之前注冊的。例如:

復制代碼 代碼如下:

 var btn = document.getElementById("test");
 btn.onmousemove = function(e){
   alert("ok");
 };
 btn["onmousemove"] = function(e){
   alert("ok1");
 };

     結果會輸出ok1。

     接下來再說說this。事件觸發時,this就是指該事件在哪個dom對象上觸發。例如:

復制代碼 代碼如下:

 var btn = document.getElementById("test");
 btn.onmousemove = function(e){
   alert(this.id);
 };

     結果輸出test。因為事件就是在id為test的dom節點上注冊的,事件觸發時,this當然代表這個dom節點,可以理解為事件是被這個dom節點調用的。

     所以,想解除事件就相當簡單了,只需要再注冊一次事件,把值設成null,例如:

復制代碼 代碼如下:

 var btn = document.getElementById("test");
 btn.onclick = function(e){
   alert("ok");
 };
 btn.onclick = null;

     原理就是最后注冊的事件要覆蓋之前的,最后一次注冊事件設置成null,也就解除了事件綁定。

     事情還沒結束,DOM0事件模型還涉及到直接寫在html中的事件。例如:

復制代碼 代碼如下:

<div id="test" class="test" onclick="exec();" ></div>

     通過這種方式注冊的事件,同樣遵循覆蓋原則,同樣只能注冊一個,最后一個生效。

     區別就是,這樣注冊的事件,相當于動態調用函數(有點eval的意思),因此不會傳入event對象,同時,this指向的是window,不再是觸發事件的dom對象。

DOM2事件模型

     DOM2事件模型相對于DOM0,小菜僅僅了解如下兩點:

          ?  DOM2支持同一dom元素注冊多個同種事件。

          ?  DOM2新增了捕獲和冒泡的概念。

     DOM2事件通過addEventListener和removeEventListener管理,當然,這是標準。

     但IE8及其以下版本瀏覽器,自娛自樂,搞出了對應的attachEvent和detachEvent,由于小菜才疏學淺,本文不做討論。

     addEventListener當然就是注冊事件,她有三個參數,分別為:"事件名稱", "事件回調", "捕獲/冒泡"。舉個例子:

復制代碼 代碼如下:

 var btn = document.getElementById("test");
 btn.addEventListener("click", function(e){
   alert("ok");
 }, false);

     事件名稱就不用多說了,相比DOM0,去掉了前邊的on而已。

     事件回調也很好理解,事件觸發了總得通知你吧!回調時和DOM0一樣,也會默認傳入一個event參數,同時this是指觸發該事件的dom節點。

     最后一個參數是布爾型,true代表捕獲事件,false代表冒泡事件。其實很好理解,先來個示意圖:

     意思就是說,某個元素觸發了某個事件,最先得到通知的是window,然后是document,依次而入,直到真正觸發事件的那個元素(目標元素)為止,這個過程就是捕獲。接下來,事件會從目標元素開始起泡,再依次而出,直到window對象為止,這個過程就是冒泡。

     為什么要這樣設計呢?這貌似是由于深厚的歷史淵源,小菜也不怎么了解,就不亂說了。

     由此可以看出,捕獲事件要比冒泡事件先觸發。

     假設有這樣的html結構:

復制代碼 代碼如下:

 <div id="test" class="test">
   <div id="testInner" class="test-inner"></div>
 </div>

     然后我們在外層div上注冊兩個click事件,分別是捕獲事件和冒泡事件,代碼如下:

復制代碼 代碼如下:

 var btn = document.getElementById("test");
 //捕獲事件
 btn.addEventListener("click", function(e){
   alert("ok1");
 }, true);
 //冒泡事件
 btn.addEventListener("click", function(e){
   alert("ok");
 }, false);

     最后,點擊內層的div,先彈出ok1,后彈出ok。結合上邊的原理圖,外層div相當于圖中的body,內層div相當于圖中最下邊的div,證明了捕獲事件先執行,然后執行冒泡事件。

     為什么要強調點擊內層的div呢?因為真正觸發事件的dom元素,必須是內層的,外層dom元素才有機會模擬捕獲事件和冒泡事件,從原理圖上就看出了。

     如果在真正觸發事件的dom元素上注冊捕獲事件和冒泡事件呢?

     html結構同上,js代碼如下:

復制代碼 代碼如下:

 var btnInner = document.getElementById("testInner");
 //冒泡事件
 btnInner.addEventListener("click", function(e){
   alert("ok");
 }, false);
 //捕獲事件
 btnInner.addEventListener("click", function(e){
   alert("ok1");
 }, true);

     當然還是點擊內層div,結果是先彈出ok,再彈出ok1。理論上應該先觸發捕獲事件,也就是先彈出ok1,但是這里比較特殊,因為我們是在真正觸發事件的dom元素上注冊的事件,相當于在圖中的div上注冊,由圖可以看出真正觸發事件的dom元素,是捕獲事件的終點,是冒泡事件的起點,所以這里就不區分事件了,哪個先注冊,就先執行哪個。本例中,冒泡事件先注冊,所以先執行。

     這個道理適用于多個同種事件,比如說一下子注冊了3個冒泡事件,那么執行順序就按照注冊的順序來,先注冊先執行。例如:

復制代碼 代碼如下:

 var btnInner = document.getElementById("testInner");
 btnInner.addEventListener("click", function(e){
   alert("ok");
 }, false);
 btnInner.addEventListener("click", function(e){
   alert("ok1");
 }, false);
 btnInner.addEventListener("click", function(e){
   alert("ok2");
 }, false);

     結果當然是依次彈出ok、ok1、ok2。

     為了進一步理解事件模型,還有一種場景,假如說外層div和內層div同時注冊了捕獲事件,那么點擊內層div時,外層div的事件一定是先觸發的,代碼如下:

復制代碼 代碼如下:

 var btn = document.getElementById("test");
 var btnInner = document.getElementById("testInner");
 btnInner.addEventListener("click", function(e){
   alert("ok");
 }, true);
 btn.addEventListener("click", function(e){
   alert("ok1");
 }, true);

     結果是先彈出ok1。

     假如外層div和內層div都是注冊的冒泡事件,點擊內層div時,一定是內層div事件先執行,原理相同。

     細心的讀者會發現,對于div嵌套的情況,如果點擊內層的div,外層的div也會觸發事件,這貌似會有問題!

     點擊的明明是內層div,但是外層div的事件也觸發了,這的確是個問題。

     其實,事件觸發時,會默認傳入一個event對象,前邊提過了,這個event對象上有一個方法:stopPropagation,通過此方法,可以阻止冒泡,這樣外層div就接收不到事件了。代碼如下:

復制代碼 代碼如下:

 var btn = document.getElementById("test");
 var btnInner = document.getElementById("testInner");
 btn.addEventListener("click", function(e){
   alert("ok1");
 }, false);
 btnInner.addEventListener("click", function(e){
   //阻止冒泡
 e.stopPropagation();
   alert("ok");
 }, false);

     終于要說說怎么解除事件了。解除事件語法:btn.removeEventListener("事件名稱", "事件回調", "捕獲/冒泡");

     這和綁定事件的參數一樣,詳細說明下:

          ?  事件名稱,就是說解除哪個事件唄。

          ?  事件回調,是一個函數,這個函數必須和注冊事件的函數是同一個。

          ?  事件類型,布爾值,這個必須和注冊事件時的類型一致。

     也就是說,名稱、回調、類型,三者共同決定解除哪個事件,缺一不可。舉個例子:

復制代碼 代碼如下:

 var btn = document.getElementById("test");
 //將回調存儲在變量中
 var fn = function(e){
   alert("ok");
 };
 //綁定
 btn.addEventListener("click", fn, false);
 //解除
 btn.removeEventListener("click", fn, false);

     要想注冊過的事件能夠被解除,必須將回調函數保存起來,否則無法解除。

DOM0與DOM2混用

     事情本來就很亂了,這又來個混合使用,還讓不讓人活了。。。

     別怕,混合使用完全沒問題,DOM0模型和DOM2模型各自遵循自己的規則,互不影響。

     整體上來說,依然是哪個先注冊,哪個先執行,其他就沒什么了。

后記

     至此,原生js事件已經講的差不多了,小菜僅僅知道這些而已,歡迎讀者補充其他知識點。

     在實際應用中,真正的行家不會傻傻的真的注冊這么多事件,一般情況下,只需在最外層dom元素注冊一次事件,然后通過捕獲、冒泡機制去找到真正觸發事件的dom元素,最后根據觸發事件的dom元素提供的信息去調用回調。

     也就是說,行家會自己管理事件,而不依賴瀏覽器去管理,這樣即可以提高效率,又保證了兼容性,JQuery不就是這么做的嘛~

     好了,教程到此結束,希望對讀者有所幫助!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美成人在线免费视频| 国产欧美最新羞羞视频在线观看| 亚洲美腿欧美激情另类| 亚洲18私人小影院| 国产精品无av码在线观看| 日韩欧美国产骚| 伊人久久综合97精品| 一级做a爰片久久毛片美女图片| 亚洲精品国产综合区久久久久久久| 国产一区二区在线免费视频| 九九热精品视频在线播放| 亚洲人成电影网站色xx| 亚洲小视频在线观看| 精品国产999| 亚洲国产日韩欧美在线动漫| 日韩免费观看高清| 欧美有码在线视频| 欧美亚洲成人精品| 亚洲人成伊人成综合网久久久| 久久成人综合视频| 久久777国产线看观看精品| 亚洲三级黄色在线观看| 一区二区三欧美| 精品国产一区二区三区四区在线观看| 成人黄色在线观看| 日韩在线播放av| 国产成人精品av在线| 日韩中文字幕不卡视频| 美女性感视频久久久| 亚洲精品aⅴ中文字幕乱码| 国产一区二区黑人欧美xxxx| 国产精品久久久久久久久粉嫩av| 欧美一区二区视频97| 亚洲国产欧美日韩精品| 97超视频免费观看| 在线观看欧美日韩| 日本精品视频在线观看| 奇米影视亚洲狠狠色| 亚州成人av在线| 亚洲欧美中文日韩v在线观看| 欧美成人免费全部观看天天性色| 国产精品亚洲网站| 欧美裸身视频免费观看| 成人xxxx视频| 亚洲第一精品久久忘忧草社区| 久久夜色撩人精品| 国产精品69久久久久| 亚洲成在人线av| 亚洲欧美日韩另类| 亚洲第一网中文字幕| 国内精品一区二区三区四区| 一本一本久久a久久精品牛牛影视| 亚洲精品日韩激情在线电影| 日韩成人性视频| 亚洲一区二区三区视频播放| 国产精品久久中文| 亚洲免费av电影| 亚洲精品国产福利| 亚洲国产一区二区三区在线观看| 色偷偷88888欧美精品久久久| 欧美亚洲午夜视频在线观看| 色婷婷久久av| 91精品国产自产91精品| 日韩欧美一区二区三区久久| 亚洲深夜福利网站| 久久av红桃一区二区小说| 欧美黑人性生活视频| 亚洲国内精品视频| 日韩成人激情影院| 国产一区二区三区久久精品| 91老司机精品视频| 国产丝袜一区二区| 亚洲在线观看视频网站| 国产精品三级久久久久久电影| 亚洲人精选亚洲人成在线| 国产欧美日韩最新| 日韩理论片久久| 日本aⅴ大伊香蕉精品视频| 欧美综合激情网| 成人黄色免费在线观看| 在线精品91av| 国产视频精品免费播放| 欧美一级电影久久| 亚洲欧美成人精品| 97不卡在线视频| 岛国视频午夜一区免费在线观看| 久久亚洲精品成人| 久久亚洲精品一区二区| 欧美日韩福利在线观看| 亚洲国产成人精品久久| 亚洲第一页自拍| 国产精品青草久久久久福利99| 一区二区日韩精品| 国产一区二区黑人欧美xxxx| 欧洲永久精品大片ww免费漫画| 在线激情影院一区| 日韩美女av在线免费观看| 亚洲第一区第二区| 欧美午夜www高清视频| 国产日韩精品一区二区| 日韩亚洲欧美中文高清在线| 一本大道亚洲视频| 韩国视频理论视频久久| 国产日韩精品电影| 91午夜在线播放| 91久久国产婷婷一区二区| 国产视频久久久| 国产精品情侣自拍| 日韩毛片在线观看| 日本一区二三区好的精华液| 国产精品一区二区三区在线播放| 欧美日韩一二三四五区| 国语自产精品视频在线看一大j8| 亚洲在线一区二区| 亚洲国产99精品国自产| 中文字幕日韩欧美在线| 国产一区二区免费| 欧美在线日韩在线| 成人免费视频xnxx.com| 欧美在线观看一区二区三区| 萌白酱国产一区二区| 亚洲成人1234| 欧美综合激情网| 精品国产31久久久久久| 国产成人精彩在线视频九色| 色综合亚洲精品激情狠狠| 日韩视频在线免费观看| 日本精品视频在线观看| 自拍亚洲一区欧美另类| 日韩成人av在线播放| 久久成人国产精品| 亚洲第一精品久久忘忧草社区| 久久久国产精品视频| 久久69精品久久久久久久电影好| 亚洲国产精品成人va在线观看| 最新国产精品拍自在线播放| 欧美国产日韩一区二区三区| 91精品国产综合久久香蕉| 中文字幕国产亚洲2019| 国产精品一区久久久| 欧美日韩国产页| 91在线高清视频| 国产91精品视频在线观看| 欧美大片网站在线观看| 欧美黄色片在线观看| 亚洲国产成人av在线| 992tv成人免费视频| 国产精品免费一区二区三区都可以| www.久久久久久.com| 欧美黑人一级爽快片淫片高清| 欧洲一区二区视频| 91国内产香蕉| 亚洲精品永久免费| 久久最新资源网| 日韩欧中文字幕| 亚洲一区中文字幕在线观看| 国产91九色视频| 在线看片第一页欧美| 国产在线播放91| 97精品免费视频| 91av免费观看91av精品在线| 日韩精品视频三区| 91成人国产在线观看| 久久福利视频导航|