六十天前端强化训练之第十一天之事件机制超详解析
=====欢迎来到编程星辰海的博客讲解======
目录
一、事件模型演进史
1.1 原始事件模型(DOM Level 0)
1.2 DOM Level 2事件模型
1.3 DOM Level 3事件模型
二、事件流深度剖析
2.1 捕获与冒泡对比实验
2.2 事件终止方法对比
三、事件委托高级应用
3.1 动态元素处理方案
3.2 性能对比测试
3.3 复杂场景处理
四、浏览器兼容性全解
4.1 事件对象差异
4.2 移动端特殊处理
五、生产环境最佳实践
5.1 性能优化策略
5.2 调试技巧
六、扩展知识体系
6.1 框架事件系统对比
6.2 新兴提案跟踪
七、综合案例升级版
7.1 功能增强列表
7.2 性能基准测试
八、延伸学习路径
8.1 推荐书单
8.2 在线实验平台
8.3 进阶学习主题
一、事件模型演进史
1.1 原始事件模型(DOM Level 0)
历史背景:
1996年随JavaScript 1.0引入,主要特点:
- 简单的事件属性绑定
- 不支持事件捕获
- 只能绑定单个处理程序
典型实现:
JAVASCRIPT
element.onclick = function() { // 处理逻辑 };
局限性:
- 无法实现事件流的精细控制
- 多个处理程序会相互覆盖
- 缺少统一的事件对象
1.2 DOM Level 2事件模型
核心改进:
- 引入事件流三阶段机制
- 支持添加多个事件监听
- 标准化事件对象属性
方法对比:
| 方法 | 参数说明 | 兼容性 |
|---|---|---|
| addEventListener | (type, handler, useCapture) | IE9+ |
| attachEvent | ('on'+type, handler) | IE6-10 |
| removeEventListener | 参数与添加时严格一致 | 注意内存泄漏 |
内存管理要点:
JAVASCRIPT
// 错误示例:导致内存泄漏 element.addEventListener('click', function() {// 匿名函数无法移除 });// 正确做法 const handler = function() { /*...*/ }; element.addEventListener('click', handler); // 需要移除时 element.removeEventListener('click', handler);
1.3 DOM Level 3事件模型
新增特性:
- 新增事件类型:DOMContentLoaded、textInput等
- 自定义事件支持
- 增强键盘事件处理
自定义事件示例:
JAVASCRIPT
// 创建事件 const customEvent = new CustomEvent('build', {detail: { time: Date.now() },bubbles: true,cancelable: true });// 触发事件 element.dispatchEvent(customEvent);
二、事件流深度剖析
2.1 捕获与冒泡对比实验
测试代码:
HTML
<div id="grandParent"><div id="parent"><div id="child"></div></div> </div><script>const log = msg => console.log(`${performance.now().toFixed(2)}ms: ${msg}`);document.getElementById('grandParent').addEventListener('click', () => log('GrandParent捕获'), true);document.getElementById('parent').addEventListener('click', () => log('Parent捕获'), true);document.getElementById('child').addEventListener('click', () => log('Child捕获'), true);document.getElementById('child').addEventListener('click', () => log('Child冒泡'));document.getElementById('parent').addEventListener('click', () => log('Parent冒泡'));document.getElementById('grandParent').addEventListener('click', () => log('GrandParent冒泡')); </script>
输出结果:
TEXT
3.45ms: GrandParent捕获 3.58ms: Parent捕获 3.62ms: Child捕获 3.65ms: Child冒泡 3.67ms: Parent冒泡 3.69ms: GrandParent冒泡
2.2 事件终止方法对比
| 方法 | 作用范围 | 兼容性 |
|---|---|---|
| stopPropagation() | 阻止后续传播阶段 | 全支持 |
| stopImmediatePropagation() | 阻止同元素后续监听器 | IE9+ |
| preventDefault() | 阻止默认行为 | 注意可取消性 |
三、事件委托高级应用
3.1 动态元素处理方案
传统方法的缺陷:
JAVASCRIPT
// 动态添加元素后需要重新绑定 newElements.forEach(element => {element.addEventListener('click', handler); });
委托模式优势:
JAVASCRIPT
// 统一处理现有和未来元素 container.addEventListener('click', function(event) {const target = event.target.closest('.item');if (target) {handleItemClick(target);} });
3.2 性能对比测试
测试条件:
- 列表项数量:1000个
- 点击操作频率:每秒50次
- 测试浏览器:Chrome 108
结果对比:
| 方式 | 内存占用 | CPU使用率 | 响应延迟 |
|---|---|---|---|
| 单独绑定 | 8.3MB | 23% | 4.2ms |
| 事件委托 | 2.1MB | 7% | 1.8ms |
3.3 复杂场景处理
多层级委托:
JAVASCRIPT
document.addEventListener('click', function(event) {const tableCell = event.target.closest('td');const tableRow = event.target.closest('tr');const table = event.target.closest('table');if (tableCell) {handleCellClick(tableCell);}if (tableRow) {handleRowClick(tableRow);}if (table) {handleTableClick(table);} });
混合事件处理:
JAVASCRIPT
const modal = document.getElementById('modal');// 阻止模态框外部点击 document.body.addEventListener('click', function(event) {if (!modal.contains(event.target)) {event.stopPropagation();hideModal();} });// 模态框内部委托 modal.addEventListener('click', function(event) {const closeBtn = event.target.closest('.close-btn');if (closeBtn) {hideModal();} });
四、浏览器兼容性全解
4.1 事件对象差异
| 属性/方法 | 标准方式 | IE方式 (<=10) |
|---|---|---|
| 目标元素 | event.target | event.srcElement |
| 阻止默认行为 | event.preventDefault() | event.returnValue = false |
| 阻止冒泡 | event.stopPropagation() | event.cancelBubble = true |
兼容性代码示例:
JAVASCRIPT
function handleEvent(event) {event = event || window.event;const target = event.target || event.srcElement;if (event.preventDefault) {event.preventDefault();} else {event.returnValue = false;}if (event.stopPropagation) {event.stopPropagation();} else {event.cancelBubble = true;} }
4.2 移动端特殊处理
触摸事件处理:
JAVASCRIPT
let touchStartX = 0;element.addEventListener('touchstart', function(event) {touchStartX = event.changedTouches[0].screenX; });element.addEventListener('touchend', function(event) {const touchEndX = event.changedTouches[0].screenX;if (Math.abs(touchEndX - touchStartX) > 30) {handleSwipe();} });
点击延迟解决:
HTML
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.6/fastclick.min.js"></script> <script>if ('addEventListener' in document) {document.addEventListener('DOMContentLoaded', function() {FastClick.attach(document.body);}, false);} </script>
五、生产环境最佳实践
5.1 性能优化策略
合理使用passive事件:
JAVASCRIPT
// 改善滚动性能 window.addEventListener('touchmove', function(event) {// 处理逻辑 }, { passive: true });
事件节流与防抖:
JAVASCRIPT
// 防抖实现 function debounce(fn, delay) {let timer = null;return function(...args) {clearTimeout(timer);timer = setTimeout(() => fn.apply(this, args), delay);}; }// 使用示例 window.addEventListener('resize', debounce(() => {console.log('窗口调整结束'); }, 300));
5.2 调试技巧
事件监听器检查:
JAVASCRIPT
// 获取所有事件监听器 console.log(getEventListeners(document.body));// Chrome DevTools操作指南: // 1. 打开Elements面板 // 2. 选中目标元素 // 3. 查看Event Listeners标签
性能分析示例:
JAVASCRIPT
function expensiveOperation() {// 复杂计算... }// 添加性能标记 function handleClick() {performance.mark('start');expensiveOperation();performance.mark('end');performance.measure('click handling', 'start', 'end'); }
六、扩展知识体系
6.1 框架事件系统对比
React合成事件:
- 事件池机制
- 跨浏览器封装
- 委托到document
Vue事件处理:
- v-on指令语法
- 修饰符系统(.stop, .prevent)
- 自定义事件系统
6.2 新兴提案跟踪
Scrollend事件:
JAVASCRIPT
element.addEventListener('scrollend', () => {console.log('滚动完全停止'); });
Pointer Events规范:
JAVASCRIPT
element.addEventListener('pointerdown', (event) => {console.log(`接触类型:${event.pointerType}`); });
七、综合案例升级版
7.1 功能增强列表
JAVASCRIPT
class DynamicList {constructor(containerId) {this.container = document.getElementById(containerId);this.selectedItems = new Set();this.init();}init() {this.container.addEventListener('click', this.handleClick.bind(this));this.container.addEventListener('dblclick', this.handleDoubleClick.bind(this));this.container.addEventListener('contextmenu', this.handleContextMenu.bind(this));}handleClick(event) {const item = event.target.closest('.list-item');if (!item) return;if (event.ctrlKey || event.metaKey) {// 多选模式item.classList.toggle('selected');this.selectedItems.has(item) ? this.selectedItems.delete(item): this.selectedItems.add(item);} else {// 单选模式this.clearSelection();item.classList.add('selected');this.selectedItems.add(item);}}handleDoubleClick(event) {const item = event.target.closest('.list-item');if (item) {this.editItemContent(item);}}handleContextMenu(event) {event.preventDefault();const item = event.target.closest('.list-item');if (item) {this.showContextMenu(item, event.clientX, event.clientY);}}// 其他辅助方法... }
7.2 性能基准测试
测试代码:
JAVASCRIPT
function benchmark(testFn, iterations) {const start = performance.now();for (let i = 0; i < iterations; i++) {testFn();}const duration = performance.now() - start;console.log(`执行${iterations}次耗时:${duration.toFixed(2)}ms`); }// 对比测试 function testDirectBinding() {const container = document.createElement('div');for (let i = 0; i < 1000; i++) {const item = document.createElement('div');item.className = 'item';item.addEventListener('click', () => {});container.appendChild(item);} }function testEventDelegation() {const container = document.createElement('div');container.addEventListener('click', function(event) {if (event.target.classList.contains('item')) {// 处理逻辑}});for (let i = 0; i < 1000; i++) {const item = document.createElement('div');item.className = 'item';container.appendChild(item);} }benchmark(testDirectBinding, 100); // 执行100次耗时:4587.23ms benchmark(testEventDelegation, 100); // 执行100次耗时:623.41ms
八、延伸学习路径
8.1 推荐书单
- 《JavaScript高级程序设计》(第4版)第17章-事件
- 《你不知道的JavaScript》(中卷)第二部分-异步和性能
- 《高性能JavaScript》第6章-快速响应的用户界面
8.2 在线实验平台
- JSFiddle事件沙箱:JSFiddle - Code Playground
- CodePen事件专题:https://codepen.io/
- Google Developers实验室:https://developers.google.com/web/tools/chrome-devtools
8.3 进阶学习主题
- 浏览器渲染流程与事件循环
- Web Workers中的事件处理
- 服务端事件(Server-Sent Events)
- WebSocket实时通信事件
- 浏览器扩展程序事件系统
本内容涵盖从事件机制基础到企业级应用的全方位知识,建议结合实践项目逐步深入。每个技术点都可展开为独立的研究课题,持续关注W3C规范更新和浏览器厂商的最新实现。
相关文章:
六十天前端强化训练之第十一天之事件机制超详解析
欢迎来到编程星辰海的博客讲解 目录 一、事件模型演进史 1.1 原始事件模型(DOM Level 0) 1.2 DOM Level 2事件模型 1.3 DOM Level 3事件模型 二、事件流深度剖析 2.1 捕获与冒泡对比实验 2.2 事件终止方法对比 三、事件委托高级应用 3.1 动态元…...
调试正常 ≠ 运行正常:Keil5中MicroLIB的“量子态BUG”破解实录
调试正常 ≠ 运行正常:Keil5中MicroLIB的“量子态BUG”破解实录——从勾选一个选项到理解半主机模式,嵌入式开发的认知升级 📌 现象描述:调试与烧录的诡异差异 在线调试时 程序正常运行 - 独立运行时 设备无响应 ! 编译过程 0 Err…...
基于SpringBoot实现旅游酒店平台功能八
一、前言介绍: 1.1 项目摘要 随着社会的快速发展和人民生活水平的不断提高,旅游已经成为人们休闲娱乐的重要方式之一。人们越来越注重生活的品质和精神文化的追求,旅游需求呈现出爆发式增长。这种增长不仅体现在旅游人数的增加上࿰…...
ArcGIS Pro中字段的新建方法与应用
一、引言 在地理信息系统(GIS)的数据管理和分析过程中,字段操作起着至关重要的作用。 无论是进行地图制作、空间分析还是数据统计,字段都是承载属性信息的基本单元。 ArcGIS Pro作为一款功能强大的GIS软件,为用户提…...
c#面试题12
1.ApplicationPool介绍一下 c#里没有 2.XML 可扩展标记语言,一般以.xml文件格式的形式存在。可用于存储结构化的数据 3.ASP.NET的用户控件 将原始的控件,用户根据需要进行整合成一个新的控件 4.介绍一下code-Behind 即代码后置技术,就是…...
Matlab中快速查找元素索引号
1、背景介绍 在算法设计过程中,有时候需要从一维/二维数组中,快速查找是否某个元素,以及该元素所在的位置。如一维矩阵[1 2 3 4 5 6 6 7 8]所示,元素6所在的位置为6 7。 2、函数测试 matlab中函数find()可以快速查找到指定元素所…...
LabVIEW非线性拟合实现正弦波参数提取
LabVIEW的Nonlinear Curve Fit.vi基于Levenberg-Marquardt算法,能够实现非线性最小二乘拟合,包括正弦波三参数(幅值、频率、相位)的精确求解。该工具适用于非均匀采样、低信噪比信号等复杂场景,但需注意初始参数设置与…...
S19文件格式详解:汽车ECU软件升级中的核心镜像格式
文章目录 引言一、S19文件格式的起源与概述二、S19文件的核心结构三、S19在汽车ECU升级中的应用场景四、S19与其他格式的对比五、S19文件实例解析六、工具链支持与安全考量七、未来趋势与挑战结语引言 在汽车电子控制单元(ECU)的软件升级过程中,S19文件(也称为Motorola S-…...
Redis 缓存穿透、缓存击穿与缓存雪崩详解:问题、解决方案与最佳实践
目录 引言 1. 缓存穿透 1.1 什么是缓存穿透? 示例: 1.2 缓存穿透的原因 1.3 缓存穿透的解决方案 1.3.1 缓存空对象 1.3.2 布隆过滤器(Bloom Filter) 1.3.3 参数校验 2. 缓存击穿 2.1 什么是缓存击穿? 示例&…...
Mamba| Miniforge3 安装和配置
参考教程: B站 教程概要 安装最新的 Mamba,建议通过安装 Miniforge 来实现,因为 Miniforge 默认包含 Mamba。Miniforge 下载:建议使用南京大学镜像站mamba 设置镜像源:清华镜像源修改默认环境安装路径设置 pip 镜像&a…...
Qt入门笔记
目录 一、前言 二、创建Qt项目 2.1、使用向导创建 2.2、最简单的Qt应用程序 2.2.1、main函数 2.2.2、widget.h文件 2.2.3、widget.cpp文件 2.3、Qt按键Botton 2.3.1、创建一个Botton 2.3.2、信号与槽 2.3.3、按键使用信号与槽的方法 2.4、文件Read与Write-QFile类 2…...
C语言每日一练——day_4
引言 针对初学者,每日练习几个题,快速上手C语言。第四天。(连续更新中) 采用在线OJ的形式 什么是在线OJ? 在线判题系统(英语:Online Judge,缩写OJ)是一种在编程竞赛中用…...
下降路径最⼩和(medium)
题目描述: 给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径 的 最小和 。 下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(…...
redux_旧版本
reduxjs/toolkit(RTK)是 Redux 官方团队推出的一个工具集,旨在简化 Redux 的使用和配置。它于 2019 年 10 月 正式发布,此文章记录一下redux的旧版本如何使用,以及引入等等。 文件目录如下: 步骤 安装依…...
⭐算法OJ⭐经典题目分类索引(持续更新)
在编程竞赛和算法学习中,Online Judge(OJ)平台是程序员们磨练技能的重要工具。OJ平台上的题目种类繁多,涵盖了从基础数据结构到复杂算法的各个方面。为了更好地理解和掌握这些题目,对其进行分类是非常有必要的。这篇索…...
python之使用scapy扫描本机局域网主机,输出IP/MAC表
安装scapy库 pip install scapy -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple扫描本机局域网的所有主机,输出IP/MAC对于表 # -*- coding: UTF-8 -*- import netifaces from scapy.all import srp from scapy.layers.l2 import ARP, Ether import ipa…...
Spring Boot中@Valid 与 @Validated 注解的详解
Spring Boot中Valid 与 Validated 注解的详解 引言 在Spring Boot应用中,参数校验是确保数据完整性和一致性的重要手段。Valid和Validated注解是Spring Boot中用于参数校验的两个核心注解。本文将详细介绍这两个注解的用法、区别以及代码样例。 Valid注解 功能介…...
18、TCP连接三次握手的过程,为什么是三次,可以是两次或者更多吗【高频】
三次握手的过程: 第一次握手:客户端 向 服务器 发送一个 SYN(也就是同步序列编号报文),请求建立连接。随后,客户端 进入 SYN_SENT 状态;服务器收到 SYN 之后,由 LISTEN 状态变为 SYN…...
Ceph(2):Ceph简介
1 Ceph简介 Ceph使用C语言开发,遵循LGPL协议开源。Sage Weil(Ceph论文发表者)于2011年创立了以Inktank公司主导Ceph的开发和社区维护。2014年Redhat收购inktank公司,并发布Inktank Ceph企业版(ICE)软件,业务场景聚焦云…...
第二篇:CTF常见题型解析:密码学、逆向工程、漏洞利用、Web安全
# 零基础小白入门CTF解题到成为CTF大佬系列文章 ## 第二篇:CTF常见题型解析:密码学、逆向工程、漏洞利用、Web安全 ### 引言 在CTF比赛中,题目类型多种多样,涵盖了网络安全领域的多个方向。掌握这些题型的解题方法,…...
《Python基础教程》附录B笔记:Python参考手册
《Python基础教程》第1章笔记👉https://blog.csdn.net/holeer/article/details/143052930 附录B Python参考手册 Python标准文档是完整的参考手册。本附录只是一个便利的速查表,当你开始使用Python进行编程后,它可帮助你唤醒记忆。 B.1 表…...
linux学习(十三)(shell编程(文字,变量,循环,条件,调试))
Shell 编程 Shell 编程,也称为 shell 脚本,是 Linux作系统不可或缺的一部分。shell 脚本实质上是系统 shell 执行的程序。虽然它可能不如 C 或 C 等编译语言强大,但 shell 编程对于管理级任务、自动执行重复性任务和系统监控非常有效。 大多…...
大模型微调中warmup(学习率预热)是什么
大模型微调中warmup(学习率预热)是什么 在大模型微调中,添加warmup(学习率预热)是指在训练初期逐步增加学习率,避免直接使用高学习率导致参数震荡。 🔧 为什么需要warmup? 大模型参数敏感:预训练模型的参数已接近最优,初期用大学习率可能剧烈扰动参数(如“急刹车…...
wireshark 如何关闭混杂模式 wireshark操作
Fiddler和Wireshark都是进行抓包的工具:所谓抓包就是将网络传输发送与接收的数据包进行截获、重发、编辑、转存等操作,也用来检查网络安全。抓包也经常被用来进行数据截取等。黑客常常会用抓包软件获取你非加密的上网数据,然后通过分析&#…...
ChatGPT4.5详细介绍和API调用详细教程
OpenAI在2月27日发布GPT-4.5的研究预览版——这是迄今为止OpenAI最强大、最出色的聊天模型。GPT-4.5在扩大预训练和微调规模方面迈出了重要的一步。通过扩大无监督学习的规模,GPT-4.5提升了识别内容中的模式、建立内容关联和生成对于内容的见解的能力,但…...
centos linux安装mysql8 重置密码 远程连接
1. 下载并安装 MySQL Yum 仓库 从 MySQL 官方网站下载并安装 Yum 仓库配置文件。 # 下载MySQL 8.0的Yum仓库包 wget https://dev.mysql.com/get/mysql80-community-release-el7-5.noarch.rpm # 安装Yum仓库包 sudo rpm -ivh mysql80-community-release-el7-5.noarch.rpm2. 启…...
AWS 如何导入内部SSL 证书
SSL 证书的很重要的功能就是 HTTP- > HTTPS, 下面就说明一下怎么导入ssl 证书,然后绑定证书到ALB. 以下示例说明如何使用 AWS Management Console 导入证书。 从以下位置打开 ACM 控制台:https://console.aws.amazon.com/acm/home。如果您是首次使用 ACM,请查找 AWS Cer…...
Unity DOTS从入门到精通之 自定义Authoring类
文章目录 前言安装 DOTS 包什么是Authoring1. 实体组件2. Authoring类 前言 DOTS(面向数据的技术堆栈)是一套由 Unity 提供支持的技术,用于提供高性能游戏开发解决方案,特别适合需要处理大量数据的游戏,例如大型开放世…...
一键换肤的Qt-Advanced-Stylesheets
项目简介 能在软件运行时对 CSS 样式表主题(包括 SVG 资源和 SVG 图标)进行实时颜色切换的Qt项目。 项目预览: 项目地址 地址:Qt-Advanced-Stylesheets 本地编译环境 Win11 家庭中文版 Qt5.15.2 (MSVC2019) Qt Creator1…...
golang 静态库 Undefined symbol: __mingw_vfprintf
正常用golang编译一个静态库给 其他语言 调用,编译时报错 Error: Undefined symbol: __mingw_vfprintf 很是奇怪,之前用用golang写静态库成功过,编译也没问题,结果却是截然不同。 试了很多次,发现唯一的差别就是在 …...
