Js中的事件委托

来源:互联网 发布:下载美化照片软件 编辑:程序博客网 时间:2024/06/09 16:03

DOM 2 中,js加入了事件委托的支持;
当我们从后端拿数据的时候,往往要根据这些数据生成相应的元素,或界面,之后,可能要进行进一步的业务操作,这其中,就可能会用到事件。
在Dom1中,事件处理使用类似 obj.onclick这样的属性绑定函数来实现,这固然简单方便,但是,当我们需要自动添加的事件有成百上千个以后,页面将会有上千个事件,这是很可怕的一件事,于是,在DOM2标准中,就提供了事件委托的支持。
什么是事件委托,字面理解,就是将事件委托出去,而不是开发者手动添加事件,如果说,整个页面只有一个事件,就能响应所有需求,岂不美哉。事件委托提供了这种功能。那么,事件委托,要委托给谁呢?
一般情况下,委托给事件密集元素的父元素即可(别的元素也行)。

<!-- 正式内容区 -->    <div class="row">        <div class="cont-wrap col-xs-12 col-md-12" id="cont-wrap">        <!-- 卡片列表 js生成 -->        </div>    </div>

在js中,我们在cont-wrap里面生成需要的原素并注册事件。

contWrap.addEventListener(“click”, doClick);
addEventtListener就是Dom2级的事件注册函数(事件监听),也就是利用它使用事件委托技术
addEventListener接受三个参数,即:事件类型(click,load,keydown之类的,注意,这里前面没有“on”),事件处理函数(即所谓的事件句柄,真正去处理事件的函数),第三个是一个布尔值,一般可以不传递,实际上,js中的函数根本不考虑你的参数是否真正传递,也不关心你是否有参数,因为js的函数实际上是一个对象,他的参数都存放在argument数组中,这个参数我们后面再说。
我们可以看到,上面那句话并没有吧click事件和事件句柄注册到具体的元素,而是注册到了他们的共有的父元素,contWrap上,那么真正需要事件处理的元素如何获取事件呢?这就谈到了第三个参数,事件的流向,即事件捕获和事件冒泡。

先问一个问题,当一个鼠标点击了页面,他实际上是点击了什么
是整篇文档,还是具体的某有一个button等元素?

实际上,都是!

当一个页面无论什么位置发生了一个点击事件(或者别的事件)以后,从最顶层的元素,document,一直向下流到最底层的元素,可能是某一个具体的button,或者某一个图片,等,之后,会再从最底层的元素流到最顶层的document。

这个过程,前半部分,从顶层到底层,叫做事件捕获,就好像一点点找到具体的点击元素一样,后半部分,叫做事件冒泡,就好像从底层元素一点一点告诉顶层自己被点击了。具体的原理不用深究,捕获还是冒泡,都只是影响顺序,一般情况下这里的顺序并不是很重要。
第三个参数,如果是true,就用事件捕获触发,如果是false,就用冒泡触发,默认false。

那么我们来具体看看一个事件处理函数吧

function doClick(event){    var e = event || window.event;    var target = e.target || e.srcElement;    if(target.className == "cont-item"){    }else if(target.nodeName == "P" || target.nodeName == "IMG"){    }    }else if(target.className == "item-title"){    }else{        alert("系统错误:不存在的元素");    }}

首先,函数有一个event参数,前面说过,函数并不关心参数,参数以数组元素的形式存储在argument属性中,所以参数列表不一样也无所谓。
每一个事件处理函数都会接受一个event对象,里面始终保存着当前事件触发的元素,注意,这可能和this不一样

var e = event || window.event;var target = e.target || e.srcElement;

这两行,就是获取event和当前的事件触发元素target。
Event和target可能会在老版本浏览器上存在不兼容现象(主要是IE),所以这里做了适配。
那么现在问一个问题假如我点击了一个button,现在
target,this分别是什么
target是你点击的元素,this在这里是contWrap。
看起来好像跟button没啥关系,实际上不是的,我们先来说明这两个属性。
Target是你当前触发事件的元素,一定是button吗?不一定,因为你的button可能外面还包裹着div等元素,点击事件同时也作用于div上,那么如何准确找到button呢,我们可以在设置元素的同时加一个属性

Button.index = data[i].id;

这里只是模拟一下,因为你可能会需要根据数据设置很多元素,所以,这里假设外围有一个循环,遍历你的数据,只要还有数据,就新建元素,并且把唯一标识,即每次循环的i值作为元素对象的index属性保存,那么下一次,你只需要检查你的button的index属性就可以轻松知道是哪一个元素被点击了。
其次,this是什么。前面说过,this指代当前函数的运行环境,或者说,他的调用对象,谁调用了这个事件处理函数,很显然,就是contWrap在add一个事件监听的时候所以,this指代的是contWrap,这里不小心的话很容易搞错,一定要在事件监听的事件处理函数中手动获取target,不要检查this,因为this不一定是你的具体想要的触发元素。
多说一句,js中的其他对象,比如说array数组,对array[]的时候方括号中的this也是指代的array这个对象,而不是外层的可能有的函数什么的。
到这里,一个事件监听的主要内容就已经谈完了,但是笔者最后还有一些话
当一个区域都需要点击事件的时候,一定要检查所有这个区域的元素,比如,div下面有一个img和一个span,如果你是想点击图片和文字都会触发事件,那一定是要给div,img,span都检查一遍,不然虽然语法没错,但是用户体验可能会很不好。

原创粉丝点击