浏览器事件机制

本文详细探讨了浏览器事件的触发、事件流的捕获冒泡过程,介绍了DOM0级和IE/DOM2级事件模型,重点讲解了事件冒泡、阻止冒泡、事件委托及其局限性,以及同步和异步的区别。还涵盖了事件循环、宏任务和微任务,并用实例演示了event.target和event.currentTarget的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

浏览器事件机制

什么是事件

事件是用户操作页面时发生的交互动作,比如click/move等,事件除了用户触发的动作外,还可以是文档加载、窗口滚动和大小调整。事件被封装为一个event对象,包含了事件的属性和方法。

事件流

事件流就是事件的流向,先捕获,再到事件源,最后再冒泡,在DOM2级事件模型中,事件流分为三个阶段:事件捕获、事件处理、事件冒泡

事件模型

  • DOM0级事件模型:可以在网页中直接定义监听函数,也可以通过js来指定监听函数,直接在DOM对象上注册事件。
  • IE事件模型:该事件模型共有两个过程:事件处理阶段和事件冒泡阶段。事件处理阶段会首先执行目标元素绑定的监听事件。然后是事件冒泡阶段,冒泡指的是事件从目标元素冒泡到document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。
  • DOM2级事件模型:一共三个过程:事件捕获阶段:事件从document一直向下传播到目标元素,依次检查经过的结点是否绑定了事件监听函数,如果绑定则执行。后两个阶段与IE事件模型相同。

事件冒泡

事件冒泡就是元素自身的事件被触发后,如果父元素有相同的事件,如onclick 事件,那么元素本身的触发状态就会传递,也就是冒泡到父元素,父元素的相同事件也会一级一级根据嵌套关系向外触发,直到 document/window,冒泡过程结束

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L1LWvCK4-1652435220241)(https://user-images.githubusercontent.com/70066311/168251514-1e11c64f-668e-4909-8ec1-ea866fb5a71c.png)]

如何阻止事件冒泡

  • 普通浏览器:event.stopPropagation()
  • IE浏览器:event.cancelBubble = true

事件委托

事件委托就是把子元素响应事件的函数委托到父元素,由父元素统一处理多个子元素的事件。事件委托的优点是内存消耗少,效率较高、可以动态绑定事件

事件委托的局限性:对于一些事件没有事件冒泡机制,无法实现事件委托。

事件委托的使用场景

场景一:给页面的所有的a标签添加click事件,代码如下:

document.addEventListener("click", function(e) {
	if (e.target.nodeName == "A")
		console.log("a");
}, false);

但是这些a标签可能包含一些像span、img等元素,如果点击到了这些a标签中的元素,就不会触发click事件,因为事件绑定上在a标签元素上,而触发这些内部的元素时,e.target指向的是触发click事件的元素(span、img等其他元素)。

这种情况下就可以使用事件委托来处理,将事件绑定在a标签的内部元素上,当点击它的时候,就会逐级向上查找,直到找到a标签为止,代码如下:

document.addEventListener("click", function(e) {
	var node = e.target;
	while (node.parentNode.nodeName != "BODY") {
		if (node.nodeName == "A") {
			console.log("a");
			break;
		}
		node = node.parentNode;
	}
}, false);

场景二:动态绑定事件。在很多情况下我们会进行动态的删除或添加元素,需要给这些元素解绑或绑定事件。如果有了事件委托,那么事件绑定到父层,那么子元素的添加或删除就不会涉及到动态添加或删除事件,就可以减少很多工作。

局限性:事件委托也有局限性,例如:focus、blur之类的事件没有事件冒泡机制;mousemove、mouseout 这样的事件需要进行定位,对性能的消耗比较高,不适合事件委托

缺点:事件委托会影响页面性能:

  • 对于最底层元素,如果点击了最底层元素,那么到绑定元素之间的DOM层数如果太多就会影响性能。
  • 对于元素,绑定事件委托的次数太多也会影响性能。

event.target 和 event.currentTarget 的区别

我们为一个元素绑定一个点击事件的时候,可以指定是要在捕获阶段绑定或者换在冒泡阶段绑定。 当addEventListener的第三个参数为true的时候,代表是在捕获阶段绑定,当第三个参数为false或者为空的时候,代表在冒泡阶段绑定

event.target指向引起触发事件的元素,而event.currentTarget则是事件绑定的元素,只有被点击的那个目标元素的event.target才会等于event.currentTarget

结合下面的例子,就可以很好来理解event.target和event.currentTarget:

<div id="a">
    <div id="b">
      <div id="c">
        <div id="d"></div>
      </div>
    </div>
</div>

<script>
    document.getElementById('a').addEventListener('click', function(e) {
      console.log('target:' + e.target.id + '&currentTarget:' + e.currentTarget.id);
    });    
    document.getElementById('b').addEventListener('click', function(e) {
      console.log('target:' + e.target.id + '&currentTarget:' + e.currentTarget.id);
    });    
    document.getElementById('c').addEventListener('click', function(e) {
      console.log('target:' + e.target.id + '&currentTarget:' + e.currentTarget.id);
    });    
    document.getElementById('d').addEventListener('click', function(e) {
      console.log('target:' + e.target.id + '&currentTarget:' + e.currentTarget.id);
    });
</script>

同步和异步的区别

  • 同步指的是当一个进程在执行某个请求时,如果这个请求需要等待一段时间才能返回,那么这个进程会一直等待下去,直到消息返回为止再继续向下执行。
  • 异步指的是当一个进程在执行某个请求时,如果这个请求需要等待一段时间才能返回,这个时候进程会继续往下执行,不会阻塞等待消息的返回,当消息返回时系统再通知进程进行处理。

事件循环

JS是单线程运行的,在执行代码时,JS通过将不同函数的执行上下文压入栈中保证代码的有序执行。当执行到异步任务时,JS并不会等待异步任务执行完,而是将这个事件挂起,继续执行后面的任务,当异步任务执行完后,将它的回调函数加入到任务队列中等待执行。任务队列分为宏任务队列和微任务队列,当当前的执行栈执行结束后,JS引擎会判断微任务队列中是否有任务,如果有则执行任务,然后再执行宏任务队列中的任务。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U1k8hpMf-1652435220242)(https://user-images.githubusercontent.com/70066311/164969442-d06118b2-b17b-439f-b4fb-0990126c58f7.png)]

EventLoop的执行顺序如下:

  • 首先执行同步代码,这属于宏任务
  • 当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行
  • 执行所有微任务
  • 当执行完所有微任务后,如有必要会渲染页面
  • 然后开始下一轮 Event Loop,执行宏任务中的异步代码

宏任务和微任务有哪些

  • 微任务:promise、
  • 宏任务:setTimeout、setInterval、I/O 操作、UI 渲染

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5DVUNl3T-1652435220242)(https://user-images.githubusercontent.com/70066311/168248924-b90e2dd9-f8d4-41ef-81a8-71bc10b4ada1.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值