导航:首页 > 编程语言 > js中dom中事件代理

js中dom中事件代理

发布时间:2023-01-31 19:33:28

『壹』 事件代理和事件委托

事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件,事件委托又叫事件代理。

举一个通俗的例子:有三个同事预计会在周一收到快递。为签收快递,有两种办法:一是三个人在公司门口等快递;二是委托给前台代为签收。现实当中,我们大都采用委托的方案
前台收到快递后,会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工,前台也会在收到寄给新员工的快递后核实并代为签收。

这里其实还有2层意思的:

一般来说,dom需要有事件处理程序,我们都会直接给它设事件处理程序就好了,那如果是很多的dom需要添加事件处理呢?比如我们有100个li,每个li都有相同的click点击事件,可能我们会用for循环的方法,来遍历所有的li,然后给它们添加事件,那这么做会存在什么影响呢?

javaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;如果要用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能;

每个函数都是一个对象,是对象就会占用内存,对象越多,内存占用率就越大,自然性能就越差了,比如上面的100个li,就要占用100个内存空间,如果是1000个,10000个呢,如果用事件委托,那么我们就可以只对它的父级(如果只有一个父级)这一个对象进行操作,这样我们就需要一个内存空间就够了,性能就会更好。

事件委托是利用事件的冒泡原理来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件,举个例子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。

介绍了浏览器的事件冒泡机制,这里再详细介绍一下浏览器处理DOM事件的过程。对于事件的捕获和处理,不同的浏览器厂商有不同的处理机制,这里我们主要介绍W3C对DOM2.0定义的标准事件。DOM2.0模型将事件处理流程分为三个阶段:一、事件捕获阶段,二、事件目标阶段,三、事件起泡阶段。如图:

事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的。

事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。

事件起泡:从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来阻止事件的冒泡传播。

1、在介绍事件委托的方法之前,我们先来看一段一般方法的例子:子节点实现相同的功能,实现功能是点击li,弹出123:

我们看到有多少次的dom操作,首先要找到ul,然后遍历li,然后点击li的时候,又要找一次目标的li的位置,才能执行最后的操作,每次点击都要找一次li;那么我们用事件委托的方式做又会怎么样呢?

这里用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的,那么问题就来了,如果我想让事件代理的效果跟直接给节点的事件效果一样怎么办,比如说只有点击li才会触发:

Event对象提供了一个属性叫target,可以返回事件的目标节点,我们称为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的,我们需要转成小写再做比较

这样改下就只有点击li会触发事件了,且每次只执行一次dom操作,如果li数量很多的话,将大大减少dom的操作,优化的性能可想而知!

2、上面的例子是说li操作的是同样的效果,要是每个li被点击的效果都不一样,那么用事件委托还有用吗?

用事件代理如何优化??

现在是移入li,li变红,移出li,li变白,这么一个效果,然后点击按钮,可以向ul中添加一个li子节点

这是一般的做法,但是你会发现,新增的li是没有事件的,说明添加子节点的时候,事件没有一起添加进去,这不是我们想要的结果,那怎么做呢?一般的解决方案会是这样,将for循环用一个函数包起来,命名为mHover,如下:

虽然功能实现了,看着还挺好,但实际上无疑是又增加了一个dom操作,在优化性能方面是不可取的,那么有事件委托的方式,能做到优化吗?

看上面是用事件委托的方式,新添加的子元素是带有事件效果的,我们可以发现,当用事件委托的时候,根本就不需要去遍历元素的子节点,只需要给父级元素添加事件就好了,其他的都是在js里面的执行,这样可以大大的减少dom操作,这才是事件委托的精髓所在。

那什么样的事件可以用事件委托,什么样的事件不可以用呢?

适合用事件委托的事件:

不适合的就有很多了,举个例子,mousemove,每次都要计算它的位置,非常不好把控,再比如说focus,blur,load,unload之类的,本身就没用冒泡的特性,自然就不能用事件委托了。

『贰』 DOM事件机制

前言

一、DOM事件级别

DOM级别一共可以分为四个级别:DOM0级、DOM1级、DOM2级和DOM3级。而DOM事件分为3个级别:DOM 0级事件处理,DOM 2级事件处理和DOM 3级事件处理。由于DOM 1级中没有事件的相关内容,所以没有DOM 1级事件。

1.DOM 0级事件

el.onclick=function(){}

当希望为同一个元素/标签绑定多个同类型事件的时候(如给上面的这个btn元素绑定3个点击事件),是不被允许的。DOM0事件绑定,给元素的事件行为绑定方法,这些方法都是在当前元素事件行为的冒泡阶段(或者目标阶段)执行的。

2.DOM 2级事件

el.addEventListener(event-name, callback, useCapture)

event-name: 事件名称,可以是标准的DOM事件

callback: 回调函数,当事件触发时,函数会被注入一个参数为当前的事件对象 event

useCapture: 默认是false,代表事件句柄在冒泡阶段执行

IE9以下的IE浏览器不支持 addEventListener()和removeEventListener(),使用 attachEvent()与detachEvent() 代替,因为IE9以下是不支持事件捕获的,所以也没有第三个参数,第一个事件名称前要加on。

3.DOM 3级事件

在DOM 2级事件的基础上添加了更多的事件类型。

UI事件,当用户与页面上的元素交互时触发,如:load、scroll

焦点事件,当元素获得或失去焦点时触发,如:blur、focus

鼠标事件,当用户通过鼠标在页面执行操作时触发如:dblclick、mouseup

滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel

文本事件,当在文档中输入文本时触发,如:textInput

键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress

合成事件,当为IME(输入法编辑器)输入字符时触发,如:compositionstart

变动事件,当底层DOM结构发生变化时触发,如:DOMsubtreeModified

同时DOM3级事件也允许使用者自定义一些事件。

二、DOM事件模型和事件流

DOM事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段。

(1)捕获阶段:事件从window对象自上而下向目标节点传播的阶段;

(2)目标阶段:真正的目标节点正在处理事件的阶段;

(3)冒泡阶段:事件从目标节点自下而上向window对象传播的阶段。

DOM事件捕获的具体流程

捕获是从上到下,事件先从window对象,然后再到document(对象),然后是html标签(通过document.documentElement获取html标签),然后是body标签(通过document.body获取body标签),然后按照普通的html结构一层一层往下传,最后到达目标元素。

而事件冒泡的流程刚好是事件捕获的逆过程。

接下来我们看个事件冒泡的例子:

正如我们上面提到的onclick给元素的事件行为绑定方法都是在当前元素事件行为的冒泡阶段(或者目标阶段)执行的。

三、事件代理(事件委托)

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。

1.优点

减少内存消耗,提高性能

假设有一个列表,列表之中有大量的列表项,我们需要在点击每个列表项的时候响应一个事件

如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的,效率上需要消耗很多性能。借助事件代理,我们只需要给父容器ul绑定方法即可,这样不管点击的是哪一个后代元素,都会根据冒泡传播的传递机制,把容器的click行为触发,然后把对应的方法执行,根据事件源,我们可以知道点击的是谁,从而完成不同的事。

动态绑定事件

在很多时候,我们需要通过用户操作动态的增删列表项元素,如果一开始给每个子元素绑定事件,那么在列表发生变化时,就需要重新给新增的元素绑定事件,给即将删去的元素解绑事件,如果用事件代理就会省去很多这样麻烦。

2.如何实现

接下来我们来实现上例中父层元素 #list 下的 li 元素的事件委托到它的父层元素上:

四、Event对象常见的应用

event. preventDefault()

如果调用这个方法,默认事件行为将不再触发。什么是默认事件呢?例如表单一点击提交按钮(submit)跳转页面、a标签默认页面跳转或是锚点定位等。

很多时候我们使用a标签仅仅是想当做一个普通的按钮,点击实现一个功能,不想页面跳转,也不想锚点定位。

也可以通过JS方法来阻止,给其click事件绑定方法,当我们点击A标签的时候,先触发click事件,其次才会执行自己的默认行为

接下来我们看个例子:输入框最多只能输入六个字符,如何实现?

event.stopPropagation() & event.stopImmediatePropagation()

event.stopPropagation() 方法阻止事件冒泡到父元素,阻止任何父事件处理程序被执行。上面提到事件冒泡阶段是指事件从目标节点自下而上向window对象传播的阶段。

我们在例4的inner元素click事件上,添加event.stopPropagation()这句话后,就阻止了父事件的执行,最后只打印了'inner'。

stopImmediatePropagation 既能阻止事件向父元素冒泡,也能阻止元素同事件类型的其它监听器被触发。而 stopPropagation 只能实现前者的效果。我们来看个例子:

如上所示,使用 stopImmediatePropagation后,点击按钮时,不仅body绑定事件不会触发,与此同时按钮的另一个点击事件也不触发。

event.target & event.currentTarget

老实说这两者的区别,并不好用文字描述,我们先来看个例子:

当我们点击最里层的元素d的时候,会依次输出:

从输出中我们可以看到,event.target指向引起触发事件的元素,而event.currentTarget则是事件绑定的元素,只有被点击的那个目标元素的event.target才会等于event.currentTarget。也就是说,event.currentTarget始终是监听事件者,而event.target是事件的真正发出者。

五、参考文章

DOM级别与DOM事件

DOM事件机制解惑

事件模型

JavaScript 事件委托详解

JavaScript 事件的学与记:stopPropagation 和 stopImmediatePropagation

event.target和event.currentTarget的区别

原文: https://github.com/ljianshu/Blog/issues/44

最后:“相信有很多想学前端的小伙伴,今年年初我花了一个月整理了一份最适合2018年学习的web前端干货,从最基础的HTML+CSS+JS到移动端HTML5等都有整理,送给每一位前端小伙伴,53763,1707这里是小白聚集地,欢迎初学和进阶中的小伙伴。”

祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。

『叁』 原生javascript 怎么事件代理 addeventlistener

事件代理就好比,有一个小队,共十人,给其中一人绑上一个大喇叭,你要找张三的时候,直接告诉绑上大喇叭的人,大喇叭一喊:咱们队伍中叫张三的给我出来。这个过程就叫做事件代理。
http://www.cnblogs.com/ARMdong/articles/javascript_delegate.html

『肆』 前端性能优化总结(一)-js、css优化

移动互联网时代,用户对于网页的打开速度要求越来越高。首屏作为直面用户的第一屏,其重要性不言而喻。优化用户体验更是我们前端开发非常需要 focus 的东西之一。

从用户的角度而言,当打开一个网页,往往关心的是从输入完网页地址后到最后展现完整页面这个过程需要的时间,这个时间越短,用户体验越好。所以作为网页的开发者,就从输入url到页面渲染呈现这个过程中去提升网页的性能。

所以输入URL后发生了什么呢?在浏览器中输入url会经历域名解析、建立TCP连接、发送http请求、资源解析等步骤。

http缓存优化是网页性能优化的重要一环,这一部分我会在后续笔记中做一个详细总结,所以本文暂不多做详细整理。本文主要从网页渲染过程、网页交互以及Vue应用优化三个角度对性能优化做一个小结。

首先谈谈拿到服务端资源后浏览器渲染的流程:

关键渲染路径是浏览器将 HTML、CSS、JavaScript 转换为在屏幕上呈现的像素内容所经历的一系列步骤。也就是我们刚刚提到的的的浏览器渲染流程。

为尽快完成首次渲染,我们需要最大限度减小以下三种可变因素:

首先,DOM 和 CSSOM 通常是并行构建的,所以 CSS 加载不会阻塞 DOM 的解析。

然而,由于 Render Tree 是依赖于 DOM Tree 和 CSSOM Tree 的,
所以他必须等待到 CSSOM Tree 构建完成,也就是 CSS 资源加载完成(或者 CSS 资源加载失败)后,才能开始渲染。因此,CSS 加载会阻塞 Dom 的渲染。

由此可见,对于 CSSOM 缩小、压缩以及缓存同样重要,我们可以从这方面考虑去优化。

当浏览器遇到 script 标记时,会阻止解析器继续操作,直到 CSSOM 构建完毕,JavaScript 才会运行并继续完成 DOM 构建过程。

当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility 等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。

回流(Reflow)
当 Render Tree 中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。

有时即使仅仅回流一个单一的元素,它的父元素以及任何跟随它的元素也会产生回流。现代浏览器会对频繁的回流或重绘操作进行优化:浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。
当你访问以下属性或方法时,浏览器会立刻清空队列:

因为队列中可能会有影响到这些属性或方法返回值的操作,即使你希望获取的信息与队列中操作引发的改变无关,浏览器也会强行清空队列,确保你拿到的值是最精确的。

避免频繁操作样式,最好一次性重写 style 属性,或者将样式列表定义为 class 并一次性更改 class 属性。

避免频繁操作 DOM,创建一个 documentFragment,在它上面应用所有 DOM 操作,最后再把它添加到文档中。
也可以先为元素设置 display: none,操作结束后再把它显示出来。因为在 display 属性为 none 的元素上进行的 DOM 操作不会引发回流和重绘。
避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。

图片懒加载在一些图片密集型的网站中运用比较多,通过图片懒加载可以让一些不可视的图片不去加载,避免一次性加载过多的图片导致请求阻塞(浏览器一般对同一域名下的并发请求的连接数有限制),这样就可以提高网站的加载速度,提高用户体验。

将页面中的img标签src指向一张小图片或者src为空,然后定义data-src(这个属性可以自定义命名,我才用data-src)属性指向真实的图片。src指向一张默认的图片,否则当src为空时也会向服务器发送一次请求。可以指向loading的地址。注意,图片要指定宽高。

当载入页面时,先把可视区域内的img标签的data-src属性值负给src,然后监听滚动事件,把用户即将看到的图片加载。这样便实现了懒加载。

事件委托其实就是利用JS事件冒泡机制把原本需要绑定在子元素的响应事件(click、keydown……)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。
优点:

例如有一个列表需要绑定点击事件,每一个列表项的点击都需要返回不同的结果。
传统写法:

传统方法会利用for循环遍历列表为每一个列表元素绑定点击事件,当列表中元素数量非常庞大时,需要绑定大量的点击事件,这种方式就会产生性能问题。这种情况下利用事件委托就能很好的解决这个问题。

改用事件委托:

输入搜索时,可以用防抖debounce等优化方式,减少http请求;
这里以滚动条事件举例:防抖函数 onscroll 结束时触发一次,延迟执行

节流函数:只允许一个函数在N秒内执行一次。滚动条调用接口时,可以用节流throttle等优化方式,减少http请求;
下面还是一个简单的滚动条事件节流函数:节流函数 onscroll 时,每隔一段时间触发一次,像水滴一样

参考链接: https://zhuanlan.hu.com/p/113864878?from_voters_page=true

阅读全文

与js中dom中事件代理相关的资料

热点内容
微信不访问视频文件夹吗 浏览:259
文件夹加密大师注册码 浏览:1
onedrive怎么上传文件 浏览:488
android多线程写文件栈溢出 浏览:242
台电酷闪量产工具 浏览:837
如何破坏文件 浏览:15
从什么网站上查找国家标准 浏览:254
iphone5s最省电的浏览器 浏览:225
用数据线如何接摄像头 浏览:110
qq手机电脑互传文件 浏览:613
linux内核升级方法 浏览:986
iphone5没有热点 浏览:189
哪里有在线幼儿c语言编程 浏览:959
iframe跨域调用js对象 浏览:178
苹果手机能分文件夹吗 浏览:679
fdb文件怎么删除里面内容 浏览:638
龙江网络配置什么路由器 浏览:169
如何使用指标导入数据 浏览:866
平时用什么app看nba 浏览:503
win10想以管理员身份运行bat文件 浏览:85

友情链接