JavaScript学习笔记(2)DOM 事件流&&事件处理程序&&事件代理

定义:

  • 事件:用户或浏览器自身执行的某种动作。(click,load,mouseover)
  • 事件流:从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序。
  • 事件处理程序:响应某个事件的函数。均以on开头。(onclick,onmouseover等)

1.事件流

事件流分成两种:事件冒泡和事件捕获:

  • IE的事件流叫做事件冒泡,即事件开始时由最具体的元素接受,然后逐级向上传播到较为不具体的节点。
  • 事件捕获的思想恰恰相反:不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。(在事件达到预定目标之前捕获它)

DOM事件流

“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段,处于目标阶段和事件冒泡阶段。首先发生的是事件捕获阶段,为截获事件提供了机会。然后是实际的目标接收事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件作出相应。

图片来源于网络

以上图为例,单击div会按照图上显示的顺序触发事件。

浏览器支持

  • IE9,safari,chrome等目前均支持事件捕获的事件流类型,这些浏览器都是从windows对象开始捕获事件的。
  • 大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容浏览器。(IE8及更早版本不支持时间捕获)如果不是特别需要,不建议在事件捕获阶段注册事件处理程序。
  • IE9,Opera,Firefox,Chrome 和 Safari都支持DOM事件流,IE8及更早版本不支持DOM事件流。

例子

addEventListener

在写例子之前,先简单介绍一个方法:addEventListener

  • 该方法是‘DOM2级事件处理程序’的方法,它接受三个参数:要处理的事件名,作为事件处理程序的函数和一个布尔值
    • 布尔值为false代表在冒泡阶段调用事件处理程序,true代表在捕获阶段调用事件处理程序
  • 比如:btn.addEventListener("click",function(){alert("Hello world")},false) 就代表给按钮btn注册一个事件,当被点击时浏览器会弹出消息“Hello World”,并且在冒泡阶段调用click。
比较事件冒泡和事件捕获

接下来就用addEventListener来展示事件冒泡和事件捕获的区别:
先放上html 和 css 代码:

<div id="level1">
    <div id="level2">
        <div id="level3"></div>
    </div>
</div>
#level1{
    background:red;
    height:200px;
    width:200px;
}
    
#level2{
    background:orange;
    height:100px;
    width:100px;
}
    
#level3{
    background:yellow;
    height:50px;
    width:50px;
}

呈现的效果很简单,就是三个不同颜色的div块:


事件流对比.png

然后用JS给每一个div注册一个点击事件,为了更加直观,当每一个div的点击事件被触发时,会显示一条该div块背景颜色的消息,这样我们就能清楚地看到各个div的click事件被触发的先后顺序

var level1=document.getElementById('level1');
var level2=document.getElementById('level2');
var level3=document.getElementById('level3');

level.addEventListener('click',function(){
    alert('yellow');
},false);

leve2.addEventListener('click',function(){
    alert('orange');
},false);

leve3.addEventListener('click',function(){
    alert('red');
},false);

根据上面的例子,addEventListener的布尔值参数被设置为false,所以会在冒泡阶段调用事件处理程序。当点击黄色方块后,会先后弹出消息"yellow","orange","red";点击橙色方块后,会弹出消息"orange","red";点击红色方块后,会弹出"red".这个结果也印证了我们之前所说的事件冒泡会使事件开始时由最具体的元素接受,然后逐级向上传播到较为不具体的节点。这里的黄色方块是嵌套在最里面的div块,所以是该例子中最具体的节点,红色块是最外层的div快,在该例中是最不具体的节点。

接着我们再测试一下用事件捕获的思想会获得什么结果:
html和css代码都不需要变动,只需要对JS代码稍作修改:把布尔值从false改成true.

var level1=document.getElementById('level1');
var level2=document.getElementById('level2');
var level3=document.getElementById('level3');

level.addEventListener('click',function(){
    alert('yellow');
},true);

leve2.addEventListener('click',function(){
    alert('orange');
},true);

leve3.addEventListener('click',function(){
    alert('red');
},true);

结果还是和我们预想的一样,当点击黄色方块后,会先后弹出消息"red","orange","yellow";当点击橙色方块后,会先后弹出消息"red","orange";点击红色方块时仍然只有"red".结果和上例恰好相反。

从上述两个例子,我们可以清晰地看出事件冒泡和事件捕获两种事件流的区别。

事件处理程序

4种为事件指定处理程序的方式:
  • HTML 事件处理程序:
    <input type="button" value="click" onclick="showMsg()"/>
    function showMsg(){
        alert("hello world");
    }
  • DOM0级事件处理程序:
    btn.onclick=function(){
        alert("hello world");
    };
  • DOM2级事件处理程序:
    btn.addEventListener("click",function(){},false); //事件冒泡
    btn.addEventListener("click",function(){},true); //事件捕获
  • IE事件处理程序
    • 通过attachEvent()添加的事件处理程序会被添加到冒泡阶段。
    • 使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此this等于window。
    btn.attachEvent("onclick",function(){
        alert("hello world");
    });

事件代理(event delegation)

定义

事件代理允许我们需要为很多元素添加事件的时候,可以将事件添加到它们的父节点而将事件委托给父节点来触发处理函数,这得益于事件冒泡机制。

举例

html 代码如下:

<ul id="parent">
  <li id="child1">item1</li>
  <li id="child2">item2</li>
  <li id="child3">item3</li>
  <li id="child4">item4</li>
  <li id="child5">item5</li>
</ul>

Javascript代码如下:

var parent=document.getElementById("parent");
parent.addEventListener("click",function(event){
    if(event.target&&event.target.nodeName=="LI"){
    alert("list item "+event.target.id+" was clicked");
  }
});

这里我们假设需要为每一个Li节点添加一个点击事件,如果依次添加,尤其是如果你需要在程序内不同的地方添加和删除点击事件,那么就会非常麻烦。其中一个解决方法便是将点击事件添加到LI节点的父元素UL节点上,如上述代码所示,当事件冒泡到父节点以后,通过target属性可以得知哪一个LI节点被点击了,从而进行相应的处理。此例只是将获取的LI元素的ID显示出来了。

jQuery中的delegate()

delegate()方法为指定的元素(被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数,该方法有四个参数,分别是选择器,事件类型,传递到函数的数据,函数,传递到函数的数据可以选填。

举例

还是上面那个例子,html代码不变,jQuery代码如下:

    $("#parent").delegate("li","click",function(){
        $(this).after("clicked");
    })

为什么要用事件代理?

事件代理只需要在父元素绑定一次所需事件,而不需要在子元素上绑定多次,从而大大提升了性能,也提升了编码效率。

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容

  • 以下文章为转载,对理解JavaScript中的事件处理机制很有帮助,浅显易懂,特分享于此。 什么是事件? 事件(E...
    jxyjxy阅读 3,017评论 1 10
  • 一、问答 1. dom对象的innerText和innerHTML有什么区别? innerHTML: 也就是从对象...
    饥人谷_罗伟恩阅读 584评论 0 2
  • 一、dom对象的innerText和innerHTML有什么区别? innerHTML返回的是从对象起始位置到终止...
    __Qiao阅读 404评论 0 0
  • 保安队才建立起来两个月,就有一宗大案子在县属境内发生了。 时已深冬,天气寒冷干燥,山也退了颜色,一派枯黄,县衙大堂...
    ARMSTRONG萌阅读 383评论 0 0
  • 阳光是否不会遗漏任何一个角落,是否每个努力拼搏的青春总会有逆袭……?!
    悦图文阅读 168评论 0 1