浏览器中的JavaScript使用事件驱动的编程模型。一切都始于事件。这是对JavaScript事件的介绍,以及事件处理的工作方式
介绍
浏览器中的JavaScript使用事件驱动的编程模型。
一切都始于事件。
该事件可能是DOM加载,完成获取的异步请求,用户单击元素或滚动页面或用户在键盘上键入。
有很多不同类型的事件。
事件处理程序
您可以使用事件处理程序,这是事件发生时调用的函数。
您可以为同一事件注册多个处理程序,并且在该事件发生时将全部调用它们。
JavaScript提供了三种注册事件处理程序的方式:
内联事件处理程序
由于其约束,今天很少使用这种事件处理程序样式,但这是JavaScript早期的唯一方法:
<a href="site.com" onclick="dosomething();">A link</a>
DOM事件处理程序
当一个对象最多具有一个事件处理程序时,这是很常见的,因为在这种情况下无法添加多个处理程序:
window.onload = () => {
//window loaded
}
在处理时最常用XHR要求:
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
//.. do something
}
您可以使用以下方法检查处理程序是否已分配给属性if ('onsomething' in window) {}
。
使用addEventListener()
这是现代方式。此方法允许注册所需数量的处理程序,并且它是最受欢迎的处理程序:
window.addEventListener('load', () => {
//window loaded
})
请注意,IE8和更低版本不支持此功能,而是使用了它自己的
attachEvent()
API。如果您需要支持较旧的浏览器,请记住这一点。
聆听不同的元素
你可以听window
拦截“全局”事件(例如键盘的用法),您可以侦听特定元素以检查事件的发生,例如鼠标单击按钮。
这就是为什么addEventListener
有时会被调用window
,有时在DOM元素上。
事件对象
一个事件处理程序得到一个Event
对象作为第一个参数:
const link = document.getElementById('my-link')
link.addEventListener('click', event => {
// link clicked
})
该对象包含许多有用的属性和方法,例如:
target
,是引发事件的DOM元素type
,事件类型stopPropagation()
,称为停止在DOM中传播事件
(查看完整清单)。
其他属性由特定类型的事件提供,例如Event
是用于不同特定事件的接口:
每个页面都有一个链接的MDN页面,因此您可以检查它们的所有属性。
例如,当发生KeyboardEvent时,您可以以可读格式检查按下了哪个键(Escape
,Enter
依此类推)key
财产:
window.addEventListener('keydown', event => {
// key pressed
console.log(event.key)
})
在发生鼠标事件时,我们可以检查按下了哪个鼠标按钮:
const link = document.getElementById('my-link')
link.addEventListener('mousedown', event => {
// mouse button pressed
console.log(event.button) //0=left, 2=right
})
事件冒泡和事件捕获
冒泡和捕获是事件用于传播的两个模型。
假设您的DOM结构是
<div id="container">
<button>Click me</button>
</div>
您想跟踪用户何时单击按钮,并且有2个事件侦听器,其中一个button
和一个#container
。请记住,单击子元素将始终传播到其父元素,除非您停止传播(请参阅下文)。
这些事件侦听器将按顺序调用,此顺序由所使用的事件冒泡/捕获模型确定。
起泡表示事件从被单击的项(子项)一直传播到其所有父树,从最近的树开始。
在我们的示例中,button
会在#container
处理程序。
捕捉相反:外部事件处理程序在更具体的处理程序之前触发,button
。
默认情况下,所有事件都会冒泡。
您可以通过将第三个参数应用于addEventListener并将其设置为来选择采用事件捕获true
:
document.getElementById('container').addEventListener(
'click',
() => {
//window loaded
},
true
)
注意首先运行所有捕获事件处理程序。
然后是所有冒泡事件处理程序。
顺序遵循此原则:DOM从Window对象开始遍历所有元素,然后查找被单击的项目。这样做时,它将调用与事件关联的任何事件处理程序(捕获阶段)。
一旦到达目标,它就会重复遍历父树的过程,直到Window对象,再次调用事件处理程序(冒泡阶段)。
停止传播
除非停止,否则DOM元素上的事件将传播到其所有父元素树。
<html>
<body>
<section>
<a id="my-link" ...>
的点击事件a
将传播到section
接着body
。
您可以通过调用stopPropagation()
Event的方法,通常在事件处理程序的末尾:
const link = document.getElementById('my-link')
link.addEventListener('mousedown', event => {
// process the event
// ...
event.stopPropagation()
})
热门活动
以下是您可能会处理的最常见事件的列表。
加载
load
被开除window
和body
页面加载完成后的元素。
鼠标事件
click
单击鼠标按钮时触发。dblclick
两次单击鼠标时。当然在这种情况下click
在此事件之前被解雇。mousedown
,mousemove
和mouseup
可以组合使用以跟踪拖放事件。小心mousemove
,因为它在鼠标移动过程中会多次触发(请参见节流之后)
键盘事件
keydown
按下键盘按钮时触发(以及在按钮按下时重复按键的任何时间)停留按下)。keyup
释放键时触发。
滚动
这scroll
事件被触发window
每次滚动页面。在事件处理程序内,您可以通过检查以下内容来检查当前滚动位置window.scrollY
。
请记住,此事件不是一次性事件。它在滚动过程中会触发很多次,而不仅仅是在滚动结束或开始时,所以不要在处理程序中进行任何繁重的计算或操作-使用节流反而。
节流
如上所述,mousemove
和scroll
有两个事件不会在每个事件中一次性触发,而是在动作的所有持续时间内连续调用它们的事件处理函数。
这是因为它们提供了坐标,因此您可以跟踪正在发生的事情。
如果在事件处理程序中执行复杂的操作,则会影响性能并给站点用户带来缓慢的体验。
提供节流功能的库洛达什用100多行代码实施它,以处理所有可能的用例。这是一个简单易懂的实现,它使用setTimeout每100毫秒缓存一次滚动事件:
let cached = null
window.addEventListener('scroll', event => {
if (!cached) {
setTimeout(() => {
//you can access the original event at `cached`
cached = null
}, 100)
}
cached = event
})
免费下载我的JavaScript初学者手册
更多js教程:
- JavaScript中应避免的事情(不良部分)
- JavaScript中的延迟和承诺(+ Ember.js示例)
- 如何使用JavaScript将文件上传到服务器
- JavaScript编码风格
- JavaScript数组简介
- JavaScript编程语言简介
- 完整的ECMAScript 2015-2019指南
- 了解JavaScript承诺
- JavaScript的词汇结构
- JavaScript类型
- JavaScript变数
- 示例Web应用程序提示列表
- JavaScript函数式编程简介
- 具有Async和Await的现代异步JavaScript
- JavaScript循环和范围
- Map JavaScript数据结构
- 设置JavaScript数据结构
- JavaScript模板文字指南
- 学习JavaScript的路线图
- JavaScript表达式
- 发现JavaScript计时器
- JavaScript事件说明
- JavaScript循环
- 使用map,filter,reduce和find编写JavaScript循环
- JavaScript事件循环
- JavaScript函数
- JavaScript词汇表
- JavaScript闭包说明
- JavaScript Arrow函数教程
- JavaScript正则表达式指南
- 如何在JavaScript中检查字符串是否包含子字符串
- 如何从JavaScript中的数组中删除项目
- 如何深度克隆JavaScript对象
- Introduction to Unicode and UTF-8
- JavaScript中的Unicode
- 如何在JavaScript中大写字符串的第一个字母
- 如何在JavaScript中将数字格式化为货币值
- 如何在JavaScript中将字符串转换为数字
- 这在JavaScript中
- 如何在JavaScript中获取当前时间戳
- JavaScript严格模式
- JavaScript立即调用函数表达式(IIFE)
- 如何使用JavaScript重定向到另一个网页
- 如何从JavaScript对象中删除属性
- 如何在JavaScript中将项目追加到数组
- 如何检查JavaScript对象属性是否未定义
- ES模块简介
- CommonJS简介
- JavaScript异步编程和回调
- 如何替换JavaScript中所有出现的字符串
- 现代JavaScript语法快速参考指南
- 如何在JavaScript中修剪数字中的前导零
- 如何检查JavaScript对象
- 关于JavaScript日期的权威指南
- Moment.js教程
- JavaScript中的分号
- JavaScript算术运算符
- JavaScript Math对象
- 在JavaScript中生成随机且唯一的字符串
- 如何使您的JavaScript函数进入睡眠状态
- JavaScript原型继承
- JavaScript例外
- 如何使用JavaScript类
- JavaScript食谱
- JavaScript中的引号
- 如何在JavaScript中验证电子邮件地址
- 如何获取JavaScript数组中一组对象的唯一属性
- 如何在JavaScript中检查字符串是否以另一个字符串开头
- 如何在JavaScript中创建多行字符串
- ES6指南
- 如何在JavaScript中获取当前URL
- ES2016指南
- 如何使用JavaScript中的值初始化新数组
- ES2017指南
- ES2018指南
- 如何在Array.prototype.map()中使用Async和Await
- 异步与同步代码
- 如何在JavaScript中生成两个数字之间的随机数
- HTML Canvas API教程
- 如何在JavaScript中的for-of循环中获取迭代的索引
- 什么是单页应用程序?
- WebAssembly简介
- JSON简介
- JSONP指南
- Should you use or learn jQuery in 2020?
- 如何使用纯JavaScript隐藏DOM元素
- 如何在JavaScript中合并两个对象
- 如何清空JavaScript数组
- 如何使用JavaScript编码URL
- 如何在JavaScript中设置默认参数值
- 如何在JavaScript中按属性值对对象数组进行排序
- 如何计算JavaScript对象中的属性数量
- JavaScript中的call()和apply()
- WebRTC库PeerJS简介
- 使用Rest and Spread处理对象和数组
- 用JavaScript分解对象和数组
- 调试JavaScript的权威指南
- TypeScript指南
- 在JavaScript中动态选择对象的方法
- 将undefined传递给JavaScript立即调用的函数表达式
- 松散类型与强类型语言
- 如何使用JavaScript设置DOM元素的样式
- 用JavaScript投放
- JavaScript生成器教程
- node_modules文件夹的大小不是问题。这是一种特权
- 在JavaScript中导入模块时如何解决意外的标识符错误
- 如何在JavaScript中列出对象的所有方法
- 字符串replace()方法
- 字符串search()方法
- 我如何运行一些JavaScript代码段
- ES2019指南
- 字符串charAt()方法
- 字符串charCodeAt()方法
- 字符串codePointAt()方法
- 字符串concat()方法
- 字符串endsWith()方法
- 字符串include()方法
- 字符串indexOf()方法
- 字符串lastIndexOf()方法
- 字符串localeCompare()方法
- 字符串match()方法
- 字符串normalize()方法
- 字符串padEnd()方法
- 字符串padStart()方法
- 字符串repeat()方法
- 字符串slice()方法
- 字符串split()方法
- 字符串startsWith()方法
- String substring()方法
- 字符串toLocaleLowerCase()方法
- 字符串toLocaleUpperCase()方法
- String toLowerCase()方法
- 字符串toString()方法
- String toUpperCase()方法
- 字符串trim()方法
- String trimEnd()方法
- String trimStart()方法
- JavaScript的记忆化
- 字符串valueOf()方法
- JavaScript参考:字符串
- Number isInteger()方法
- Number isNaN()方法
- Number isSafeInteger()方法
- Number parseFloat()方法
- Number parseInt()方法
- Number toString()方法
- Number valueOf()方法
- Number toPrecision()方法
- Number toExponential()方法
- Number toLocaleString()方法
- Number toFixed()方法
- Number isFinite()方法
- JavaScript参考:数字
- JavaScript属性描述符
- 对象的assign()方法
- 对象的create()方法
- Object defineProperties()方法
- Object defineProperty()方法
- 对象entry()方法
- 对象Frozen()方法
- Object getOwnPropertyDescriptor()方法
- Object getOwnPropertyDescriptors()方法
- Object getOwnPropertyNames()方法
- Object getOwnPropertySymbols()方法
- Object getPrototypeOf()方法
- Object is()方法
- Object isExtensible()方法
- Object isFrozen()方法
- Object isSealed()方法
- 对象keys()方法
- 对象的preventExtensions()方法
- 对象seal()方法
- Object setPrototypeOf()方法
- Object values()方法
- 对象的hasOwnProperty()方法
- Object isPrototypeOf()方法
- 对象的propertyIsEnumerable()方法
- Object toLocaleString()方法
- Object toString()方法
- Object valueOf()方法
- JavaScript参考:对象
- JavaScript赋值运算符
- JavaScript国际化
- JavaScript typeof运算子
- JavaScript新运算符
- JavaScript比较运算符
- JavaScript运算符优先级规则
- JavaScript instanceof运算符
- JavaScript陈述式
- JavaScript范围
- JavaScript类型转换(广播)
- JavaScript相等运算符
- JavaScript if / else条件
- JavaScript切换条件
- JavaScript删除运算符
- JavaScript函数参数
- JavaScript Spread运算符
- JavaScript返回值
- JavaScript逻辑运算符
- JavaScript三元运算符
- JavaScript递归
- JavaScript对象属性
- JavaScript错误对象
- JavaScript全局对象
- JavaScript filter()函数
- JavaScript map()函数
- JavaScript reduce()函数
- JavaScript`in`运算子
- JavaScript运算子
- 如何在JavaScript中获取CSS属性的值
- 如何将事件侦听器添加到JavaScript中的多个元素
- JavaScript私有类字段
- 如何在JavaScript中按日期值对数组排序
- JavaScript公共类字段
- JavaScript符号
- 如何使用JavaScript bcrypt库
- 使用对象解构时如何重命名字段
- 如何在不使用TypeScript的情况下检查JavaScript中的类型
- 如何检查JavaScript数组是否包含特定值
- 双重否定运算符是什么!用JavaScript做吗?
- JavaScript比较中应使用哪个等号运算符? == vs ===
- JavaScript仍然值得学习吗?
- 如何在JavaScript中返回异步函数的结果
- 如何在JavaScript中检查对象是否为空
- 如何突破JavaScript中的for循环
- 如何在JavaScript中的特定索引处将项目添加到数组
- 为什么不应该修改JavaScript对象原型
- 在JavaScript中使用let和var有什么区别?
- 用于激活JavaScript功能的链接
- 如何在JavaScript中连接两个字符串
- 如何在JavaScript中连接两个数组
- 如何检查JavaScript值是否为数组?
- 如何在JavaScript中获取数组的最后一个元素?
- 如何使用Axios发送urlencoded数据
- 如何使用JavaScript获取明天的日期
- 如何使用JavaScript获取昨天的日期
- 如何从JavaScript日期获取月份名称
- 如何检查两个日期是否在JavaScript中是同一天
- 如何在JavaScript中检查日期是否指向过去的一天
- 标有JavaScript的语句
- 如何等待2个或更多的Promise在JavaScript中解析
- 如何在JavaScript中获取两个日期之间的日期
- 如何使用提取上传文件
- 如何在JavaScript中格式化日期
- 如何遍历JavaScript中的对象属性
- 如何在JavaScript中计算两个日期之间的天数
- 如何在ES模块中使用顶级等待
- JavaScript动态导入
- JavaScript可选链接
- 如何在JavaScript中替换字符串内的空格
- JavaScript空合并
- 如何在JavaScript中展平数组
- JavaScript的十年
- 如何使用Axios发送授权标头
- JavaScript中的关键字和保留字列表
- 如何在JavaScript中将数组转换为字符串
- 如何删除所有的node_modules文件夹内容
- 如何从JavaScript数组中删除重复项
- 在JavaScript中让vs const
- 各种JavaScript库中的相同POST API调用
- 如何在JS中获取数组中的前n个项目
- 如何在JS中将数组划分为多个相等的部分
- 如何减慢JavaScript中的循环
- 如何在HTML画布中加载图像
- 如何在JavaScript中将字符串切成单词
- 如何在JavaScript中将数组分成两半
- 如何将文本写入HTML画布
- 如何在JavaScript中删除字符串的最后一个字符
- 如何在JavaScript中删除字符串的第一个字符
- 如何修复TypeError:无法分配为只读对象“#&lt; Object&gt;”的属性“ exports”错误
- 如何创建退出意图弹出窗口
- 如何检查一个元素是否是另一个元素的后代
- 如何对每个Axios请求强制使用凭据
- 如何解决JavaScript中的“不是函数”错误
- 盖茨比,如何更改图标
- 使用Gatsby加载外部JS文件
- 如何使用JavaScript检测暗模式
- 包裹,如何修复“ regeneratorRuntime未定义”错误
- 如何检测Adblocker是否与JavaScript一起使用
- 使用TypeScript中的类型进行对象分解
- Deno手册:Deno的简要介绍🦕
- 如何使用JavaScript获取路径或URL的最后一段
- 如何随机播放JavaScript数组中的元素
- 如何检查JavaScript对象中是否存在密钥
- 事件冒泡和事件捕获
- event.stopPropagation与event.preventDefault()与在DOM事件中返回false
- JavaScript中的原始类型与对象
- 在JavaScript中,如何判断值的类型?
- 如何从JavaScript中的函数返回多个值
- JavaScript中的箭头函数与常规函数
- 我们可以通过哪些方式访问对象属性的值?
- JavaScript中的null和undefined有什么区别?
- 方法和函数有什么区别?
- 我们可以通过哪些方法摆脱JavaScript循环?
- JavaScript for..of循环
- 什么是JavaScript中的对象解构?
- JavaScript吊起了什么?
- 如何使用JavaScript将逗号更改为点
- 使用DOM时计时的重要性
- 如何反转JavaScript数组
- 如何在JavaScript中检查值是否为数字
- 如何在JavaScript函数中接受无限的参数
- JavaScript代理对象
- 使用香草JavaScript在浏览器中进行事件委托
- JavaScript super关键字
- XState简介
- 值是通过引用传递还是通过JavaScript中的值传递?
- JavaScript中的自定义事件
- JavaScript中的自定义错误
- JavaScript中的命名空间
- JavaScript中逗号的奇怪用法
- JavaScript中的链接方法调用
- 如何处理承诺拒绝
- 如何在JavaScript中交换两个数组元素
- 如何在使用Gitbook时解决“ cb.apply不是函数”错误
- 如何在JavaScript中的数组开头添加项目
- Gatsby,修复“找不到模块gatsby-cli / lib / reporter”错误
- 如何获取JavaScript数组中项目的索引
- 如何在JavaScript中测试空对象
- 如何将对象解构为JavaScript中的现有变量
- 数组JavaScript数据结构
- 堆栈JavaScript数据结构
- JavaScript数据结构:队列
- JavaScript数据结构:集
- JavaScript数据结构:字典
- JavaScript数据结构:链接列表
- JavaScript,如何导出函数
- JavaScript,如何导出多个功能
- JavaScript,如何退出功能
- JavaScript,如何在字符串中查找字符
- JavaScript,如何过滤数组
- JavaScript,如何扩展类
- JavaScript,如何在数组中查找重复项
- JavaScript,如何替换数组的项
- JavaScript算法:线性搜索
- JavaScript算法:二进制搜索
- JavaScript算法:选择排序
- JavaScript算法:Quicksort
- JavaScript算法:合并排序
- JavaScript算法:冒泡排序