说说JavaScript中的事件模型
一、事件与事件流
javascript
中的事件,可以理解就是在HTML
文档或者浏览器中发生的一种交互操作,使得网页具备互动性, 常见的有加载事件、鼠标事件、自定义事件等
由于DOM
是一个树结构,如果在父子节点绑定事件时候,当触发子节点的时候,就存在一个顺序问题,这就涉及到了事件流的概念
事件流都会经历三个阶段:
- 事件捕获阶段(capture phase)
- 处于目标阶段(target phase)
- 事件冒泡阶段(bubbling phase)
事件冒泡是一种从下往上的传播方式,由最具体的元素(触发节点)然后逐渐向上传播到最不具体的那个节点,也就是DOM
中最高层的父节点
1 2 3 4 5 6 7 8 9 10 | <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <title>Event Bubbling</title> </head> <body> <button id= "clickMe" >Click Me</button> </body> </html> |
然后,我们给button
和它的父元素,加入点击事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var button = document.getElementById( 'clickMe' ); button.onclick = function() { console.log( '1.Button' ); }; document.body.onclick = function() { console.log( '2.body' ); }; document.onclick = function() { console.log( '3.document' ); }; window.onclick = function() { console.log( '4.window' ); }; |
点击按钮,输出如下
1 2 3 4 | 1.button 2.body 3.document 4.window |
点击事件首先在button
元素上发生,然后逐级向上传播
事件捕获与事件冒泡相反,事件最开始由不太具体的节点最早接受事件, 而最具体的节点(触发节点)最后接受事件
二、事件模型
事件模型可以分为三种:
- 原始事件模型(DOM0级)
- 标准事件模型(DOM2级)
- IE事件模型(基本不用)
原始事件模型
事件绑定监听函数比较简单, 有两种方式:
- HTML代码中直接绑定
1 | <input type= "button" onclick= "fun()" > |
- 通过
JS
代码绑定
1 2 | var btn = document.getElementById( '.btn' ); btn.onclick = fun; |
特性
- 绑定速度快
DOM0
级事件具有很好的跨浏览器优势,会以最快的速度绑定,但由于绑定速度太快,可能页面还未完全加载出来,以至于事件可能无法正常运行
-
只支持冒泡,不支持捕获
-
同一个类型的事件只能绑定一次
1 2 3 4 | <input type= "button" id= "btn" onclick= "fun1()" > var btn = document.getElementById( '.btn' ); btn.onclick = fun2; |
如上,当希望为同一个元素绑定多个同类型事件的时候(上面的这个btn
元素绑定2个点击事件),是不被允许的,后绑定的事件会覆盖之前的事件
删除 DOM0
级事件处理程序只要将对应事件属性置为null
即可
1 | btn.onclick = null ; |
标准事件模型
在该事件模型中,一次事件共有三个过程:
- 事件捕获阶段:事件从
document
一直向下传播到目标元素, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行 - 事件处理阶段:事件到达目标元素, 触发目标元素的监听函数
- 事件冒泡阶段:事件从目标元素冒泡到
document
, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行
事件绑定监听函数的方式如下:
1 | addEventListener(eventType, handler, useCapture) |
事件移除监听函数的方式如下:
1 | removeEventListener(eventType, handler, useCapture) |
参数如下:
eventType
指定事件类型(不要加on)handler
是事件处理函数useCapture
是一个boolean
用于指定是否在捕获阶段进行处理,一般设置为false
与IE浏览器保持一致
举个例子:
1 2 3 | var btn = document.getElementById( '.btn' ); btn.addEventListener(‘click’, showMessage, false ); btn.removeEventListener(‘click’, showMessage, false ); |
特性
- 可以在一个
DOM
元素上绑定多个事件处理器,各自并不会冲突
1 2 3 | btn.addEventListener(‘click’, showMessage1, false ); btn.addEventListener(‘click’, showMessage2, false ); btn.addEventListener(‘click’, showMessage3, false ); |
- 执行时机
当第三个参数(useCapture
)设置为true
就在捕获过程中执行,反之在冒泡过程中执行处理函数
下面举个例子:
1 2 3 4 5 | <div id= 'div' > <p id= 'p' > <span id= 'span' >Click Me!</span> </p > </div> |
设置点击事件
1 2 3 4 5 6 7 8 9 10 11 | var div = document.getElementById( 'div' ); var p = document.getElementById( 'p' ); function onClickFn ( event ) { var tagName = event .currentTarget.tagName; var phase = event .eventPhase; console.log(tagName, phase); } div.addEventListener( 'click' , onClickFn, false ); p.addEventListener( 'click' , onClickFn, false ); |
上述使用了eventPhase
,返回一个代表当前执行阶段的整数值。1为捕获阶段、2为事件对象触发阶段、3为冒泡阶段
点击Click Me!
,输出如下
1 2 | P 3 DIV 3 |
可以看到,p
和div
都是在冒泡阶段响应了事件,由于冒泡的特性,裹在里层的p
率先做出响应
如果把第三个参数都改为true
1 2 | div.addEventListener( 'click' , onClickFn, true ); p.addEventListener( 'click' , onClickFn, true ); |
输出如下
1 2 | DIV 1 P 1 |
两者都是在捕获阶段响应事件,所以div
比p
标签先做出响应
IE事件模型
IE事件模型共有两个过程:
- 事件处理阶段:事件到达目标元素, 触发目标元素的监听函数。
- 事件冒泡阶段:事件从目标元素冒泡到
document
, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行
事件绑定监听函数的方式如下:
1 | attachEvent(eventType, handler) |
事件移除监听函数的方式如下:
1 | detachEvent(eventType, handler) |
举个例子:
1 2 3 | var btn = document.getElementById( '.btn' ); btn.attachEvent(‘onclick’, showMessage); btn.detachEvent(‘onclick’, showMessage); |
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
2023-05-17 记录--vue3优雅的使用element-plus的dialog
2021-05-17 TP6框架--EasyAdmin学习笔记:定义路由