事件流和事件委托

导读:

当我们点击一个元素触发该元素上绑定的点击事件时,同时也点击了该元素的父元素以及祖先元素等元素,如果该元素的父元素以及祖先元素等元素也绑定了点击事件,那么它们的执行顺序是怎样的呢?为了解决这个问题,所以有了事件流的概念。

1、事件流

当一个HTML元素产生一个事件时,该事件会在元素节点与根结点之间的路径传播,路径所经过的结点都会收到该事件,这个传播过程可称为DOM事件流。简单地说:事件流就是描述页面中接收事件的顺序。其包含三个阶段:

  • 捕获阶段:事件从 Document 节点自上而下向目标节点传播的阶段;
  • 目标阶段:真正的目标节点正在处理事件的阶段;
  • 冒泡阶段:事件从目标节点自下而上向 Document 节点传播的阶段。

在整个事件流的任何位置通过调用事件的 stopPropagation() 方法可以停止事件的传播过程。

DOM同时支持两种事件模型:捕获型事件(事件句柄在捕获阶段执行)和冒泡型事件(事件句柄在冒泡阶段执行)。现在主流的是冒泡事件。

冒泡事件

事件冒泡即在某一 DOM 元素被触发时,从该节点开始然后逐级向上触发事件,直至到达文档根。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
	<meta charset="utf-8"/>
	<title>事件流测试</title>
</head>
<body>
<div id="parent">
	<button id="child">Click me</button>
</div>
<script type="text/javascript">
	var child = document.getElementById(‘child‘);
	var parent = document.getElementById(‘parent‘);
	// 创建冒泡事件,将 addEventListener 的第三个参数设为 false
	child.addEventListener(‘click‘,function(){
    	alert(‘0 - I am child‘);
	},false);
	parent.addEventListener(‘click‘,function(){
    	alert(‘1 - I am parent‘);
	},false);
	document.body.addEventListener(‘click‘,function(){
    	alert(‘2 - I am body‘);
	},false);
	document.addEventListener(‘click‘,function(){
    	alert(‘3 - I am document‘);
	},false);
	window.addEventListener(‘click‘,function(){
    	alert(‘4 - I am window‘);
	},false);
</script>
</body>
</html>

当我们点击页面中的按钮后会依次弹出:

  • 0 - I am child
  • 1 - I am parent
  • 2 - I am body
  • 3 - I am document
  • 4 - I am window

另外有一些不支持冒泡的事件:

  • focus: 元素获得焦点时触发,不支持冒泡。
  • blur:元素失去焦点时触发,不支持冒泡。
  • mouseenter:鼠标移入元素触发,不支持冒泡。
  • mouseleave:鼠标移出元素时触发,不支持冒泡。
捕获事件

事件捕获的概念,与事件冒泡正好相反。事件从目标元素的所有祖先元素依次往下传递。创建捕获事件,只需要将 addEventListener() 的第三个参数设为 true 即可。再次点击页面中的按钮会依次弹出:

  • 4 - I am window
  • 3 - I am document
  • 2 - I am body
  • 1 - I am parent
  • 0 - I am child

2、事件委托

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

结合上述事件冒泡这一个机制,那么我们给最外面的元素添加点击事件,当点击里面元素的时候,都会冒泡到最外层的元素上,所以其祖先元素都会触发,这就是事件委托,委托它们先祖代为执行事件。

当然此时点击里面的元素至委托的先祖元素间的所有元素也会执行事件,如果想让事件委托的效果跟直接给节点的事件效果一样,我们需要使用 Event 对象提供的一个属性叫 target,可以返回触发事件的目标节点,我们称之为事件源,也就是说,target 可以表示为当前的事件操作的 Dom,但是不是真正操作 Dom,当然,这个是有兼容性的,标准浏览器用 ev.target,IE浏览器用 event.srcElement,此时只是获取了当前节点的位置,然后我们用 nodeName 来获取具体是什么标签名。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
	<meta charset="utf-8"/>
	<title>事件委托测试</title>
</head>
<body>
<div id="parent">
	<button id="child0">Click me 0</button>
	<button id="child1">Click me 1</button>
	<button>Click me 2</button>
</div>
<script type="text/javascript">
	var parent = document.getElementById(‘parent‘);

	parent.addEventListener(‘click‘,function(ev){
		var ev = event || window.event;
	    var target = ev.target || ev.srcElement;
	    if(target.nodeName.toLowerCase() == ‘button‘){
	        alert(‘n - I am child‘);
	    }
	},false);
</script>
</body>
</html>

上面的例子中我们把事件绑定在了按钮的父元素上,但是只有在点击按钮时才会执行事件。不过显然上面操作的是同样的效果,要是每个子元素被点击后执行效果都不一样,那么用事件委托还有用吗?答案是肯定的,我们来看下面的例子:

parent.addEventListener(‘click‘,function(ev){
	var ev = event || window.event;
    var target = ev.target || ev.srcElement;
    if(target.nodeName.toLowerCase() == ‘button‘){
        switch(target.id) {
        	case ‘child0‘:alert(‘1 - I am child0‘);
        	break;
        	case ‘child1‘:alert(‘2 - I am child1‘);
        	break;
        	default:alert(‘3 - I am child2‘);
        }
	}
},false);

目前讲的都是在 Document 加载完成后,在现有 Dom 节点下的操作,那么如果是新增的节点,新增的节点会有事件吗?

用事件委托的方式,新添加的后代元素依然是带有事件效果的。我们可以发现,当用事件委托的时候,根本就不需要去遍历元素的子节点,只需要给父级元素添加事件就好了,其他的都是在 Js 里面的执行,所以事件委托的方式不仅使得新添加的后代元素带有事件效果,而且这样也可以大大的减少了 Dom 操作。

现在又有一个新的问题,上面的例子在分配不同的函数(事件触发后执行的函数)时,我们需要知道对应子元素的一个独有的属性,但是新增加的元素的属性我们无法预知,所以没办法像上面一样添加指定的函数,这里我们有一个折中的办法,即使不及之前的:

parent.addEventListener(‘click‘,function(ev){
	var ev = event || window.event;
    var target = ev.target || ev.srcElement;
    if(target.nodeName.toLowerCase() == ‘button‘){
        target.style.backgroundColor="#00FF00";
	}
},false);

写在最后

事件流和事件委托的介绍在这里就告一段落了,写得可能有些乱,仅供参考吧,也算作是自己的学习笔记,如果文中有什么错误,欢迎大家指正,愿与大家在交流之中共同进步,愈激烈,愈深刻。感谢。

原文地址:https://www.cnblogs.com/anani/p/8657204.html

时间: 2024-08-25 15:30:36

事件流和事件委托的相关文章

HTML 事件(三) 事件流与事件委托

本篇主要介绍HTML DOM中的事件流和事件委托. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三) 事件流与事件委托 4. HTML 事件(四) 模拟事件操作[未发布] 目录 1. 事件流 1.1 何为事件流 1.2 事件流的三个阶段 1.3 addEventListener()注册事件流的阶段 1.4 阻止事件流的传播 2. 事件委托 2.1 何为事件委托 2.2 ul.li场景示例 2.3 JQuery的事件委托

事件流及事件冒泡机制

事件流 "DOM2级事件"规定的事件流包括三个阶段: 事件捕获阶段(为截获事件提供了机会) 处于目标阶段(实际的目标接收到事件) 事件冒泡阶段(可以在这个阶段对事件做出响应) IE9.Opera.Firefox.Chrome 和 Safari 都支持 DOM 事件流:IE8 及更早版本不支持 DOM 事件流. 事件冒泡机制 a.在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回

事件流,事件捕获与事件冒泡-基础知识总结------彭记(018)

事件流: -事件流包括三个阶段-事件捕获阶段.处于目标阶段和事件冒泡阶段. -首先发生的是事件捕获,为截获事件提供了机会,然后是实际的目标接收到事件,最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应. 事件冒泡: -事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点(文档). <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8">

JavaScript 中的事件流和事件处理程序(读书笔记思维导图)

JavaScript 程序采用了异步事件驱动编程模型.在这种程序设计风格下,当文档.浏览器.元素或与之相关的对象发生某些有趣的事情时,Web 浏览器就会产生事件(event). JavaScript 与 HTML 之间的交互是通过事件实现的.事件就是文档或浏览器窗口中发生的一些特定的交互瞬间,或者说事件就是 Web 浏览器通知应用程序发生了什么事情.可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码. 以下是<JavaScript高级程序设计>中事件流和事件处理程序的总结:

js事件流、事件处理程序/事件侦听器

1.事件流 事件冒泡 IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档). 事件捕获 事件捕获的思想是不太具体的节点应该更早的接收到事件,而最具体的节点应该在最后接收到节点.事件捕获的用意在于事件到达预定目标之前捕获它. DOM事件流 “DOM2级事件流”规定的事件流包括三个阶段:事件捕获阶段.处于目标阶段和冒泡阶段.首先发生的是事件捕获,为截获事件提供了机会.然后是实际的目标接收到

js学习笔记:事件——事件流、事件处理程序、事件对象

Javascript与HTML之间的交互是通过事件实现的. 事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间. 可以使用侦听器来预定事件,以便事件发生时执行相应代码. 事件流 事件流描述的是从页面中接受事件的顺序. 事件冒泡 IE的事件流叫做事件冒泡,即事件开始是由最具体的元素接收,然后逐级向上传播到较为不具体的节点(文档). 如果点击了页面中的一个div元素,那么这个click事件可能会按照如下顺序传播: < div> < body> < html> docume

关于事件流,事件冒泡和事件捕获

1.事件流 假设有这样一个场景: 有一个导航条:div > ul > li > a,每个元素块宽高一样,就像是一组同心圆.如果我们点击a元素,那么浏览器会认为单击事件不仅仅发生在a上.换句话说,在我们单击a元素的同事,我们也单击了容器中的其他元素. 事件流描述的是从页面中接收事件的顺序.但有意思的是,IE 和 Netscape 却分别提出了不一样的事件流概念.IE 的事件流是事件冒泡,而Netscape的事件流是事件捕获流. 那么问题来了,什么是事件冒泡?什么是事件捕获? 2.事件冒泡

事件流之事件冒泡与事件捕获&lt;JavaScript高级程序设计&gt;学习笔记

1.事件流 浏览器开发团队遇到一个很有意思问题:页面的那一部分会拥有特定的事件? 对于理解这个问题您可以想象画在一张纸上的一组同心圆,如果你把手指放在圆心上,那么你的手指指向的其实不是一个圆,而是纸上所有的圆.放到实际页面中就是,你点击一个按钮,而是纸上所有的圆. <栗子:现实生活中的声波.水波> 事件流:从页面中接收事件的顺序,通俗说:用户操作DOM的一系列行为交互. 2.事件冒泡 事件冒泡:IE的事件流叫事件冒泡,即事件开始由最具体的元素(文档中嵌套层次最深的那个元素)接收,然后逐级向上传

事件流:事件冒泡和事件捕获

事件流:事件冒泡和事件捕获 1. 两者概念 事件捕获指的是从document到触发事件的那个节点,即自上而下的去触发事件., element.addEventListener(event,function(),false); 事件冒泡是自下而上的去触发事件.绑定事件方法的第三个参数,就是控制事件触发顺序是否为事件捕获. element.addEventListener(event,function(),true); 从上面可知,第三个参数为true或者false; true,事件捕获: fals