目录
浏览器的事件机制是web前端面试及开发过程中绕不开的话题,可以说一切用户操作或者浏览器的行为都离不了事件,它允许开发者通过JS处理用户的操作,并处理操作逻辑,将结果反馈给用户。本篇文章将深入浏览器事件的运行机制,和大家一起探讨其强大的功能及广泛的用法
浏览器的事件,参考事件列表大致可以分为以下几类:
常见的鼠标事件有
键盘事件
常见的键盘事件:
常用的表单事件:
窗口事件一般作用于window对象上,常用的事件有:
Dom一般用于监听文档操作:
多媒体事件一般在audio,video标签上进行操作:
当给元素增加draggable属性时,标签就具备被拖拽功能,我们可以使用以下事件监听标签拖拽操作:
移动事件类似鼠标操作:
剪切板事件是当用户选中文本时在标签上操作剪切板的动作:
错误事件一般出现在加载文件,资源,音视频,链接等地方:
当标签使用过渡或者动画时,会触发以下事件:
事件监听有两种方式,分别是on+event和addEventListener(event)两种方式(event表示上面的事件名称)
on+event可以直接在HTML标签中使用,添加参数event可以将事件对象传递到函数中
- <button onclick="handleClick(event)">点击button>
- <button onclick="handleClick()">点击2button>
- <script>
- const handleClick = (e) => {
- console.log(e);
- }
- script>
在JS中也可以通过element.on+event的方式给标签添加事件监听
- <body>
- <button id="btn3">点击3button>
- <script>
- const handleClick = (e) => {
- console.log(e);
- }
- btn3.onclick = handleClick
- script>
- body>
在JS中使用on+event的方式给标签添加事件监听时,后面的监听函数会覆盖前面的,当我们要取消监听时直接给on+event赋值null即可,思考下面的代码:
- <body>
- <button id="btn3">点击3button>
- <script>
- const handleClick = (e) => {
- e.target.onclick = handleClick2
- console.log("handleClick");
- }
- const handleClick2 = (e) => {
- e.target.onclick = null
- console.log("handleClick2");
- }
- btn3.onclick = (e) => {
- console.log("onclick");
- e.target.onclick = handleClick
- }
- script>
- body>
当我们使用on+event给标签添加事件时,后定义的函数会覆盖前面的,这就会导致函数耦合度变高,维护性降低,举个例子,下面的代码中点击btn3时就会触发三个fn,此时如果我需要解除fn1的执行,只能修改onclick函数的逻辑,如何解决这种问题呢?
- <body>
- <button onclick="handleClick(event)">点击button>
- <button onclick="handleClick()">点击2button>
- <button id="btn3">点击3button>
- <script>
- btn3.onclick = (e) => {
- fn1()
- fn2()
- fn3()
- }
- const fn1 = () => {
- console.log(111);
- }
- const fn2 = () => {
- console.log(222);
- }
- const fn3 = () => {
- console.log(333);
- }
- script>
- body>
JS提供了element.addEventListener(event,fn)的方式用于给标签添加事件监听,使用addEventListener函数可以给标签添加多个事件钩子函数
- <body>
- <button id="btn1">点击button>
- <button id="btn2">点击2button>
- <script>
- btn1.addEventListener("click", handleClick1)
- btn1.addEventListener("click", handleClick3)
- btn2.addEventListener("click", handleClick2)
- function handleClick1(e) {
- console.log(e);
- console.log("handleClick1");
- }
- function handleClick2(e) {
- console.log(e);
- console.log("handleClick2");
- }
- function handleClick3(e) {
- console.log(e);
- console.log("handleClick3");
- }
- script>
- body>
通过removeEventListener移除某个事件的监听,思考下面的代码,我实现了一个事件的once功能,执行一次后立即注销事件
- <body>
- <button id="btn1">点击button>
- <script>
- btn1.addEventListener("click", handleClick1)
- function handleClick1(e) {
- console.log("handleClick1");
- btn1.removeEventListener("click", handleClick1)
- }
- script>
- body>
addEventListener第二个参数除了可以是函数外,还可以传入一个对象,当其为对象类型时,可以传入一个handleEvent属性充当事件函数
- btn1.addEventListener("click", {
- handleEvent: handleClick2
- })
addEventListener的第三个参数是一个布尔值或配置对象,用于指定更多选项,当其类似是布尔时,true表示监听捕获阶段反之则是监听冒泡;当这个参数传入的是一个对象时,里面包含以下配置:
- <body>
- <button id="btn1">点击button>
- <script>
- btn1.addEventListener("click", handleClick3, {
- once: true,
- passive: true,
- capture: true
- })
- function handleClick3(e) {
- console.log("handleClick3");
- }
- script>
- body>
这三个配置默认值都是false
事件触发有两种方式,分别是用户操作或者浏览器触发的和手动使用触发器触发,手动触发的两种方式分别使用element的event名和dispatchEvent进行触发事件
第一种是使用event名直接调用标签的操作,比如:click(),focus()等
- <body>
- <button id="btn1">按钮1button>
- <button id="btn2">按钮2button>
- <button id="btn3">按钮3button>
- <script>
- btn1.addEventListener("click", (e) => {
- console.log("点击按钮1");
- btn2.click()
- })
- btn2.addEventListener("click", (e) => {
- console.log("点击按钮2");
- btn3.click()
- })
- btn3.addEventListener("click", (e) => {
- console.log("点击按钮3");
- })
- script>
- body>
第二种是使用dispatchEvent进行事件抛发
- // 创建自定义点击事件
- const clickEvent = new Event('click');
- // 手动触发自定义事件
- btn3.dispatchEvent(clickEvent);
完整代码:
- <button id="btn1">按钮1button>
- <button id="btn2">按钮2button>
- <button id="btn3">按钮3button>
- <script>
-
- btn1.addEventListener("click", (e) => {
- console.log("点击按钮1");
- btn2.click()
- })
- btn2.addEventListener("click", (e) => {
- console.log("点击按钮2");
- // 创建自定义点击事件
- const clickEvent = new Event('click');
- // 手动触发自定义事件
- btn3.dispatchEvent(clickEvent);
- })
- btn3.addEventListener("click", (e) => {
- console.log("点击按钮3");
- })
- script>
一个完整的事件流程包括三个阶段,分别是捕获(Captur),目标(Target)和冒泡(Bubbling),过程如下图。
任何在以下三种阶段注册的事件监听器会在每个阶段被触发。
事件首先从根元素(通常是html)向下传播到目标元素的过程。在这个阶段,事件会依次经过DOM树中的每个祖先元素,直到达到事件的目标元素。
在捕获阶段增加的事件监听函数会在事件的捕获阶段触发,在上文我们提到了给addEventListener增加配置项可以使handler在事件捕获时调用,思考下面的代码:
- <body>
- <div id="outBox">
- <div id="inBox">
- <div id="targetBox">
- 点击
- div>
- div>
- div>
- <script>
- outBox.addEventListener("click", (e) => {
- console.log("outBox");
- }, true)
- inBox.addEventListener("click", (e) => {
- console.log("inBox");
- }, true)
- targetBox.addEventListener("click", (e) => {
- console.log("targetBox");
- }, true)
- /*
- outBox
- inBox
- targetBox
- */
- script>
- body>
一旦事件达到了目标元素,就会在目标元素上触发事件。这是事件的目标,通常是用户交互的对象。
事件从目标元素开始,然后向上冒泡到根元素的过程。在这个阶段,事件会依次经过DOM树中的每个祖先元素,直到达到根元素。
冒泡阶段与捕获相反,在冒泡阶段增加的事件监听函数会在事件的冒泡阶段触发,将addEventListener的capture配置项改成false或者默认不传配置参数,就会使handler回调在事件冒泡时触发,思考下面的代码:
- <body>
- <div id="outBox">
- <div id="inBox">
- <div id="targetBox">
- 点击
- div>
- div>
- div>
- <script>
- outBox.addEventListener("click", (e) => {
- console.log("outBox");
- })
- inBox.addEventListener("click", (e) => {
- console.log("inBox");
- })
- targetBox.addEventListener("click", (e) => {
- console.log("targetBox");
- })
- /*
- targetBox
- inBox
- outBox
- */
- script>
- body>
tips:使用on属性监听标签的事件时,不支持在捕获阶段的监听
事件对象是指事件的钩子函数的event参数,常用的属性有:
浏览器事件机制是前端开发中非常重要的一部分,本文深入探讨了浏览器事件机制的各个方面,包括不同类型的事件、事件监听的方式、事件触发方式、事件流程以及事件对象的使用。对于开发者来说,熟悉浏览器事件机制是非常重要的,它可以帮助开发者实现各种交互和动态效果,提升用户体验。
以上就是文章全部内容了,感谢你看到了最后,如果觉得文章不错的话,还望三连支持一下,谢谢!