深入分析原生JavaScript事件

JQuery这种Write Less Do More的框架,用多了难免会对原生js眼高手低。

小菜其实不想写这篇博客,貌似很初级的样子,但是看到网络上连原生js事件绑定和解除都说不明白,还是决定科普一下了。

首先声明,小菜懂的也不是很多,只是把我的思路和大家分享一下。

DOM0事件模型

事件模型在不断发展,早期的事件模型称为DOM0级别。

DOM0事件模型,所有的浏览器都支持。

直接在dom对象上注册事件名称,就是DOM0写法,比如:

复制代码 代码如下:


document.getElementById("test").onclick = function(e){};

意思就是注册一个onclick事件。当然,它和这种写法是一个意思:

复制代码 代码如下:


document.getElementById("test")["onmousemove"] = function(e){};

这没什么,只不过是两种访问js对象属性的方法,[]的形式主要是为了解决属性名不是合法的标识符,比如:object.123肯定报错,但是object["123"]就避免了这个问题,与此同时,[]的写法,也把js写活了,用字符串表示属性名称,可以在运行时动态绑定事件。

言归正传,事件被触发时,会默认传入一个参数e,表示事件对象,通过e,我们可以获取很多有用的信息,比如点击的坐标、具体触发该事件的dom元素等等。

基于DOM0的事件,对于同一个dom节点而言,只能注册一个,后边注册的同种事件会覆盖之前注册的。例如:

复制代码 代码如下:


 var btn = document.getElementById("test");
 btn.onmousemove = function(e){
   alert("ok");
 };
 btn["onmousemove"] = function(e){
   alert("ok1");
 };

结果会输出ok1。

接下来再说说this。事件触发时,this就是指该事件在哪个dom对象上触发。例如:

复制代码 代码如下:


 var btn = document.getElementById("test");
 btn.onmousemove = function(e){
   alert(this.id);
 };

结果输出test。因为事件就是在id为test的dom节点上注册的,事件触发时,this当然代表这个dom节点,可以理解为事件是被这个dom节点调用的。

所以,想解除事件就相当简单了,只需要再注册一次事件,把值设成null,例如:

复制代码 代码如下:


 var btn = document.getElementById("test");
 btn.onclick = function(e){
   alert("ok");
 };
 btn.onclick = null;

原理就是最后注册的事件要覆盖之前的,最后一次注册事件设置成null,也就解除了事件绑定。

事情还没结束,DOM0事件模型还涉及到直接写在html中的事件。例如:

复制代码 代码如下:


<div ></div>

通过这种方式注册的事件,同样遵循覆盖原则,同样只能注册一个,最后一个生效。

区别就是,这样注册的事件,相当于动态调用函数(有点eval的意思),因此不会传入event对象,同时,this指向的是window,不再是触发事件的dom对象。

DOM2事件模型

DOM2事件模型相对于DOM0,小菜仅仅了解如下两点:

·  DOM2支持同一dom元素注册多个同种事件。

·  DOM2新增了捕获和冒泡的概念。

DOM2事件通过addEventListener和removeEventListener管理,当然,这是标准。

但IE8及其以下版本浏览器,自娱自乐,搞出了对应的attachEvent和detachEvent,由于小菜才疏学浅,本文不做讨论。

addEventListener当然就是注册事件,她有三个参数,分别为:"事件名称", "事件回调", "捕获/冒泡"。举个例子:

复制代码 代码如下:


 var btn = document.getElementById("test");
 btn.addEventListener("click", function(e){
   alert("ok");
 }, false);

事件名称就不用多说了,相比DOM0,去掉了前边的on而已。

事件回调也很好理解,事件触发了总得通知你吧!回调时和DOM0一样,也会默认传入一个event参数,同时this是指触发该事件的dom节点。

最后一个参数是布尔型,true代表捕获事件,false代表冒泡事件。其实很好理解,先来个示意图:

意思就是说,某个元素触发了某个事件,最先得到通知的是window,然后是document,依次而入,直到真正触发事件的那个元素(目标元素)为止,这个过程就是捕获。接下来,事件会从目标元素开始起泡,再依次而出,直到window对象为止,这个过程就是冒泡。

为什么要这样设计呢?这貌似是由于深厚的历史渊源,小菜也不怎么了解,就不乱说了。

由此可以看出,捕获事件要比冒泡事件先触发。

假设有这样的html结构:

复制代码 代码如下:


 <div>
   <div></div>
 </div>

然后我们在外层div上注册两个click事件,分别是捕获事件和冒泡事件,代码如下:

复制代码 代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgxjzw.html