当前位置: 首页 > news >正文

前端JavaScript-嵌套事件

点击

如果在多层嵌套中,对每层都设置事件监视器,试试看

<!DOCTYPE html>
<html lang="cn">
<body><div id="container"><button>点我!</button></div><pre id="output"></pre><script src="button.js"></script>"
</body>
</html>
const output = document.querySelector("#output");
const container = document.querySelector("#container");
const button = document.querySelector("button");function handleClick(e) {output.textContent += `你在 ${e.currentTarget.tagName} 元素上进行了点击\n`;
}document.body.addEventListener("click", handleClick);
container.addEventListener("click", handleClick);
button.addEventListener("click", handleClick);

在 JS 脚本中先用 querySelector (querySelector是JS原生提供的DOM元素查找函数,是DOM API中的一部分,它的作用是通过 CSS选择器 定位匹配的第一个元素)来确定了 output 和 container 位置并赋值给变量

(CSS选择器通过特定语法匹配HTML元素并应用样式,通过 .class 、 #id ,将其应用到JS里面来提取元素的好处就是不用更改语法)

接着设置了自定义函数 handleClick(e) ,参数e是一个事件对象(Event object),这是浏览器自动传递给事件处理函数的一个参数,比如 button.addEventListener("click", handleClick); 这告诉了如果点击了button那么就调用 handleClick,这时会自动生成一个事件对象,其中 e.currentTarget 就是监听对象 button ,而 e.currentTarget.tagName 就是 事件监听器对象元素的标签名

这个事件并不是通过 alert 实现输出,而是直接更改 DOM元素output 的值,这会在点击后直接显示

你在 BUTTON 元素上进行了点击
你在 DIV 元素上进行了点击
你在 BODY 元素上进行了点击

可以看到三层元素都触发了单击事件

可以观察到

        最先触发的是按钮的

        然后是其父元素...

可以理解为:事件从点击的最里层的元素冒泡而出

.target 和 .currentTarget 有什么区别

event.target 和 event.currentTarget 都指向DOM元素,但是

        event.target 指向的是触发事件的元素,在冒泡过程中是保持不变的

        event.currentTarget 指向的是事件处理程序当前附加到的元素,也就是当前处理层的元素

注册而非轮询

也许你会好奇,为什么我都没有加 while ,我一旦触发事件还是会有相应的结果呢?

其实事件监视器是被动的、称为“事件驱动程序”的模式

在浏览器内部有一个事件循环机制,它会不断地持续检查队列中是否有事件要处理

异步处理:当用户触发事件时,浏览器会将这个事件放入事件队列,事件循环一旦检测到队列中有事件就会用相应的事件处理(异步处理是一种编程和系统设计模式,其核心在于非阻塞执行,在发起耗时操作,如IO、网络请求等后,程序不会等待操作完成,而是继续执行后续任务,等操作完成再回调

(不阻塞:不会阻塞主线程或消耗CPU资源来主动检查事件是否发生,只有事件触发时相关代码才会执行)

在线程、线程池、异步-CSDN博客有更详细说明

隐藏

我们想要实现隐藏视频,只有在点击按钮的时候才显现,这时候点击视频会开始播放,点击除视频外的地方会隐藏视频

<button>显示视频</button><div class="hidden"><video><source src="/shared-assets/videos/flower.webm" type="video/webm" /><p>你的浏览器不支持 HTML 视频,这里有视频的<a href="rabbit320.mp4">替代链接</a>。</p></video>
</div>
const btn = document.querySelector("button");
const box = document.querySelector("div");
const video = document.querySelector("video");btn.addEventListener("click", () => box.classList.remove("hidden"));
video.addEventListener("click", () => video.play());
box.addEventListener("click", () => box.classList.add("hidden"));

在 JS 里面添加了三个 'click' 事件处理器

classList 是 DOM 元素对象的一个属性,提供了一个便捷的方式来操作元素的类(class属性),它是 DOMTokenList 类型的对象,用于添加、删除、检查和切换 CSS 类

button 的点击处理器会通过 box 的 classList 移除 div 的 "hidden" 类

在运行的时候会发现点击按钮的时候会显示视频,但是点击视频的时候盒子又被隐藏了,这是因为 video 在 div 里面,所以点击视频会触发 video 的事件,也会触发 div 的事件

这时候我们就想要阻止 video 向外界的感染,需要通过 stopPropagation( ) 方法

const btn = document.querySelector("button");
const box = document.querySelector("div");
const video = document.querySelector("video");btn.addEventListener("click", () => box.classList.remove("hidden"));video.addEventListener("click", (event) => {event.stopPropagation();video.play();
});box.addEventListener("click", () => box.classList.add("hidden"));

可以看到我们在 video 的事件里面添加了 event.stopPropagation();

事件捕捉

跟冒泡顺序相反,从最外层到最里面,想实现这样的操作只需要将 capture 参数设置为 true

比如刚开始的按钮例子

document.body.addEventListener("click", handleClick, { capture: true });
container.addEventListener("click", handleClick, { capture: true });
button.addEventListener("click", handleClick);

顺序就发生了颠倒

你在 BODY 元素上进行了点击
你在 DIV 元素上进行了点击
你在 BUTTON 元素上进行了点击

事件委托

默认冒泡的话,我们可以通过子元素感染父元素,而不用一个个设置了,不直接在子元素上设置监听器,而是将监听器设置在父元素上,通过冒泡让父元素监听来自子元素的事件,

<!DOCTYPE html>
<html lang="en"></html>
<body><link href="button.css" rel="stylesheet" type="text/css"><div id="container"><div class="tile"></div><div class="tile"></div><div class="tile"></div><div class="tile"></div><div class="tile"></div><div class="tile"></div><div class="tile"></div><div class="tile"></div><div class="tile"></div><div class="tile"></div><div class="tile"></div><div class="tile"></div><div class="tile"></div><div class="tile"></div><div class="tile"></div><div class="tile"></div></div><script src="button.js"></script>"
</body>
</html>
.tile {height: 100px;width: 25%;float: left;
}
function random(number) {return Math.floor(Math.random() * number);
}function bgChange() {const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;return rndCol;
}const container = document.querySelector("#container");container.addEventListener("click", (event) => {event.target.style.backgroundColor = bgChange();
});

在这个例子中有很多 .title 元素在 #container 内

但是没有对每个元素添加事件监听器

而是在父元素 #container 上加了监听器,通过 event.target 来确定是哪个子元素触发了事件,并更改其 style.backgroundColor 为 bgChange

http://www.xdnf.cn/news/567739.html

相关文章:

  • matlab加权核范数最小化图像去噪
  • Linux——PostgreSQL数据库日常维护
  • 25_05_19Linux实战篇、第一章_02若依前后端部署之路(前端)
  • 在 Excel xll 自动注册操作 中使用东方仙盟软件————仙盟创梦IDE
  • 代码随想录 算法训练 Day8:字符串part01
  • 关于TCP三次握手
  • 【ULR #1】打击复读 (SAM, DAG链剖分)
  • PHP学习笔记(八)
  • Linux操作系统之进程(二):进程状态
  • cocos creator使用jenkins打包微信小游戏,自动上传资源到cdn,windows版运行jenkins
  • 攻防世界-stegano
  • 物流项目第五期(运费计算实现、责任链设计模式运用)
  • TDengine 运维—容量规划
  • 学习 Android(十一)Service
  • 安卓蓝牙frameworks/base/core/java/android/bluetooth这个路径下文件的作用
  • Android 自定义SnackBar和下滑取消
  • 命令行参数和环境变量
  • 力扣热题100,力扣148.排序链表力扣.26找出字符串中第一个匹配项的下标力扣146.LRU缓存序列管理器
  • MySQL 8.0 OCP 1Z0-908 171-180题
  • Keepalived 配置深度解析及最佳实践
  • 回表是数据库概念,还是mysql的概念?
  • MyBatis 关联映射深度解析:_association_ 与 _collection_ 实战教程
  • k8s-ServiceAccount 配置
  • spring5-配外部文件-spEL-工厂bean-FactoryBean
  • 【疑难杂症】Mysql 无报错 修改配置文件后服务启动不起来 已解决|设置远程连接
  • Redis SETNX:分布式锁与原子性操作的核心
  • Docker run命令-p参数详解
  • Python打卡训练营day28-类的定义与方法
  • 2021-04-12 VSC++: 寻找N以内的亲密数对。(求因子和)
  • 【Node.js】Web开发框架