Javascript事件模型(一):DOM0事件和DOM2事件
javascript事件模型,本文主要有以下内容:
- DOM0事件模型
- DOM2事件模型
一、DOM0事件模型
早期的事件模型称为DOM0级别。
DOM0的事件具有极好的跨浏览器优势, 会以最快的速度绑定, 如果你通过DOM2绑定要等到JS运行, DOM0不用, 因为DOM0是写在元素上面;
直接在dom对象上注册事件名称,就是DOM0写法,比如:
document.getElementById("test").onclick = function(e){};
另外一种写法是:
document.getElementById("test")["onclick"] = function(e){};
[]的形式主要是为了解决属性名不是合法的标识符,比如: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就是指该事件在哪个dom对象上触发。例如:
var btn = document.getElementById("OK");
btn.onmousemove = function(e){
alert(this.id);
};
结果输出OK。因为事件就是在id为OK的dom节点上注册的,事件触发时,this当然代表这个dom节点,可以理解为事件是被这个dom节点调用的。
所以,想解除事件就相当简单了,只需要再注册一次事件,把值设成null,例如:
var btn = document.getElementById("OK");
btn.onclick = function(e){
alert("ok");
};
btn.onclick = null;
原理就是最后注册的事件要覆盖之前的,最后一次注册事件设置成null,也就解除了事件绑定。当然,你也可以用unbind等。
DOM0事件模型还涉及到直接写在html中的事件。例如:
1 <div id="test" class="test" onclick="exec();" ></div>
通过这种方式注册的事件,同样遵循覆盖原则,同样只能注册一个,最后一个生效。
区别就是,这样注册的事件,相当于动态调用函数(有点eval的意思),因此不会传入event对象,同时,this指向的是window,不再是触发事件的dom对象。
二、DOM2事件模型
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 id="test" class="test">
<div id="testInner" class="test-inner"></div>
</div>
然后我们在外层div上注册两个click事件,分别是捕获事件和冒泡事件,代码如下:
var btn = document.getElementById("test");
//捕获事件
btn.addEventListener("click", function(e){
alert("ok1");
}, true);
//冒泡事件
btn.addEventListener("click", function(e){
alert("ok");
}, false);
最后,点击内层的div,先弹出ok1,后弹出ok。结合上边的原理图,外层div相当于图中的body,内层div相当于图中最下边的div,证明了捕获事件先执行,然后执行冒泡事件。
为什么要强调点击内层的div呢?因为真正触发事件的dom元素,必须是内层的,外层dom元素才有机会模拟捕获事件和冒泡事件,从原理图上就看出了。
如果在真正触发事件的dom元素上注册捕获事件和冒泡事件呢?
html结构同上,js代码如下:
var btnInner = document.getElementById("testInner");
//冒泡事件
btnInner.addEventListener("click", function(e){
alert("ok");
}, false);
//捕获事件
btnInner.addEventListener("click", function(e){
alert("ok1");
}, true);
当然还是点击内层div,结果是先弹出ok,再弹出ok1。理论上应该先触发捕获事件,也就是先弹出ok1,但是这里比较特殊,因为我们是在真正触发事件的dom元素上注册的事件,相当于在图中的div上注册,由图可以看出真正触发事件的dom元素,是捕获事件的终点,是冒泡事件的起点,所以这里就不区分事件了,哪个先注册,就先执行哪个。本例中,冒泡事件先注册,所以先执行。
这个道理适用于多个同种事件,比如说一下子注册了3个冒泡事件,那么执行顺序就按照注册的顺序来,先注册先执行。例如:
var btnInner = document.getElementById("testInner");
btnInner.addEventListener("click", function(e){
alert("ok");
}, false);
btnInner.addEventListener("click", function(e){
alert("ok1");
}, false);
btnInner.addEventListener("click", function(e){
alert("ok2");
}, false);
结果当然是依次弹出ok、ok1、ok2。
为了进一步理解事件模型,还有一种场景,假如说外层div和内层div同时注册了捕获事件,那么点击内层div时,外层div的事件一定是先触发的,代码如下:
var btn = document.getElementById("test");
var btnInner = document.getElementById("testInner");
btnInner.addEventListener("click", function(e){
alert("ok");
}, true);
btn.addEventListener("click", function(e){
alert("ok1");
}, true);
结果是先弹出ok1。
假如外层div和内层div都是注册的冒泡事件,点击内层div时,一定是内层div事件先执行,原理相同。
细心的读者会发现,对于div嵌套的情况,如果点击内层的div,外层的div也会触发事件,这貌似会有问题!
点击的明明是内层div,但是外层div的事件也触发了,这的确是个问题。
其实,事件触发时,会默认传入一个event对象,前边提过了,这个event对象上有一个方法:stopPropagation,通过此方法,可以阻止冒泡,这样外层div就接收不到事件了。代码如下:
var btn = document.getElementById("test");
var btnInner = document.getElementById("testInner");
btn.addEventListener("click", function(e){
alert("ok1");
}, false);
btnInner.addEventListener("click", function(e){
//阻止冒泡
e.stopPropagation();
alert("ok");
}, false);
解除事件语法:btn.removeEventListener("事件名称", "事件回调", "捕获/冒泡");
这和绑定事件的参数一样,详细说明下:
· 事件名称,就是说解除哪个事件呗。
· 事件回调,是一个函数,这个函数必须和注册事件的函数是同一个。
· 事件类型,布尔值,这个必须和注册事件时的类型一致。
也就是说,名称、回调、类型,三者共同决定解除哪个事件,缺一不可。举个例子:
var btn = document.getElementById("test");
//将回调存储在变量中
var fn = function(e){
alert("ok");
};
//绑定
btn.addEventListener("click", fn, false);
//解除
btn.removeEventListener("click", fn, false);
要想注册过的事件能够被解除,必须将回调函数保存起来,否则无法解除。
Javascript事件模型(一):DOM0事件和DOM2事件的更多相关文章
- JS事件模型小结
三种事件模型:原始事件模型(DOM0),DOM2事件模型,IE事件模型: 不同点: 事件程序的注册(给HTML元素所对应的JS对象绑定事件) 事件传播的过程 事件模型的注册: 一.原始事件模型(没有兼 ...
- JavaScript事件模型及事件代理
事件模型 JavaScript事件使得网页具备互动和交互性,我们应该对其深入了解以便开发工作,在各式各样的浏览器中,JavaScript事件模型主要分为3种:原始事件模型.DOM2事件模型.IE事件模 ...
- 理解javascript中的事件模型
javascript中有两种事件模型:DOM0,DOM2.而对于这两种的时间模型,我一直不是非常的清楚,现在通过网上查阅资料终于明白了一些. 一. DOM0级事件模型 DOM0级事件模型是早期的事件 ...
- 【repost】JavaScript 事件模型 事件处理机制
什么是事件? 事件(Event)是JavaScript应用跳动的心脏 ,也是把所有东西粘在一起的胶水.当我们与浏览器中 Web 页面进行某些类型的交互时,事件就发生了.事件可能是用户在某些内容上的点击 ...
- javascript中0级DOM和2级DOM事件模型浅析
Javascript程序使用的是事件驱动的设计模式,为一个元素添加事件监听函数,当这个元素的相应事件被触发那么其添加的事件监听函数就被调用: <input type="button&q ...
- JavaScript 事件模型 事件处理机制
什么是事件? 事件(Event)是JavaScript应用跳动的心脏 ,也是把所有东西粘在一起的胶水.当我们与浏览器中 Web 页面进行某些类型的交互时,事件就发生了.事件可能是用户在某些内容上的点击 ...
- javascript中0级DOM和2级DOM事件模型浅析 分类: C1_HTML/JS/JQUERY 2014-08-06 15:22 253人阅读 评论(0) 收藏
Javascript程序使用的是事件驱动的设计模式,为一个元素添加事件监听函数,当这个元素的相应事件被触发那么其添加的事件监听函数就被调用: <input type="button&q ...
- JS的事件模型
之前对事件模型还是比较清楚的,许多概念都清晰映射在脑海中.工作之后,一方面使用的局限性,二是习惯于用框架中的各种事件监听方式,简单即方便,久而久之,事件的一些概念开始淡出记忆中,就像我现在已经开始淡忘 ...
- Javascript高级编程学习笔记(58)—— 事件(2)事件处理程序
事件处理程序 事件处理程序即响应某个事件的函数 事件处理程序以 “on” 开头 如“onclick”,“onload” HTML事件处理程序 某个元素支持的每种事件都可以使用一个与响应的事件处理程序同 ...
随机推荐
- es5和es6实现lazyman
es6实现 1 class _LazyMan { constructor(name) { this.tasks = []; this.sleep = this.sleep.bind(this); th ...
- LVS + keepalived(DR) 实战
一.LVS体系结构 使用LVS架设的服务器集群系统有三个部分组成:最前端的负载均衡层,用Load Balancer表示,中间的服务器群组层,用Server Array表示,最底端的数据共享存储层,用S ...
- C#处理JSON 数据
网络中数据传输经常是xml或者json,现在做的一个项目之前调其他系统接口都是返回的xml格式,刚刚遇到一个返回json格式数据的接口,通过例子由易到难总结一下处理过程,希望能帮到和我一样开始不会的朋 ...
- 启动LUXContentTests过程中遇到的问题
首先,要想在localbox中使用Selenium,就得准备好浏览器的driver文件.比如chrome对应的chromedriver文件,该文件是一个exe可执行文件. 问题:当我尝试去跑LUXCo ...
- Linux 系统管理04--账号管理
Linux系统管理04--账号管理 一.用户账号管理 1.用户账号概述 (1)用户账号的常见分类: 1>超级用户:root uid=0 gid=0 权限最大. 2>普通用户:uid> ...
- GPIO的配置过程
今天看到一篇很好的博文,,看这里:http://www.cnblogs.com/crazyxu/archive/2011/10/14/2212337.html 下面总结一下,加深一下理解. 要使用GP ...
- effective c++ 思维导图
历时两个多月的时间,终于把effective c++又复习了一遍,比较慢,看的是英文版,之前看的时候做过一些笔记,但不够详细,这次笔者是从头到尾的翻译了一遍,加了一些标题,先记录到word里面,然后发 ...
- jquery ajax自定义分页组件(jquery.loehpagerv1.0)原创
简单的两个步骤截可调用 <script src="<%=basePath%>/resources/js/jquery-1.7.1.min.js"></ ...
- phpcms笔记
一.建立虚拟站点 1.先更改www目录下的站点名称,再找到apache, 打开"Apache2\conf\extra"下的"httpd-vhosts.conf" ...
- nginx源码分析——configure脚本
源码:nginx 1.13.0-release 一.前言 在分析源码时,经常可以看到类似 #if (NGX_PCRE) .... #endif 这样的代码段,这样的设计可以在不改动源码的 ...