js-事件及事件委托

2023-11-04

1. 事件

当用户浏览网页时,存在许许多多与网页交互的操作。例如按钮的点击、屏幕的滑动、鼠标的移动等等,通过这些交互完成某些操作,达到某种效果。我们可以将这些交互称之为事件。

2. 事件冒泡

事件冒泡是指事件在某个元素上触发后一直向上传播(父元素),一直传播到document。如果向上冒泡的过程中遇到相同的事件,则触发。例如下面的例子:

<body>
    <div id="myDiv">
        <ul>
            <li id="myLi">1</li>
        </ul>
    </div>
    <script>
        const li = document.getElementById('myLi')
        li.onclick = function () {
            console.log(this.id); //myLi
        }

        const div = document.getElementById('myDiv')
        div.addEventListener('click', function () {
            console.log(this.id); //myDiv
        })
    </script>
</body>

在这里插入图片描述
当我们点击li标签的时候,会触发li上绑定的click事件,但是在触发li的click事件后会触发div上绑定的click事件。这就是事件冒泡,其实仔细想想这也是可以理解的,因为点击了li标签则意味着div也被点击了。就像你住在中国的某个省,那你肯定住在中国。上面的冒泡总过程如下:

li 》ul 》 div 》body 》html 》document

3. 事件捕获

事件捕获与事件冒泡正好是个相反的过程,事件捕获会从document开始,然后一次向下传播,直到具体的元素

//dom2事件处理程序才能控制事件捕获与事件冒泡
//并且只有addEventListener的第三个参数设置为true才会是事件捕获,false是事件冒泡。
const lis = document.getElementsByTagName('li')
for (const li of lis) {
	li.addEventListener('click', () => {
		console.log('li click');
	}, true)
}

const div = document.getElementById('myDiv')
div.addEventListener('click', () => {
	console.log('div click');
}, true)

在这里插入图片描述
可以看出事件捕获与事件冒泡确实是相反的,事件捕获先执行了div的click事件,然后执行li的click事件。捕获的顺序如下

document 》html 》body 》div 》ul 》li

4. 事件模型

4.1 DOM0事件模型

DOM0事件模型比较简单,只需要将事件处理函数赋值给一个事件处理程序属性。目前的所有浏览器都支持该方式。

const div = document.getElementById('myDiv')
div.onclick = function () {
    console.log(this.id) // myDiv
}

DOM0事件模型中移除事件方式直接将事件处理程序属性的值设置为null就行

div.onclick = null

4.2 DOM2事件模型

DOM2事件模型为事件处理程序的赋值和移除定义了两个方法:addEventListener()和removeEventListener()。它们接收3个参数:事件名、事件处理函数、布尔值(默认false),true表示捕获阶段调用事件处理程序,false表示冒泡阶段调用事件处理程序。

const div = document.getElementById('myDiv')
const handler = function () {
	console.log(this.id);
}
// 绑定click事件
div.addEventListener('click', handler)

// 移除click事件
div.removeEventListener('click', handler)
// 绑定click事件
div.addEventListener('click', function () {
	console.log(this.id);
})

// 无法移除click事件
div.removeEventListener('click', function () {
	console.log(this.id);
})

tip: 传给addEventListener、removeEventListener的事件处理函数必须先赋值给一个变量,然后共同使用才能对绑定的事件进行移除,否则移除不了绑定的事件。因为在无法移除的情况下,虽然事件处理函数看起来是相同的,但是实际上是两个不同的函数,有不同的内存地址。

4.3 IE事件模型

IE事件模型为事件处理程序的赋值和移除定义了两个方法:attachEvent()和attachEvent()。它们接收2个参数:事件名、事件处理函数。因为 IE8 及更早版本只支持事件冒泡,所以使用 attachEvent()添加的事件处理程序会添加到冒泡阶段。

const div = document.getElementById('myDiv')
const handler = function () {
	console.log(this.id);
}

//添加点击事件,注意是onClick
div.attachEvent("onclick", handler);

//移除事件
div.detachEvent("onclick", handler);

4.4 3种事件模型的其他事项

DOM0事件中this指向当前元素

DOM0事件中为同一个元素赋值两次onclick,后面会覆盖前面的(因为是赋值)

DOM2事件中this指向当前元素

DOM2可以通过addEventListener为同一个元素添加多个事件函数,并且顺序执行(观察者模式)

IE事件模型中事件处理程序是在全局作用域中运行的,因此 this 等于 window

IE事件模型可以通过attachEvent为同一个元素添加多个事件函数,但是是逆序执行的,即先添加的最后执行

5. 事件委托

事件委托又称为事件代理,事件委托就是将原本绑定到子元素的事件委托给父元素。在开发中最常见的就是菜单栏由ul和多个子li标签组成。如果要为菜单栏添加点击事件,通常方法是直接在li上绑定对应的点击事件。但是这样不利于未来添加其他的菜单项,即所谓的可扩展性。而且为每个li添加事件是费时费力的。所以通常解决办法是利用事件冒泡的特性,将事件绑定到ul标签上。

通俗的例子就是寝室中,本来是每个人都要去取快递的,但是一想这样太浪费人力了,所以非常民主地选择寝室长一个人去,一起代领。

下面看下实际的例子:

<body>
    <ul id="myUl">
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>
    <script>
        //事件委托实现
        const ul = document.getElementById('myUl')
        ul.onclick = function (e) {
            console.log(e.target.innerHTML);
        }

		//事件委托的等效代码:为每个li添加事件,
        const lis = document.getElementsByTagName('li')
        for (const li of lis) {
            li.onclick = function () {
                console.log(this.innerHTML);
            }
        }
    </script>
</body>

在这里插入图片描述
事件委托可以通过从事件对象的target属性中获取点击的目标,可以看出使用事件委托,只需要在父元素上绑定所需的事件。而通过一般的事件绑定则需要为每个子元素绑定事件。

事件委托的优势:

通过使用事件委托不需要为每个子元素设置事件函数,可以减少页面所需的内存,提升页面的整体性能;实现事件的动态绑定,新增节点不必单独添加监听事件,发生的事件交给父元素。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

js-事件及事件委托 的相关文章

  • 音频标签的 Html5 惰性“onplay”事件处理程序?

    使用新的 Html5 音频标签 onplay 事件似乎仅在第一次播放音频时触发 在此示例中 当单击 播放 时 音频将开始并显示一个显示 正在播放 的警报弹出窗口 当音频结束并再次单击 播放 时 音频会再次开始 但不会触发警报 我在这里错过了
  • 如何查询和过滤 Firebase 实时数据库 [重复]

    这个问题在这里已经有答案了 我想从数据库中获取所有人员 其中名字和姓氏由用户输入给出 到目前为止 这是我的代码 admin database ref persons orderByChild Firstname equalTo firstN
  • 从多层嵌套数组 JavaScript 中获取所有键值

    我有一个这样的对象 var data id 36e1e015d703120058c92cf65e6103eb title Alex McGibbon id 60beb5e7d7600200e5982cf65e6103ad title Ale
  • 使用ajax发送表单数据

    我想用 ajax 以表单形式发送所有输入 我有一个这样的表单
  • codePointAt 和 charCodeAt 之间的区别

    有什么区别String prototype codePointAt and String prototype charCodeAt 在 JavaScript 中 A codePointAt 65 A charCodeAt 65 从 MDN
  • 使用 jQuery live() 初始化插件?

    使用 jQuery 在特定类的所有当前和未来元素上自动初始化插件的最佳方法是什么 例如 假设我想要全部
  • 为什么人们将自己的自定义/用户函数添加到 jQuery 对象中? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我见过人们将自己的自定义 用户功能添加到jQuery目的 例如 myUserFunc function regular JS code 你为什么
  • 如何使用 JavaScript 压缩文件?

    有没有办法使用 JavaScript 来压缩文件 例如 在雅虎邮件中 当您选择下载电子邮件中的所有附件时 它会被压缩并下载到单个 zip 文件中 JavaScript 能够做到这一点吗 如果是这样 请提供一个编码示例 我发现这个图书馆叫js
  • 如何使用javascript将视频文件转换为字符串?

    我在 signalR 工作 我想通过将视频文件拆分为不同部分来将视频文件从一个客户端发送到另一个客户端 我已经通过分割图像源数据发送图像并在另一个客户端上接收该图像 document getElementById fileUpload ad
  • AngularJS 服务并承诺最佳实践

    我有一个 AngularJS 应用程序services 调用 http资源并返回promise我在控制器中解决了这个问题 这是我正在做的事情的示例 app service Blog function http q var deferred
  • linkedin js 如何是有效的 javascript

    LinkedIn Javascript 集成是通过以下方式完成的 我不明白 这怎么是一个有效的javascript 为什么 api key 没有被引用 脚本标签的主体带有src永远不会被执行 但是 加载的脚本可以像访问任何其他元素的内容一样
  • 当系列没有相同的时间值时,如何在工具提示中显示所有系列

    我有一个显示多个时间序列的图表 不同时间序列不会同时采样 有没有办法在工具提示中显示所有系列 在示例中 您可以看到所有系列都包含在前 2 个点的工具提示中 因为它们是同时采样的 其余点仅包含 1 个系列 var myChart echart
  • 如何将类组件中的 props 发送到功能组件?

    我是 ReactJS 的初学者 需要知道如何将一个页面中的 props 值发送到另一个页面 道具位于第一页上我可以获取类组件值如何获取另一页中的值 提前致谢 墙色 jsx import React Component from react
  • Python 中的 Firebase 身份验证时出现 KeyError:“databaseURL”

    相信你做得很好 我是 firebase 的新手 正在尝试进行用户身份验证 我已经安装了pyrebase4并在firebase控制台上创建了一个项目 我还启用了使用 电子邮件和密码 登录并尝试连接我的应用程序 下面是我正在尝试的代码 impo
  • 数据表 - 从 AJAX 源过滤数据

    我有一个数据表 正在从 api 获取数据 现在我的状态是活动的 非活动的 如果标志是活动的 那么我需要在数据表中显示 否则我不应该显示过期的 这是我的fiddle https jsfiddle net lakshmipriya001 qLp
  • 单击 html 中的按钮后如何从 javascript 函数写入文件

    我正在尝试编写真正基本的代码 在 html 文件上按下按钮后 通过 JavaScript 函数在本地写入 txt 文件 这不可能吗 我可以仅使用 javascript 文件写入文件 但在尝试同时使用两者时则不能
  • 如何在 getStaticPaths 内添加 params 值数组

    我有一个页面 其结构如下 read slug number 我想要得到slug每个对应的值number in the getStaticPaths这是代码 export async function getStaticPaths const
  • 如何加载Jquery Tiny滚动条

    所以我想自定义一个滚动条 我发现了一个很小的滚动条 这是一个jquery插件 http baijs nl tinyscrollbar http baijs nl tinyscrollbar 问题是 无论如何我都无法让它工作 我将 Jquer
  • 使用 CSP 防止自动点击链接 XSS 攻击

    当将 CSP 用于稍微不同的目的 沙箱 时 我意识到一个非常简单的自动点击链接似乎甚至可以绕过相对严格的 CSP 我所描述的内容如下 内容安全政策 default src none script src unsafe inline 还有身体
  • 如何向 SvelteKit/Vite 应用添加版本号?

    我正在尝试在我的 SvelteKit 应用程序中创建一个系统 它会在某个页面上向您显示有关当前应用程序版本的信息 最好是 Git 提交哈希和描述 我尝试使用Vite的定义功能 https vitejs dev config define在构

随机推荐

  • PTA -1012 数字分类

    1012 数字分类 20 分 给定一系列正整数 请按要求对数字进行分类 并输出以下 5 个数字 A 1 能被 5 整除的数字中所有偶数的和 A 2 将被 5 除后余 1 的数字按给出顺序进行交错求和 即计算 n 1 n 2 n 3 n 4
  • zigzag走线原理及应用

    电路板上弯弯扭扭的走线有什么用 往期文章 一文读懂高速互联的阻抗及反射 上 一文读懂高速互联的阻抗及反射 中 前面几篇文章有部分读者反馈太深奥 不好懂 要求来一点轻松易懂的 这不 它来了 本期文章我们来分享近期工作中的一个小故事 一段奇怪的
  • 数据结构学习——循环链表的使用

    一 循环链表的介绍 循环链表是一种特殊类型的链表 其中链表中的最后一个节点指向链表中的第一个节点 形成循环的结构 与普通链表相比 循环链表可以在链表中的任何位置进行遍历 并且可以方便地实现循环操作 在循环链表中 每个节点通常包含一个数据元素
  • vue3定义全局方法

    下面用element puls中的ElMessage组件为例 首先我在我的utils js工具类函数方法中定义了一个方法 代码如下 import ElMessage from element plus import element plus
  • 记网易面试总结

    最近进行了一次网易的社招面试 目前结果未知 但是从网易面试中我还是有一些体会 总结如下 作为非计算机专业的程序员来说 如果要进大厂 数据结构与算法是一定要补的 适度刷下leetcode中的算法题 大厂都好这一口 不要不信邪 我就以身试法了一
  • PHP用正则验证用户名

    在php中 用正则表达式写一个用户名的验证 要求 第一个字符为英文 只能用字母 数字 汉字 下划线 总长度限制在4 9位的昵称
  • vs2017 社区版本离线下载安装包

    百度得来 记录备忘 下载vS 2017 https visualstudio microsoft com zh hans thank you downloading visual studio sku Community rel 15 下载
  • Directx11教程三十八之Pick(拾取技术)

    这节教程是关于Pick 拾取技术的 程序的结构如下 在看这节教程前先弄懂 1 大概了解D3D11的渲染流水线 2 D3D11教程三十七之FrustumCulling 视截体裁剪 上半节教程 弄不懂也没关系 两节教程之间有一些联系 但是由于我
  • 完全二叉树——二叉堆(BinaryHeap)

    前言 优先队列是允许至少下列两种操作的数据结构 insert 插入 以及deleteMin 删除最小者 其中deleteMin的工作是找出 返回 并删除优先队列中最小的元素 insert操作等价于enqueue 入队 而deleteMin则
  • Mysql存储引擎

    目录 Mysql有哪些存储引擎 Mysql存储引擎IMyISAM与InnoDB区别 MyISAM索引与InnoDB索引的区别 InnoDB引擎的4大特性 如何选择存储引擎 一张表 里面有ID自增主键 当insert了17条记录以后 删除了第
  • 解决IDEA无法导入Maven项目jar包的问题 - 已解决

    当我们创建Maven项目的时候 经常会出现导入jar包失败的问题 如下图所示 发现我们导入的依赖下面都有红线 解决方法有以下几种 1 有可能是因为我们将 pom的文件忽略了 解决方法 找到 file gt settings gt Build
  • java jbutton数组_java-JButton需要显示图像数组

    我有一组存储在数组中的图像 我需要像幻灯片一样显示它们 下一个和上一个有两个JButton 它们使用户可以查看图像 但是我无法使按钮起作用 有什么建议吗 谢谢 import java awt Graphics import java awt
  • 51行代码实现简单的PHP区块链

    本文原始地址 php区块链demo 今年区块链特别火 我也很火啊 我火什么呢 前几年 公众平台出现 还得花时间去学去看 后来小程序出现 又得花时间精力去学去看 现在比特币 以太坊等去中心化货币带起了区块链的发展 还得学 没办法 技术改变师姐
  • 感冒的一般过程

    http blog sina com cn s blog 7af11b49010136hl html 又感冒了 哎 挺严重 鼻涕流不停 特别畏寒 以前没发现感冒这么可怕 看到一篇关于感冒的文章 粘过来给大家分享一下 以防感冒 感冒 是一种自
  • Python轻松爬取Rosimm写真网站全部图片

    RosimmImage 爬取Rosimm写真网站图片 有图有真相 def main start url 爬虫入口 主要爬取操作 try r requests get url html headers HEADERS timeout 10 t
  • token由来

    https www cnblogs com bigben0123 p 8334824 html
  • compiler之automatic memory management以及Java GC

    基本方案就3种 1 mark and sweep 2 stop and copy 会用到copy graph算法 见leetcode 3 reference counting 前2种方案GC是一个是独立的过程 要先进行扫描 object g
  • Java Portlet 规范概述

    首先 解释几个基本的术语 1 Portal Portal 是一种 web 应用 通常具有个性化 单点登录 来自不同源的内容聚合 aggregation 并提供信息系统表现层等特点 所谓聚合 是指将不同来源的内容整合到一个 web 页面的操作
  • awk传入变量

    for chr in 1 22 do awk v nvar chr print 1 t nvar t 4 t 3 t 4 chr chr LD map gt chr chr LD1 map done
  • js-事件及事件委托

    1 事件 当用户浏览网页时 存在许许多多与网页交互的操作 例如按钮的点击 屏幕的滑动 鼠标的移动等等 通过这些交互完成某些操作 达到某种效果 我们可以将这些交互称之为事件 2 事件冒泡 事件冒泡是指事件在某个元素上触发后一直向上传播 父元素