事件的传播:捕获/目标/冒泡

最近学习JavaScript事件,对于事件很多东西有点迷糊,综合了各位大佬的文档,来讲一下JS里面事件的相关操作。如果有错误的地方,欢迎大家指正。

事件

HTML 事件可以是浏览器行为,也可以是用户行为。以下是 HTML 事件的实例:
HTML 页面完成加载
HTML input 字段改变时
HTML 按钮被点击
通常,当事件发生时,你可以做些事情。在事件触发时 JavaScript 可以执行一些代码。HTML 元素中可以添加事件属性,使用 JavaScript 代码来添加 HTML 元素。

绑定事件

  1. 元素中直接绑定;ep:<button onclick = ""></button>
  2. DOM事件处理;
    ①elementObj.event = function(){…};
    ②addEventListener(“str”,fun(),boo);removeEventListener(“str”,fun(),boo)其中:
    1)“str”:事件名称;
    2)fun():事件处理的函数
    3)boo:捕获(true)或者不捕获(false),默认为false;当boo为true时,元素不发生冒泡行为,事件触发顺寻为捕获的顺序,即从父到子。当boo为false时,元素发生冒泡行为,事件触发为冒泡的顺序。多级层叠时,先执行捕获,再执行冒泡。接下来将以一个简单的例子解释捕获和冒泡。

事件传播的过程:

• 捕获阶段:事件对象从目标的祖先节点Window开始传播直至目标。
• 目标阶段:事件对象传递到事件目标。如果事件的type属性表明后面不会进行冒泡操作,那么事件到此就结束了。
• 冒泡阶段:事件对象以一个相反的方向进行传递,从目标开始,到Window对象结束。

了解了基本概念,那么接下来我们来看看有意思的事情,这里有段代码:

<div id="father">
			father
			<div id="son">
			son
				<div id="superson">
				super son
					<div id="susuperson">susuperson</div>
				</div>
			</div>
			<h3 id="sec_son">sec_son</h3>
</div>

显而易见的,这是一个家族,接下来用addEventListener()为他们添加点击事件:

var father = document.getElementById('father');
			var son = document.getElementById('son');
			var sec_son = document.getElementById('sec_son');
			var superson = document.getElementById('superson');
			var susuperson = document.getElementById('susuperson');
			father.addEventListener('click', function() {
				console.log("father");
			});
			son.addEventListener('click', function() {
				console.log("son");
			});
			superson.addEventListener('click', function() {
				console.log("superson");
			});
			susuperson.addEventListener('click', function() {
				console.log("susuperson");
			});
			sec_son.addEventListener('click', function() {
				console.log("sec_son");
			}):

当我们点击susuperson的时候,控制台会给我们输出这样的结果:
在这里插入图片描述
那么我们给father的事件添加捕获,即boo设置为true。再次点击susuperson,会发生如下结果:在这里插入图片描述
为了方便理解,再将superson的boo设置为true。再次点击susuperson,结果如下:
在这里插入图片描述
如上三个运行结果,可以得出以下结论:当给事件添加捕获之后,该事件会先执行。可以这样理解:事件的三个阶段可以看作是生产可乐的流水线,捕获阶段就是空瓶子过质检,设置了true,就相当于这个瓶子合格了,可以拿去装可乐了。目标阶段就是装好可乐的瓶子拿去装箱,质检没合格的瓶子拿去重铸。冒泡阶段就是将重铸过的瓶子拿去装可乐。
当然了,我们设置的点击事件并没有发生任何改变,只是举个栗子来形容这个输出结果的原因。

如何阻止事件冒泡

阻止事件冒泡拿上面的栗子来说,就是点击susuperson的时候,不让他的父元素发生事件(前提是父元素没有参与捕获)。下面有三种方式:

obj.event(function(eve){
	eve.stopPropagation(); //1.停止事件冒泡,但是不会阻止默认行为
    return false; // 2.阻止事件冒泡,也阻止了默认行为
    eve.preventDefault(); // 3.阻止默认行为,不阻止事件冒泡
});

事件委托

事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。这个栗子最好解释什么是事件委托:
有三个同事预计会在周一收到快递。为签收快递,有两种办法:一是三个人在公司门口等快递;二是委托给前台MM代为签收。现实当中,我们大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递)。前台MM收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台MM也会在收到寄给新员工的快递后核实并代为签收。

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

第一,现在委托前台的同事是可以代为签收的,即程序中的现有的dom节点是有事件的;

第二,新员工也是可以被前台MM代为签收的,即程序中新添加的dom节点也是有事件的。
看下面的代码:

<ul id="ul1">
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li></ul>
    <script>
	window.onload = function(){
  	var oUl = document.getElementById("ul1");
		var aLi = oUl.getElementsByTagName('li');
  		for(var i=0;i<aLi.length;i++){
        aLi[i].onclick = function(){
            alert(123);
        }
	}
</script>

当我们需要给每一个li元素添加点击事件时,第一个想到的就是循环,众所周知,每有一次DOM操作,就会消耗内存,如果我们有1000个li,用这样的方式添加事件,页面还没有加载完呢,用户就已经投诉了。所以可以利用冒泡来完成这件事。
Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的,我们需要转成小写再做比较

	window.onload = function(){
  	var oUl = document.getElementById("ul1");
		oUl.onclick = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    if(target.nodeName.toLowerCase() == 'li'){
         alert(123);
         alert(target.innerHTML);
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值