DOM监听事件详解

DOM监听事件详解

事件定义

​ 事件并不是代码世界里的专用词,它仅仅是由简单的:监听、变化、通知 三要素组成

​ 在前端世界中,事件可以定义为:代码监听(用户),(用户)操作产生变化、(程序员)得到通知。

DOM事件

如何监听事件

DOM level 0 事件监听方法: button.onclick = function(){}

这种方法是DOM level0就支持一种方法。可以用作简单的监听。这个方法存在一个很大的问题。那就是如果一个元素绑定事件时,有可能覆盖掉前面已经绑定好的事件。

DOM level 2 事件监听方法: button.addEventListener('click', function(){})

这种方法和level 0的绑定方法是一致 ,但监听事件每次都会生产一个全新的匿名函数,和前面的函数完全不同,不会覆盖掉前面已经绑定好的时间。

事件类型

Google: DOM events MDN

事件机制:冒泡 & 捕获

监听事件中。子元素被点击,意味着父元素也被点击了。如果同时监听子元素和父元素,就会有个通知的先后顺序

冒泡阶段(默认使用)

事件从事件目标(target)开始,往上冒泡直到页面的最上一级标签。

简单来说:就是child 先通知,parent后通知

如果想阻止事件冒泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来阻止事件的冒泡传播。

捕获阶段

相反的,事件从最上一级标签开始往下查找,直到捕获到事件目标(target)。

简单来说:就是parent 先通知,child 后通知


可以通过改变addEventListener的第三个参数改变事件的执行顺序。(false为冒泡阶段执行,true为捕获阶段执行,留空则为false)

事件传入属性

事件传入属性:event,它传入了事件触发的属性


event.addEventListener('eventType',function(e){

    console.log(e)
}

如何阻止事件:

e.prevenDefault(): 阻止默认事件,可以在容器上阻止但不推荐

e.stopPropagation(): 阻止冒泡事件

使用原生 JS 实现事件委托

基础:一个元素的父元素绑定了监听事件,而本身没有绑定监听事件。如果该元素被点击,也会触发父元素的监听事件

让我们举个例子:

这是一个ul,里面有4个li

    <ul id="ul">
        <li id="li1">1</li>
        <li id="li2">2</li>
        <li id="li3">3</li>
        <li id="li4">4</li>
    </ul>

现在要给每个li绑定一个监听事件

li1.addEventListener('click', function() {})
li2.addEventListener('click', function() {})
li3.addEventListener('click', function() {})
li4.addEventListener('click', function() {})

如果执行的函数都一样,且li个数很多,这就显得非常麻烦了。尤其是li个数不确定的时候,此时我们新增一个li,很显然,新增的li并没有绑定监听事件。

addButton.onclick = function(){
  var li = document.createElement('li')
  li.textContent = 'new'  
  document.querySelector('ul').appendChild(li)
}
//新增了li,但没有自动绑定监听事件

但是,在此例子中,如果点击了li,这个时候不也等于点击了ul吗?(参考上述基础)

因此可以直接把点击事件绑定在ul上

var ul = document.getElementById('ul')
ul.addEventListener('click', function() {})

那么是否就可以简单的监听父元素从而达到监听子元素的目的呢?

这是不对的。如果给ul添加个padding。

可以看出,当点击padding部分,也是会触发事件的。原因是我们监听的是ul。

所以这种绑定法,是有bug的,这明显不是我们想要的结果,于是我们可以给事件添加一个判断:

判断一下点击的目标,如果点的是li就触发,不然就不触发。

        ul.addEventListener('click', function(e) {
                    // 检查事件源e.targe是否为Li
                    if (e.target && e.target.nodeName.toUpperCase == "LI") {
                          console.log("点击成功");
                    }
                }

​ 这里就要科普一下用到上面所说的事件传入属性,其中:

​ target:触发该事件时点击的元素

​ currentTarget:触发该事件时监听的元素

那么,还有什么bug吗?有的!

尝试给li加个span试试:

    <ul id="ul">
        <li id="li1"><span>1</span></li>  //给第一个li加一个span
        <li id="li2">2</li>
        <li id="li3">3</li>
        <li id="li4">4</li>
    </ul>

此时发现点击第一个li已经不触发绑定事件了。

虽然前面说道,监听父元素就能达到监听子元素的目的。

但是我们为了修复 ‘padding’ 的bug,添加了一个标签判断,导致 ‘span’ 不会触发绑定事件

if (e.target && e.target.nodeName.toUpperCase == "LI") 

我们必须考虑,li是否还有后代元素。这时候我们就应该先判断点击的元素的祖先元素当中有没有li,如果有li,那点击的还是li。

所以,最后写出的事件委托函数优化如下

ul.addEventListener('click', function() {
                    let el = e.target  \\获得实际点击的元素
                    \\以下while判定点击元素el的祖先元素是否有Li
                    while (el && !el.matches(selector)) {
                        el = el.parentNode
                        if (element === el) {
                            el = null
                        }
                    }
                    if (el) {
                        console.log('执行回调函数')
                    }
                }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • (续jQuery基础(1)) 第5章 DOM节点的复制与替换 (1)DOM拷贝clone() 克隆节点是DOM的常...
    凛0_0阅读 1,316评论 0 8
  • 总结: 鼠标事件 1.click与dbclick事件$ele.click()$ele.click(handler(...
    阿r阿r阅读 1,593评论 2 10
  • 第1章 鼠标事件 1-1 jQuery鼠标事件之click与dbclick事件 用交互操作中,最简单直接的操作就是...
    mo默22阅读 1,258评论 0 6
  • 醒来,已然发现是9点,空间里好友发动态说海口微震,东北白雪飘飘,外面的世界好冷,可是为什么在室内,在被窝的自己还是...
    Mosquito_阅读 559评论 4 3
  • 刚进入007-14班时,看到班群里每天那么多留言,我顿时懵了:每天24小时,睡觉8小时,上班加路途8小时,瑜伽康复...
    游游老师阅读 170评论 1 7