DOM事件的那些事兒

DOM(Document Object Model) 即文檔對(duì)象模型蟀拷,是針對(duì)HTML和XML文檔的一個(gè)API危尿,DOM描繪了一個(gè)層次化的節(jié)點(diǎn)樹示损,允許開發(fā)人員進(jìn)行添加寿弱、移除和修改頁面的某一部分犯眠。

一、DOM事件的級(jí)別

  • DOM0 點(diǎn)擊事件的JS中寫法是: element.onclick=function(){ }症革,如果在HTML中就是onclick屬性上加一個(gè)JS語句筐咧。
    刪除DOM0事件處理程序,只要將對(duì)應(yīng)事件屬性置為null即可噪矛,即element.onclick=null量蕊。
  • DOM2 新增的點(diǎn)擊事件JS中寫法是:element.addEventListener('click', function(){}, false)。最后一個(gè)參數(shù)為true的時(shí)候表示在捕獲階段調(diào)用程序艇挨,如果是false残炮,表示在冒泡階段調(diào)用事件處理程序,不填則默認(rèn)為false缩滨。
    刪除DOM2事件處理程序势就,用removeEventListener實(shí)現(xiàn)。
    IE中的DOM2級(jí)事件處理使用了attachEvent來實(shí)現(xiàn)脉漏,IE9以下版本只支持冒泡事件苞冯,所以attachEvent添加的事件都是冒泡階段。attachEvent添加的事件第一個(gè)參數(shù)是onclick而非標(biāo)準(zhǔn)事件中的click侧巨。使用detachEvent實(shí)現(xiàn)刪除事件舅锄。
  • DOM3 定義方式?jīng)]變,知識(shí)新增了很多事件類型刃泡,包括UI事件巧娱,鼠標(biāo)事件,焦點(diǎn)事件烘贴,滾輪事件等等禁添。如:element.addEventListener('keyup', function(){}, false)

因?yàn)镈OM1主要專注于HTML文檔和XML文檔,沒有涉及事件處理桨踪,所以事件處理直接從DOM0跳到DOM2老翘。

二、DOM事件模型

DOM事件模型分為兩類:一類是IE所使用的冒泡型事件(Bubbling);另一類是DOM標(biāo)準(zhǔn)定義的冒泡型與捕獲型(Capture)的事件铺峭。除IE外的其他瀏覽器都支持標(biāo)準(zhǔn)的DOM事件處理模型墓怀。

DOM事件模型

  • 冒泡型事件處理模型(Bubbling)
    如上圖所示,冒泡型事件處理模型在事件發(fā)生時(shí)卫键,首先在最精確的元素上觸發(fā)傀履,然后向上傳播,直到根節(jié)點(diǎn)莉炉。反映到DOM樹上就是事件從葉子節(jié)點(diǎn)傳播到根節(jié)點(diǎn)钓账。

  • 捕獲型事件處理模型(Captrue)
    相反地,捕獲型在事件發(fā)生時(shí)首先在最頂級(jí)的元素上觸發(fā)絮宁,傳播到最低級(jí)的元素上梆暮。在DOM樹上的表現(xiàn)就是由根節(jié)點(diǎn)傳播到葉子節(jié)點(diǎn)。

  • 標(biāo)準(zhǔn)的DOM事件處理模型
    標(biāo)準(zhǔn)的事件處理模型分為三個(gè)階段:
    (1) 父元素中所有的捕獲型事件(如果有)自上而下地執(zhí)行
    (2) 目標(biāo)元素的冒泡型事件(如果有)
    (3) 父元素中所有的冒泡型事件(如果有)自下而上地執(zhí)行

三绍昂、DOM事件流

DOM標(biāo)準(zhǔn)采用捕獲+冒泡啦粹。兩種事件流都會(huì)觸發(fā)DOM的所有對(duì)象,從document對(duì)象開始窘游,也在document對(duì)象結(jié)束唠椭。


DOM事件流

標(biāo)準(zhǔn)DOM事件流包括三個(gè)階段:事件捕獲階段,處于目標(biāo)階段和事件冒泡階段

  • 事件捕獲階段:實(shí)際目標(biāo)(<div>)在捕獲階段不會(huì)接收事件张峰。也就是在捕獲階段泪蔫,事件從document到<html>再到<body>就停止了。上圖中為1~3喘批。
  • 處于目標(biāo)階段:事件在<div>上發(fā)生并處理。但是事件處理會(huì)被看成是冒泡階段的一部分铣揉。
  • 冒泡階段:事件又傳播回文檔饶深。

四、DOM事件捕獲的具體流程

DOM事件捕獲具體流程

首先接收的是window逛拱,然后是ducument敌厘,再是html標(biāo)簽(js獲取html節(jié)點(diǎn)用document.documentElement),然后是body朽合,最后隨著節(jié)點(diǎn)父子關(guān)系一級(jí)一級(jí)往下傳俱两,直到目標(biāo)元素。
冒泡則相反曹步,從目標(biāo)元素到window一級(jí)一級(jí)往上宪彩。
通過代碼來描述事件捕獲過程:

<div id="ev"  style='width:100px;height: 100px;background: blue'></div>
// 把打印順序攪亂,以免誤以為是因?yàn)閳?zhí)行順序影響
<script>
        var ev = document.getElementById('ev');

        ev.addEventListener('click', function (e) {
            console.log('ev captrue');
        }, true);

        window.addEventListener('click', function (e) {
            console.log('window captrue');
        }, true);

        document.addEventListener('click', function (e) {
            console.log('document captrue');
        }, true);

        document.body.addEventListener('click', function (e) {
            console.log('body captrue');
        }, true);

        document.documentElement.addEventListener('click', function (e) {
            console.log('html captrue');
        }, true);

        // 打印結(jié)果如下:
       // window captrue
       // document captrue
      // html captrue
      // body captrue
      // ev captrue

</script>

通過代碼來描述事件冒泡過程:

<div id="ev"  style='width:100px;height: 100px;background: blue'></div>
// 把打印順序攪亂讲婚,以免誤以為是因?yàn)閳?zhí)行順序影響
<script>
        var ev = document.getElementById('ev');

        ev.addEventListener('click', function (e) {
            console.log('ev captrue');
        }, false);

        window.addEventListener('click', function (e) {
            console.log('window captrue');
        }, false);

        document.addEventListener('click', function (e) {
            console.log('document captrue');
        }, false);

        document.body.addEventListener('click', function (e) {
            console.log('body captrue');
        }, false);

        document.documentElement.addEventListener('click', function (e) {
            console.log('html captrue');
        }, false);

        // 打印結(jié)果如下:
        // ev captrue
        // body captrue
        // html captrue
        // document captrue
       // window captrue
</script>

五尿孔、Event對(duì)象的常見應(yīng)用

  • event.preventDefault():阻止默認(rèn)行為。常用的情況就是給一個(gè)<a>標(biāo)簽綁定了click事件,響應(yīng)函數(shù)中設(shè)置了 event.preventDefault()活合,就阻止了鏈接跳轉(zhuǎn)的行為雏婶。
  • event.stopPropagation():阻止冒泡行為。比如:一個(gè)父級(jí)元素綁定了一個(gè)事件白指,子元素綁定了另一個(gè)事件留晚,如果想父級(jí)元素做一件事,子元素做一件事告嘲,兩件事是分開的错维,互不影響,就需要給子元素事件中設(shè)置event.stopPropagation()状蜗,否則子元素事件執(zhí)行時(shí)需五,按照冒泡的原則,父級(jí)元素事件也會(huì)響應(yīng)轧坎。
  • event.stopImmediatePropagation:除了該事件的冒泡行為被阻止之外(event.stopPropagation方法的作用)宏邮,該元素綁定的后序相同類型事件的監(jiān)聽函數(shù)的執(zhí)行也將被阻止。如一個(gè)元素上綁定了2個(gè)click事件a和b缸血,如果給a函數(shù)中添加event.stopImmediatePropagation后蜜氨,則阻止click事件冒泡,并且阻止了b函數(shù)的執(zhí)行捎泻。
  • event.currentTarget:當(dāng)事件遍歷DOM時(shí)飒炎,標(biāo)識(shí)事件的當(dāng)前目標(biāo)(類似于this)。如下例子:
    <p>1</p>
    <p>2</p>
    <p>3</p>
    <script>
        var ps = document.getElementsByTagName('p');
        for (var i = 0; i < ps.length; i++) {
            ps[i].addEventListener('click', func, false);
        }

        function func(e) {
            console.log(e.currentTarget);  // 打印所點(diǎn)擊對(duì)應(yīng)的<p>節(jié)點(diǎn)
            // 該函數(shù)用作事件處理器時(shí): this === e.currentTarget
        }
    </script>
  • event.target:表示一個(gè)觸發(fā)事件的對(duì)象的引用笆豁,常用來實(shí)現(xiàn)事件委托郎汪。如:
<ul id="ul">
   <li>1</li>
   <li>2</li>
   <li>3</li>
</ul>

    <script>
        document.getElementById("ul").addEventListener('click', function(){
              console.log(event.target);   // 當(dāng)點(diǎn)擊1時(shí),打印<li>1</li>
              console.log(event.currentTarget);  // 當(dāng)點(diǎn)擊1或2或3時(shí)闯狱,都打印整個(gè)<ul>
        });
    </script>

六煞赢、自定義事件

以上所講都是DOM一些自帶的事件,當(dāng)然也可以自己定義一些事件哄孤。

  • ① 自定義一個(gè)事件:new Event()
  • ② 給一個(gè)dom節(jié)點(diǎn)綁定自定義的事件
  • ③ 使用dispatchEvent() 分派事件
<div id="ev"></div>

<script>
var ev = document.getElementById('ev');
var evt = new Event('test');
ev.addEventListener('test', function () {
    console.log('test dispatch');
});
setTimeout(function () {
    ev.dispatchEvent(evt);
}, 3000);

// 打開頁面3面后打印 'test dispatch'
</script>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末照筑,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子瘦陈,更是在濱河造成了極大的恐慌凝危,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,002評(píng)論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晨逝,死亡現(xiàn)場(chǎng)離奇詭異蛾默,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)咏花,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門趴生,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阀趴,“玉大人,你說我怎么就攤上這事苍匆×跫保” “怎么了?”我有些...
    開封第一講書人閱讀 169,787評(píng)論 0 365
  • 文/不壞的土叔 我叫張陵浸踩,是天一觀的道長叔汁。 經(jīng)常有香客問我,道長检碗,這世上最難降的妖魔是什么据块? 我笑而不...
    開封第一講書人閱讀 60,237評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮折剃,結(jié)果婚禮上另假,老公的妹妹穿的比我還像新娘。我一直安慰自己怕犁,他們只是感情好边篮,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,237評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奏甫,像睡著了一般戈轿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上阵子,一...
    開封第一講書人閱讀 52,821評(píng)論 1 314
  • 那天思杯,我揣著相機(jī)與錄音,去河邊找鬼挠进。 笑死色乾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的领突。 我是一名探鬼主播杈湾,決...
    沈念sama閱讀 41,236評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼攘须!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起殴泰,我...
    開封第一講書人閱讀 40,196評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤于宙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后悍汛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捞魁,經(jīng)...
    沈念sama閱讀 46,716評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,794評(píng)論 3 343
  • 正文 我和宋清朗相戀三年离咐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谱俭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奉件。...
    茶點(diǎn)故事閱讀 40,928評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖昆著,靈堂內(nèi)的尸體忽然破棺而出县貌,到底是詐尸還是另有隱情,我是刑警寧澤凑懂,帶...
    沈念sama閱讀 36,583評(píng)論 5 351
  • 正文 年R本政府宣布煤痕,位于F島的核電站,受9級(jí)特大地震影響接谨,放射性物質(zhì)發(fā)生泄漏摆碉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,264評(píng)論 3 336
  • 文/蒙蒙 一脓豪、第九天 我趴在偏房一處隱蔽的房頂上張望巷帝。 院中可真熱鬧,春花似錦扫夜、人聲如沸楞泼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽现拒。三九已至,卻和暖如春望侈,著一層夾襖步出監(jiān)牢的瞬間印蔬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評(píng)論 1 274
  • 我被黑心中介騙來泰國打工脱衙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留侥猬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,378評(píng)論 3 379
  • 正文 我出身青樓捐韩,卻偏偏與公主長得像退唠,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子荤胁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,937評(píng)論 2 361

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