JS学习笔记05-网页事件
事件的本质是程序各个组成部分之间的一种通信方式,也是异步编程的一种实现。DOM支持大量的事件,本章开始介绍DOM的事件编程。
一、模型
浏览器的事件模型,就是通过监听函数(listener)对事件做出反应。事件发生后,浏览器监听到了这个事件,就会执行对应的监听函数。这是事件驱动编程模式(event-driven)的主要编程方式。
DOM事件流(event flow)有两种:事件冒泡、事件捕获。无论是事件捕获还是事件冒泡,它们都有一个共同的行为事件传播。它就像一跟引线,只有通过引线才能将绑在引线上的鞭炮(事件监听器)引爆。
DOM标准事件流的触发的先后顺序为:先捕获再冒泡。即当触发DOM事件时,会先进行事件捕获,捕获到事件源之后通过事件传播进行事件冒泡。不同的浏览器对此有着不同的实现:IE10及以下不支持捕获型事件,所以就少了一个事件捕获阶段,IE11、Chrome 、Firefox、Safari等浏览器则同时存在。
如果希望事件到某个节点为止,不再向上或向下传播,可以使用事件对象的event.stopPropagation()方法。它会阻止事件继续捕获或者冒泡。如果想要彻底取消该事件,不再触发该节点所拥有的某个事件的所有监听函数,可以使用event.stopImmediatePropagation()方法。
<body>
<div id="parent">
父元素
<div id="child">
子元素
</div>
</div>
<script type="text/javascript">
// 通过"addEventListener"方法,采用事件冒泡方式给dom元素注册click事件
var parent = document.getElementById("parent");
var child = document.getElementById("child");
document.body.addEventListener("click",function(e){
console.info("click-body");
},false);
parent.addEventListener("click",function(e){
console.info("click-parent");
},false);
child.addEventListener("click",function(e){
console.info("click-child");
},false);
</script>
</body>
1.1 事件捕获
事件捕获(event capturing):顺序是由外到内进行事件传播,直到叶子节点。如点击了子元素,如果父元素通过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件。
// 在原始代码新增事件捕获事件代码
parent.addEventListener("click",function(e){
console.info("click-parent--事件捕获");
},true);
// 点击子元素依次会输出:click-parent--事件捕获、click-child、click-parent、click-body
1.2 事件冒泡
事件冒泡(dubbed bubbling):顺序是由内到外进行事件传播,直到根节点。
// 上述过程,点击子元素依次会输出:click-child、click-parent、click-body
// 如果点击子元素不想触发父元素的事件怎么办
// 在原始代码新增停止事件传播--event.stopPropagation()
child.addEventListener("click",function(e){
console.info("click-child");
e.stopPropagation();
},false);
// 点击子元素只会输出:click-child
1.3 事件委托
事件委托还有一个名字叫事件代理,一般用于动态生成的元素。事件委托是利用事件冒泡原理来实现的,只指定一个事件处理程序,就可以管理某一类型的所有事件。
有三个同事预计会在周一收到快递。为签收快递有两种办法:一是三个人在公司门口等快递;二是委托给前台代为签收。现实当中大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递)。前台MM收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台MM也会在收到寄给新员工的快递后核实并代为签收。这里有2层意思的:
- 现在委托前台的同事是可以代为签收的,即程序中的现有的dom节点是有事件的
- 新员工也是可以被前台MM代为签收的,即程序中新添加的dom节点也是有事件的
一般来说,DOM需要有事件处理程序,直接给它设事件处理程序就好了!如果是很多的DOM(比如有100个li)需要添加事件处理呢?每个li都有相同的click点击事件,可能会用for循环的方法来遍历所有的li,然后给它们添加事件,那这么做会存在什么影响呢?
- 减少内存消耗:每个函数都是一个对象,对象越多内存占用率就越大,自然性能就越差了。如100个li就要占用100个内存空间。如果用事件委托,那么就可以只对它的父级
<ul>这一个对象进行操作,这样需要一个内存空间就够了。- 减少DOM操作:在JS中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互。访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间。如果要用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能。
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。适合用事件委托的事件:click、keydown、keyup、keypress。不适合的主要分为两大类:一类是没有冒泡机制的,如focus、blur;另一类是每次都要计算它的位置而非常不好把控的如mousemove。
二、接口
DOM 的事件操作(监听和触发),都定义在EventTarget接口。所有节点对象都部署了这个接口,其他一些需要事件通信的浏览器内置对象(如XMLHttpRequest、AudioNode、AudioContext)也部署了这个接口。
-
EventTarget.addEventListener()用于在当前节点或对象上,定义一个特定事件的监听函数,一旦这个事件发生,就会执行监听函数。该方法可以为当前对象的同一个事件添加多个不同的监听函数:这些函数按照添加顺序触发;如果为同一个事件多次添加同一个监听函数,该函数只会执行一次,多余的添加将自动被去除。该方法接受三个参数:-
type:事件名称,大小写敏感。 -
listener:监听函数。事件发生时会调用该监听函数。该参数除了监听函数,还可是一个具有handleEvent方法的对象。监听函数内部的this指向当前事件所在的那个对象。 -
useCapture:布尔值,表示监听函数是否在捕获阶段(capture)触发,默认为false(监听函数只在冒泡阶段被触发)。该参数可选外,还可是一个属性配置对象。该对象有以下属性:once:布尔值,表示监听函数是否只触发一次,然后就自动移除。capture:布尔值,表示该事件是否在捕获阶段触发监听函数。passive:布尔值,表示监听函数不会调用事件的preventDefault方法。如果监听函数调用了,浏览器将忽略这个要求,并在监控台输出一行警告。
-
-
EventTarget.removeEventListener方法用来移除addEventListener方法添加的事件监听函数。注意如果该方法要生效,其三个参数必须与addEventListener方法完全一致。 -
EventTarget.dispatchEvent方法在当前节点上触发指定事件,从而触发监听函数的执行。该方法返回一个布尔值,只要有一个监听函数调用了Event.preventDefault(),则返回值为false,否则为true。该方法的参数是一个Event对象的实例。
三、事件
事件发生以后,会产生一个事件对象,作为参数传给监听函数。浏览器原生提供一个Event对象,所有的事件都是这个对象的实例,如鼠标事件、键盘事件、触摸事件、表单事件等,详情见这里。
Event构造函数接受两个参数。第一个参数type是字符串,表示事件的名称;第二个参数options是一个对象,表示事件对象的配置。该对象主要有下面两个属性。
bubbles:布尔值(可选),默认为false,表示事件对象是否冒泡。cancelable:布尔值(可选),默认为false,表示事件是否可以被取消,即能否用Event.preventDefault()取消这个事件。一旦事件被取消,就好像从来没有发生过,不会触发浏览器对该事件的默认行为。
3.1 对象属性
-
Event.type属性返回一个字符串,表示事件类型。 -
Event.bubbles属性返回一个布尔值,表示当前事件是否会冒泡。 -
Event.eventPhase属性返回一个整数常量,表示事件目前所处的阶段。返回值有四种可能:- 0:事件目前没有发生
- 1:事件处于捕获阶段
- 2:事件到达目标节点
- 3:事件处于冒泡阶段
-
Event.target属性返回原始触发事件的那个节点,即事件最初发生的节点。 -
Event.currentTarget属性返回事件当前所在的节点,即事件当前正在通过的节点。
3.2 对象方法
Event.preventDefault方法取消浏览器对当前事件的默认行为。比如点击链接后,浏览器默认会跳转到另一个页面,使用这个方法以后,就不会跳转了。注意该方法只是取消事件对当前元素的默认影响,不会阻止事件的传播。Event.stopPropagation方法阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,但是不包括在当前节点上该事件其他监听函数执行情况。Event.stopImmediatePropagation方法阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,同时也包括在当前节点上该事件其他监听函数不再执行。

浙公网安备 33010602011771号