Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >深入理解 DOM 事件机制

深入理解 DOM 事件机制

作者头像
小生方勤
发布于 2019-06-02 07:34:23
发布于 2019-06-02 07:34:23
2.9K00
代码可运行
举报
文章被收录于专栏:前端词典前端词典
运行总次数:0
代码可运行

前言

本文主要介绍 DOM 事件级别、DOM 事件模型、事件流、事件代理和 Event 对象常见的应用,希望对你们有些帮助和启发!

一、DOM 事件级别

DOM 级别一共可以分为四个级别:DOM0 级、DOM1 级、DOM2 级和 DOM3 级。而 DOM 事件分为 3 个级别:DOM0 级事件处理,DOM2 级事件处理和DOM3 级事件处理。由于DOM1 级中没有事件的相关内容,所以没有DOM1 级事件。

1.DOM0 级事件

el.onclick=function(){}

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 例1
var btn = document.getElementById('btn');
 btn.onclick = function(){
     alert(this.innerHTML);
 }

当希望为同一个元素/标签绑定多个同类型事件的时候(如给上面的这个btn元素绑定3个点击事件),是不被允许的。DOM0 事件绑定,给元素的事件行为绑定方法,这些方法都是在当前元素事件行为的冒泡阶段(或者目标阶段)执行的

2.DOM2 级事件

el.addEventListener(event-name, callback, useCapture)

  • event-name: 事件名称,可以是标准的 DOM 事件
  • callback: 回调函数,当事件触发时,函数会被注入一个参数为当前的事件对象 event
  • useCapture: 默认是 false,代表事件句柄在冒泡阶段执行
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 例2
var btn = document.getElementById('btn');
btn.addEventListener("click", test, false);
function test(e){
    e = e || window.event;
    alert((e.target || e.srcElement).innerHTML);
    btn.removeEventListener("click", test)
}
//IE9-:attachEvent()与detachEvent()。
//IE9+/chrom/FF:addEventListener()和removeEventListener()

IE9以下的IE浏览器不支持 addEventListener()和removeEventListener(),使用 attachEvent()与detachEvent() 代替,因为IE9以下是不支持事件捕获的,所以也没有第三个参数,第一个事件名称前要加on。

3.DOM3 级事件

在DOM 2级事件的基础上添加了更多的事件类型。

  • UI事件,当用户与页面上的元素交互时触发,如:load、scroll
  • 焦点事件,当元素获得或失去焦点时触发,如:blur、focus
  • 鼠标事件,当用户通过鼠标在页面执行操作时触发如:dblclick、mouseup
  • 滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel
  • 文本事件,当在文档中输入文本时触发,如:textInput
  • 键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress
  • 合成事件,当为IME(输入法编辑器)输入字符时触发,如:compositionstart
  • 变动事件,当底层DOM结构发生变化时触发,如:DOMsubtreeModified
  • 同时 DOM3 级事件也允许使用者自定义一些事件。

二、DOM 事件模型和事件流

DOM事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段。

(1)捕获阶段:事件从window对象自上而下向目标节点传播的阶段;

(2)目标阶段:真正的目标节点正在处理事件的阶段;

(3)冒泡阶段:事件从目标节点自下而上向window对象传播的阶段。

DOM事件捕获的具体流程

捕获是从上到下,事件先从window对象,然后再到document(对象),然后是html标签(通过document.documentElement获取html标签),然后是body标签(通过document.body获取body标签),然后按照普通的html结构一层一层往下传,最后到达目标元素。

而事件冒泡的流程刚好是事件捕获的逆过程。 接下来我们看个事件冒泡的例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 例3
<div id="outer">
    <div id="inner"></div>
</div>
......
window.onclick = function() {
    console.log('window');
};
document.onclick = function() {
    console.log('document');
};
document.documentElement.onclick = function() {
    console.log('html');
};
document.body.onclick = function() {
    console.log('body');
}
outer.onclick = function(ev) {
    console.log('outer');
};
inner.onclick = function(ev) {
    console.log('inner');
};

正如我们上面提到的 onclick 给元素的事件行为绑定方法都是在当前元素事件行为的冒泡阶段(或者目标阶段)执行的。

三、事件代理(事件委托)

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。

1.优点

  • 减少内存消耗,提高性能

假设有一个列表,列表之中有大量的列表项,我们需要在点击每个列表项的时候响应一个事件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 例4
<ul id="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  ......
  <li>item n</li>
</ul>

如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的,效率上需要消耗很多性能。借助事件代理,我们只需要给父容器ul绑定方法即可,这样不管点击的是哪一个后代元素,都会根据冒泡传播的传递机制,把容器的click行为触发,然后把对应的方法执行,根据事件源,我们可以知道点击的是谁,从而完成不同的事。

  • 动态绑定事件

在很多时候,我们需要通过用户操作动态的增删列表项元素,如果一开始给每个子元素绑定事件,那么在列表发生变化时,就需要重新给新增的元素绑定事件,给即将删去的元素解绑事件,如果用事件代理就会省去很多这样麻烦。

2.如何实现

接下来我们来实现上例中父层元素 #list 下的 li 元素的事件委托到它的父层元素上:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 给父层元素绑定事件
document.getElementById('list').addEventListener('click', function (e) {
  // 兼容性处理
  var event = e || window.event;
  var target = event.target || event.srcElement;
  // 判断是否匹配目标元素
  if (target.nodeName.toLocaleLowerCase === 'li') {
    console.log('the content is: ', target.innerHTML);
  }
});

四、Event对象常见的应用

  • event. preventDefault()

如果调用这个方法,默认事件行为将不再触发。什么是默认事件呢?例如表单一点击提交按钮(submit)跳转页面、a标签默认页面跳转或是锚点定位等。

很多时候我们使用a标签仅仅是想当做一个普通的按钮,点击实现一个功能,不想页面跳转,也不想锚点定位。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//方法一:
<a href="javascript:;">链接</a>

也可以通过JS方法来阻止,给其click事件绑定方法,当我们点击A标签的时候,先触发click事件,其次才会执行自己的默认行为

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//方法二:
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
test.onclick = function(e){
    e = e || window.event;
    return false;
}
</script>
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//方法三:
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
test.onclick = function(e){
    e = e || window.event;
    e.preventDefault();
}
</script>

接下来我们看个例子:输入框最多只能输入六个字符,如何实现?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 例5
 <input type="text" id='tempInp'>
 <script>
    tempInp.onkeydown = function(ev) {
        ev = ev || window.event;
        let val = this.value.trim() //trim去除字符串首位空格(不兼容)
        // this.value=this.value.replace(/^ +| +$/g,'') 兼容写法
        let len = val.length
        if (len >= 6) {
            this.value = val.substr(0, 6);
            //阻止默认行为去除特殊按键(DELETE\BACK-SPACE\方向键...)
            let code = ev.which || ev.keyCode;
            if (!/^(46|8|37|38|39|40)$/.test(code)) {
                ev.preventDefault()
            }
        }
    }
 </script>
  • event.stopPropagation() & event.stopImmediatePropagation()

event.stopPropagation() 方法阻止事件冒泡到父元素,阻止任何父事件处理程序被执行。上面提到事件冒泡阶段是指事件从目标节点自下而上向window对象传播的阶段。 我们在例4的inner元素click事件上,添加event.stopPropagation()这句话后,就阻止了父事件的执行,最后只打印了'inner'。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 inner.onclick = function(ev) {
    console.log('inner');
    ev.stopPropagation();
};

stopImmediatePropagation 既能阻止事件向父元素冒泡,也能阻止元素同事件类型的其它监听器被触发。而 stopPropagation 只能实现前者的效果。我们来看个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<body>
  <button id="btn">click me to stop propagation</button>
</body>
......
const btn = document.querySelector('#btn');
btn.addEventListener('click', event => {
  console.log('btn click 1');
  event.stopImmediatePropagation();
});
btn.addEventListener('click', event => {
  console.log('btn click 2');
});
document.body.addEventListener('click', () => {
  console.log('body click');
});
// btn click 1

如上所示,使用 stopImmediatePropagation后,点击按钮时,不仅body绑定事件不会触发,与此同时按钮的另一个点击事件也不触发。

  • event.target & event.currentTarget

老实说这两者的区别,并不好用文字描述,我们先来看个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<div id="a">
  <div id="b">
    <div id="c"><div id="d"></div></div>
  </div>
</div>
<script>
  document.getElementById('a').addEventListener('click', function(e) {
    console.log(
      'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
  })
  document.getElementById('b').addEventListener('click', function(e) {
    console.log(
      'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
  })
  document.getElementById('c').addEventListener('click', function(e) {
    console.log(
      'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
  })
  document.getElementById('d').addEventListener('click', function(e) {
    console.log(
      'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
  })
</script>

当我们点击最里层的元素d的时候,会依次输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
target:d&currentTarget:d
target:d&currentTarget:c
target:d&currentTarget:b
target:d&currentTarget:a

从输出中我们可以看到,event.target指向引起触发事件的元素,而event.currentTarget则是事件绑定的元素,只有被点击的那个目标元素的event.target才会等于event.currentTarget也就是说,event.currentTarget始终是监听事件者,而event.target是事件的真正发出者

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-05-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小生方勤 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
深入理解事件
javascript 给 DOM 绑定事件处理函数总的来说有2种方式:在 html 文档中绑定、在 js 代码中绑定。下面的方式1、方式2属于在 html 中绑定事件,方式3、方式4和方式5属于在js代码中绑定事件,其中,方式4和5属于事件监听,而方式5是最推荐的做法。
Chor
2019/11/08
8920
DOM事件基本概念大总结(前端必备)
事件流 这一概念源自于对事件触发对象的思考。例如常见的点击事件,鼠标移动事件。这些事件发生之时,往往不只是点击或者移动到某一特定元素上。 比如点击某一个按钮,而它是由上一层的父标签,或许在上一层还有父标签甚至是整个页面。因此点击一个元素可以看成是同时点击了父标签或者整个页面。那么此时事件应该怎么响应到指定标签呢? 事件冒泡 即事件从指定元素开始传播到最外层的元素,并且该事件不仅会在指定元素上发生,还会在传播过过程中的每一个元素上发生。 <html> <body> <div>
努力的Greatiga
2022/07/25
2K0
事件
JavaScript与HTML之间的交互式通过事件实现的。 事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码。
奋飛
2019/08/15
3.4K0
JS事件流
HTML中与javascript交互是通过事件驱动来实现的,例如鼠标点击事件、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。想要知道这些事件是在什么时候进行调用的,就需要了解一下“事件流”的概念。
前端逗逗飞
2021/04/30
8.7K0
JS事件流
js 事件笔记
在Web中, 事件在浏览器窗口中被触发,执行事先绑定的事件处理器(也就是事件触发时会运行的代码块),对事件做出响应。 用户在浏览器的任何一个操作都会去触发一个事件,JavaScript采用异步事件驱动编程模型,当文档、浏览器、元素或与之相关对象发生特定事情时,浏览器会产生事件。
bamboo
2019/01/29
11.4K0
js 事件笔记
事件
事件 JavaScript和HTML的交互是通过事件实现的。JavaScript采用异步事件驱动编程模型,当文档、浏览器、元素或与之相关对象发生特定事情时,浏览器会产生事件。如果JavaScript关注特定类型事件,那么它可以注册当这类事件发生时要调用的句柄。事件是某个行为或者触发,比如点击、鼠标移动..... 当用户点击鼠标时 当网页已加载时 当图像已加载时 当鼠标移动到元素上时 当用户触发按键时... 事件流 事件流描述的是从页面中接收事件的顺序,比如有两个嵌套的div,点击了内层的div,这时候是内层
小胖
2018/06/27
1.4K0
JavaScript事件机制实现的一些理解
我们都知道JavaScript是一门事件驱动的语言,想要进一步深入了解JavaScript我们就要搞明白其中的事件机制。
henu_Newxc03
2021/12/28
5740
JavaScript事件机制实现的一些理解
事件
利用 on 开头的事件,如 onclick, 同一个元素同一个事件只能设置一个处理函数,出现多个处理函数的话,后面的会覆盖前面的。
赤蓝紫
2023/01/01
1.4K0
事件
「面试常问」系统理解浏览器之事件机制
在早期 IE 和 Netscape 团队在开发第四代浏览器的时候,遇到一个问题:当点击一个按钮的时候,是应该先处理父级的事件呢?还是应该先处理按钮的事件呢?IE 和 Netscape 给出了 2 种完全相反的答案,IE 提出事件冒泡的概念,而 Netscape 则支持事件捕获。
用户4456933
2021/06/01
5860
「面试常问」系统理解浏览器之事件机制
JavaScript的事件
javascript与HTML之间的交互是通过事件实现的。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。
小小鱼儿小小林
2020/06/24
1.6K0
JavaScript——DOM事件高级
此方法将指定的监听器注册到eventTarger(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。
岳泽以
2022/10/26
1.9K0
JavaScript——DOM事件高级
DOM事件的传播机制
DOM事件的传播机制是指当一个事件在DOM树中触发时,它是如何在各个元素之间传播的。DOM事件传播机制分为三个阶段:捕获阶段、目标阶段和冒泡阶段。此外,还有一种常用的技术称为事件委托,它能够简化事件处理程序的绑定和管理。本文将详细介绍这些概念,并提供相应的代码示例。
can4hou6joeng4
2023/11/17
2630
javascript事件详解
事件流 事件流两种顺序:冒泡与捕获。 简单的添加与删除事件 obj.onclick=function(){} obj.onclick=null; 通用事件添加的删除 obj.addEventListener(),obj.attachEvent() obj.removeEventListener(),obj.attachEvent() 三个参数分别表示,(事件,绑定函数,事件流), 注意: 1.如果必须得删除事件,这种写法,不能用匿名函数,否则删除函数的时候,不方便。 2.attachEvent的事件名称是o
前朝楚水
2018/04/02
1.4K0
事件高级
eventTarget.addEventListener()方法将指定的监听器注册到 eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。
星辰_大海
2020/09/30
1.5K0
一次关于js事件出发机制反常的解决记录
起因:正常情况下我点击s2时是先弹出我是children,再弹出我是father,但是却出现了先弹出我是father,后弹出我是children的情况,这种情况是在和安卓app交互的h5页面中出现的,本地测试没有问题,但是在安卓打包的内嵌h5页面就出现了问题。简单化的代码先展示出来。 html代码如下 <div id="father" class="ss1">s1 <div id="children" class="ss2">s2 </div> </div> 事件绑定如下 $('#fathe
吴裕超
2018/02/28
1.5K0
一次关于js事件出发机制反常的解决记录
JavaScript事件
JavaScript事件 对于事件来讲,首先,我们需要了解这样几个概念:事件;事件处理程序;事件类型;事件流;事件冒泡;事件捕获;事件对象;事件模拟,事件方面的性能优化(事件委托、移除事件处理程序); 事件的概念 事件:指的是文档或者浏览器窗口中发生的一些特定交互瞬间。我们可以通过监听器(或者处理程序)来预定事件,以便事件发生的时候执行相应的代码。 事件处理程序:我们用户在页面中进行的点击这个动作,鼠标移动的动作,网页页面加载完成的动作等,都可以称之为事件名称,即:click、mousemove、loa
汤高
2018/01/11
2.1K0
JavaScript事件
浅谈JavaScript的事件(事件对象)
  在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含这所有与事件有关的信息。包括导致事件的元素、事件的类型和事件的相关信息。例如鼠标操作的事件中,会包含鼠标的位置信息。而键盘触发的事件会包含与按下的键有关信息。所有浏览器都支持event对象,但支持方式不同。 DOM中的事件对象   兼容dom的浏览会将一个event对象传递到事件处理程序中。 1 var aa=document.getElementById("aa"); 2 aa.onclick=functi
水击三千
2018/02/27
1.3K0
前端day16-JS(WebApi)学习笔记(事件补充、事件冒泡与捕获)
var code = e.keyCode || e.charCode || e.which;
帅的一麻皮
2020/05/05
1.8K0
前端学习(50)~事件的绑定和事件对象
我们在之前的一篇文章《04-JavaScript/22-DOM简介和DOM操作》中已经讲过事件的概念。这里讲一下绑定(注册)事件的两种方式,我们以onclick事件为例。
Vincent-yuan
2020/03/19
9990
javascript 事件基础
一:事件流       事件流描述的是从页面中接收事件的顺序。  事件冒泡 <div id="one"> <div id="two"> <div id=
柴小智
2018/04/10
9840
javascript 事件基础
相关推荐
深入理解事件
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验