"事件是一种异步编程的实现方式,本质上是程序各个组成部分之间的通信。
1、EventTarget接口
dom的事件操作(监听和触发),都定义在这个接口上。
该接口有三个方法:
addEventListener:绑定事件的监听函数
removeEventListener:移除事件的监听函数
dispatchEvent:触发事件
1.1、addEventListener
格式:target.addEventListener(type,listener[,useCapture]);
"useCapture":监听函数是否在捕获阶段触发。默认为false(监听函数在冒泡阶段触发)。
addEventListener方法可以给当前对象的同一事件,添加多个监听函数,执行顺序是先添加先执行。但是如果监听函数也是同一个,则只执行一次。
1.2、removeEventListener()
removeEventListener方法用来移除addEventListener方法添加的事件监听函数。
1.3、dispatchEvent()
当前节点触发指定事件,从未触发监听的函数。这个方法类似于jQuery中的trigger方法,主动触发某个element上的监听方法。
温馨提示:上面说到了可以使用脚本去触发一个事件的发生,那如果要区分这个事件是用户真实触发还是脚本触发该怎么办呢?可以使用event对象下的 isTrusted 属性。event.isTrusted:用户触发的事件返回true,脚本触发的返回false。
2、监听函数
dom提供三种方式,用来为事件绑定监听函数。
2.1、on-属性
就是行内点击事件,<div onclick="myClick()">点我</div>
2.2、element节点的事件属性
window.onload=doSomething;
div.onclick=function(event){console.log('触发事件');};
使用这个方法指定的监听函数,只会在冒泡阶段触发。
2.3、addEventListener方法
使用 html标签 on-属性,违反了html和js代码分离原则;使用 element节点的事件属性 的缺点是,同一个事件只能定义一个监听函数,也就是说,如果定义两次onclick属性,后一次定义会覆盖前一次。因此,这两种方法都不推荐使用。
推荐使用 addEventListener 有点如下:
①、可以针对同一个事件,添加多个监听函数。
②、能够指定在哪个阶段(捕获阶段还是冒泡阶段)触发回监听函数。
③、除了DOM节点,还可以部署在window、XMLHttpRequest等对象上面,等于统一了整个JavaScript的监听函数接口。
2.4、this对象的指向
使用addEventListener 触发函数中的this指向 element对象。
使用on-属性,触发函数中的this不会指向触发事件的元素节点。
3、事件传播
3.1、事件传播的三个阶段
事件在dom之间传播有三个阶段:捕获阶段、目标阶段、冒泡阶段
事件传播的最上层对象是window,接着依次是document,html(document.documentElement)和body(document.dody)。也就是说,如果元素中有一个
元素,点击该元素。事件的传播顺序,在捕获阶段依次为window、document、html、body、div,在冒泡阶段依次为div、body、html、document、window。
注意,用户点击网页的时候,浏览器总是假定click事件的目标节点,就是点击位置的嵌套最深的那个节点(嵌套在节点的节点)。所以,最底层那个节点的捕获阶段和冒泡阶段,都会显示为target阶段。
如果希望事件到某个节点为止,不再传播,可以使用事件对象的stopPropagation方法。
4、自定义事件和事件模拟
除了浏览器预定义的那些事件,用户还可以自定义事件,然后手动触发。
这种方式IE不支持。
5、事件冒泡
e.preventDefault(); // 只阻止事件的默认行为,但不能阻止事件往上冒泡。
window.event.returnValue = false; //IE中阻止函数器默认动作的方式
e.stopPropagation(); // 可以阻止事件冒泡
e.cancelBubble = true; // IE下阻止事件冒泡
比较暴力的方式有:
return false; // 阻止事件冒泡
扩展:
e.stopImmediatePropagatio() //同一节点添加多个点击事件时,使用这个API可以控制后续 handle是否执行
Keeps the rest of the handlers from being executed and prevents the event from bubbling up the DOM tree.
比如一个 div 添加 addEventListener click事件,添加两次,当我们点击这个div时,这两个监听事件都会执行,那能不能控制在第一个监听回调函数,控制第二个回调函数不执行呢?可以。在第一个回调函数执行 e.stopImmediatePropagatio() ,第二个函数就不会执行了