DOM 事件是 JS 中比较重要的一部分知识,所谓事件,简单理解就是用户对浏览器进行的一个操作。事件在 Web 前端领域有很重要的地位,很多重要的知识点都与事件有关,所以学好 JS 事件可以让我们在JS的学习道路中更进一步。

1、事件流

  事件流描述的是从页面中接受事件的顺序。但是 IE 和 Netscape 开发团队提出了两个截然相反的事件流概念,IE 的事件流是事件冒泡流,而 Netscape 的事件流是事件捕获流。

  (1)、事件冒泡

  事件冒泡,即事件最开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播至最不具体的节点(document)。

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>事件流</title> </head>
<body>
<div>
<input type="button" value="按钮">
</div>
</body>
</html>

  上面的实例,在点击按钮之后,click 事件会按照如下的顺序逐级传播:

  input -> div -> body -> html -> document

  所有现代的浏览器都支持事件冒泡,但是在具体的实现上又有一些差别:

  IE5.5 及更早版本中的事件冒泡会跳过 html 元素(从 body 直接跳到 document)。

  IE9、Firefox、Chrome 和 Safari 则将事件一直冒泡到 window 对象。

  (2)、事件捕获

  事件捕获的思想是不太具体的 DOM 节点应该更早接收到事件,而最具体的节点最后接收到事件。

  按照事件捕获的思想,上面的实例,click 事件将会以如下的顺序逐级传播:

  document -> html -> body -> div -> input

  事件捕获和事件冒泡的传播顺序正好是相反的,虽然事件捕获是 Netscape 唯一支持的事件流模型,但 IE9、Safari、Chrome、Opera 和 Firefox 目前也都支持这种事件流模型。

  (3)、DOM 事件流

  "DOM2级事件" 规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。即同时支持冒泡和捕获,在任何事件发生时,先从顶层开始进行事件捕获,直到事件触发到达了最具体的元素,然后,再从最具体的元素向上进行事件冒泡,直到到达 document 。

  在 DOM 事件流中,实际的目标在捕获阶段不会接收事件。就是说在捕获阶段,事件从 document 到 html 再到 body 后就停止了。下一个阶段是“处于目标”阶段,于是事件在 div 中发生,并在事件处理中被看成是冒泡阶段的一部分。然后,在冒泡阶段发生。IE8 及更早的版本不支持 DOM 事件流,浏览器在捕获阶段触发事件对象上的事件,结果就是有两个机会在目标对象上面操作事件。

2、事件处理程序

  (1)、HTML 事件处理程序

  HTML 事件处理程序就是直接把事件添加在 HTML 结构中。

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>事件</title> </head>
<body>
<input type="button" value="按钮" onclick="alert('Hello')">
</body>
</html>

  也可以调用在页面中其他地方定义的脚本:

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>事件</title> </head>
<body>
<input type="button" value="按钮" onclick="show()">
<script>
function show(){
alert('Hello');
}
</script>
</body>
</html>

  事件处理程序中的代码在执行时,有权访问全局作用域中的任何代码。

  这样使用会创建一个封装着的元素属性值的函数。这个函数有一个局部变量 event ,也就是事件对象:

<input type="button" value="按钮" onclick="alert(event.type)">

  上面的代码返回:click

<input type="button" value="按钮" onclick="alert(event.target)">

  上面的代码返回:input 元素

  其中,this 值等于事件的目标元素,如:

<input type="button" value="按钮" onclick="alert(this.value)">

  上面的代码返回:按钮

  所谓的事件对象就是 event,在触发 DOM 上的事件时都会产生一个事件对象。

  type:用于获取事件类型。target:用于获取事件目标。

  而在 IE8 及更早版本获取事件目标要使用 srcElement 属性代替。

  所有现代浏览器引用事件对象,都可以直接使用 event 引用,而在 IE8 及之前版本的浏览器则需要使用 window.event 引用。

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>事件</title> </head>
<body>
<input type="button" value="按钮" onclick="show()" >
<script>
function show(ev){
ev = event || window.event;
var ele = ev.target || ev.srcElement;
alert(ele);
}
</script>
</body>
</html>

  HTML事件处理程序的缺点:HTML 代码和 JS 代码紧密的耦合在一起,如果需要对事件做出更改,那么 JS 代码和 HTML 代码都需要更改。所以应该使用 JS 指定的事件处理程序。

  (2)、JS 传统事件处理程序

  JS 中非常传统的方式,就是在一个元素上直接绑定方法,即先获取元素,再以属性方式添加事件。

  该方式也叫做 DOM0级 事件处理程序。element.onclick = function(e){}

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>事件</title> </head>
<body>
<input type="button" value="按钮" id="btn">
<script>
var oBtn = document.getElementById('btn');
oBtn.onclick = function (){
alert('Hello');
}
</script>
</body>
</html>

  把一个函数赋值给一个事件处理程序的属性,这是用的比较多的方式,非常简单而且稳定,可适应不同的浏览器,但是这样的事件绑定只会在事件冒泡中运行,捕获不行,且一个事件每次只能绑定一个事件函数。

  使用该方式指定的事件处理程序被认为是元素的方法,因此,这时候的事件处理程序是在元素的作用域中运行的,也就是 this 指向当前元素:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>事件</title> </head>
<body>
<input type="button" value="按钮" id="btn">
<script>
var oBtn = document.getElementById('btn');
oBtn.onclick = function (){
alert(this.type);
}
</script>
</body>
</html>

  上面的代码返回:button

  DOM0级 在删除事件时,直接让事件等于空。如:oBtn.onclick=null;

  (3)、W3C 事件处理程序

  W3C 中推荐使用 addEventListener() 函数进行事件绑定,使用 removeEventListener() 函数删除事件。这种方式也叫做 DOM2级 事件处理程序,它们都接收三个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。

  通常事件监听都是添加在冒泡阶段,所以添加事件的布尔值为 false。element.addEventListener('click', function (){...}, false)

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>事件</title> </head>
<body>
<input type="button" value="按钮" id="btn">
<script>
var oBtn = document.getElementById('btn');
oBtn.addEventListener('click', function (){
alert('Hello');
}, false);
</script>
</body>
</html>

  该方式和前边传统方式绑定事件的效果是一样的,这种方式绑定同时支持冒泡和捕获,addEventListener() 函数最后的参数表达了事件处理的阶段:false(冒泡),true(捕获)。这种方式最重要的好处就是对同一元素的同一个类型事件做绑定不会覆盖,比如上面代码中,再给 oBtn 绑定一个 click 事件,那么两次绑定的事件都会被执行,按照代码的顺序依次执行。

  通过 addEventListener() 函数添加的事件只能通过 removeEventListener() 函数删除,在删除事件时,必须传入与添加事件相同的参数。所以,用 addEventListener() 添加的匿名函数将无法移除。

  DOM2级 方式和 DOM0级 方式都可以给一个元素添加多个事件,添加的多个事件依次按顺序执行。

  大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。

  (4)、IE 中的事件处理程序

  在 IE 浏览器下不支持 addEventListener() 函数,只能在 IE9 以上(包括IE9)可以使用,IE 浏览器相应的要使用 attachEvent() 函数代替。

  删除事件则使用 detachEvent() 函数。这两个方法接收相同的两个参数:事件处理程序名称与事件处理函数。

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>事件</title> </head>
<body>
<input type="button" value="按钮" id="btn">
<script>
var oBtn = document.getElementById('btn');
oBtn.attachEvent('onclick', function (){
alert('Hello');
});
</script>
</body>
</html>

  attachEvent() 函数支持事件捕获的冒泡阶段,同时它不会覆盖事件的绑定。如果在 Firefox、Chrome 等其他内核的浏览器中使用这个函数去绑定事件,浏览器会报错。

如果需要做跨浏览器的事件处理程序,则需要做兼容性处理,即判断是否支持 attachEvent 方法,如果支持就使用该方法,如果不支持则使用 addEventListener() 方法。

  这里需要注意: attachEvent() 的第一个参数是“onclick”,而不是 addEventListener()方法中的“click"。

3、事件流阻止

  事件流阻止,这里阻止的是它的继续传播以及有可能产生的默认动作。

  在一些情况下我们需要阻止事件流的传播,也就是阻止事件的向上冒泡。

  某些事件的对象是可以取消的,这也意味着可以阻止默认动作的发生。

  W3C 中定义了两个方法:stopPropagation() 和 preventDefault() 用于阻止事件流。

  event.stopPropagation()  方法用于阻止事件冒泡。

  event.preventDefault()  方法用于阻止事件的默认行为。

  阻止事件的默认行为在做移动端 app 时,用的比较多,比如 a 链接的跳转,不跳转新页面,而是跳转不同的位置。

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>事件</title> </head>
<body>
<div id="box">
<a href="http://www.baidu.com" id="go">跳转</a>
</div>
<script>
var oDiv = document.getElementById('box');
var oA = document.getElementById('go');
oDiv.onclick = function (){
alert('我是a链接的父容器');
}
oA.onclick = function (ev){
ev.stopPropagation();
ev.preventDefault();
}
</script>
</body>
</html>

  上面的例子中,点击 a 链接后有一个默认的跳转行为,并且浏览器会认为你点了 a 链接,也就点了其父容器 div 元素。阻止了事件冒泡和默认行为之后,再点击跳转,就不会有任何响应了。

  stopPropagation() 和 preventDefault() 这两个方法都可以阻止事件,前者是取消事件流的继续冒泡,但是 IE8 及以前的版本不支持该方法,而后者是告诉浏览器不要执行与事件相关联的默认动作,比如 submit 类型的按钮点击会提交。如果直接使用 return false 则表示终止处理函数。

  在 IE8 及之前版本的浏览器中没有定义阻止事件流的方法,而是使用属性,cancelBubble 属性值为 true 时取消事件冒泡。returnValue 属性值为 false 时阻止事件的默认行为。

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>事件</title> </head>
<body>
<div id="box">
<a href="http://www.baidu.com" id="go">跳转</a>
</div>
<script>
var oDiv = document.getElementById('box');
var oA = document.getElementById('go');
oDiv.onclick = function (){
alert('我是a链接的父容器');
}
oA.onclick = function (ev){
ev = event || window.event;
if(ev.stopPropagation){
ev.stopPropagation();
}
else{
ev.cancelBubble = true;
}
if(ev.preventDefault){
ev.preventDefault();
}
else{
ev.returnValue = false;
}
}
</script>
</body>
</html>

  上面的代码,是兼容性写法,不管是现代的浏览器还是 IE8 及更早版本的浏览器都可以使用。

JavaScript学习总结【10】、DOM 事件的更多相关文章

  1. JavaScript:学习笔记(10)——XMLHttpRequest对象

    JavaScript:学习笔记(10)——XMLHttpRequest对象 XHR对象 使用XMLHttpRequest (XHR)对象可以与服务器交互.您可以从URL获取数据,而无需让整个的页面刷新 ...

  2. JavaScript学习 - 基础(七) - DOM event(事件)

    DOM event(事件) 定义事件: // 定义事件: //方式一,直接在标签上定义事件 // 方式二: var a11 = document.getElementsByName('a11')[0] ...

  3. JavaScript学习笔记(10)——JavaScript语法之操作DOM

    1.页面输出用document.write()方法,但是不可以在window.onload中用,否则整个html页面将被覆盖. 2.通过javascript获取对象后,改变对象中的html内容:doc ...

  4. javascript学习笔记之DOM与表单

    DOM(文档对象模型),猫叔了一个层次化的节点树 一.DOM NODE相关公共属性与方法 DOM中所有节点都实现了NODE接口,该接口的公共属性和方法如下: 1.节点基本属性 1)NodeType 节 ...

  5. javascript学习笔记之DOM

    DOM(文档对象模型),描述了一个层次化的节点树 一.DOM NODE相关公共属性与方法 DOM中所有节点都实现了NODE接口,该接口的公共属性和方法如下: 1.节点基本属性 1)NodeType 节 ...

  6. javascript学习 真正理解DOM脚本编程技术背后的思路和原则

    本文学习来源于<javascriptDOM编程艺术>仅作笔记 学会怎样才能利用DOM脚本编程技术以一种既方便自己更体贴用户的方式去充实和完善你们的网页. 循序渐进:从最核心的内容开始,逐步 ...

  7. JavaScript 学习笔记-HTML&&DOM

    HTML DOM (文档对象模型) 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model). HTML DOM 模型被构造为对象的树. JavaScript 能够 ...

  8. 【JavaScript学习整理】DOM对象(location history screen navigator)

    DOM: 描述网页各个组成部分之间的关系. parentNode: 父节点 childNode: 子节点 firstChild: 第一个子节点 lastChild: 最后一个子节点 nextSibli ...

  9. JavaScript学习笔记之DOM对象

    目录 1.Document 2.Element 3.Attribute 4.Event 1.Document 每个载入浏览器的 HTML 文档都会成为 Document 对象,Document 对象允 ...

  10. JavaScript学习笔记之DOM介绍

    目录 1.简介 2.方法 3.属性 4.访问节点 5.修改节点 6.添加节点 7.删除节点 8.替换节点 9.改变 CSS 1.简介 文档对象模型(Document Object Model,DOM) ...

随机推荐

  1. jQuery之前端国际化jQuery.i18n.properties

    jQuery.i18n.properties是一款轻量级的jQuery国际化插件,能实现Web前端的国际化. 国际化英文单词为:Internationalization,又称i18n,"i& ...

  2. JQuery- 动画与效果

    这几天做网站,刚好用到! 1.基本效果 匹配元素从左上角开始变浓变大或缩小到左上角变淡变小 ①隐藏元素 除了可以设置匹配元素的display:none外,可以用以下函数 hide(speed,[cal ...

  3. Hibernate学习之get和load区别

    结论: insert():插入记录并将同步更新到session缓存. update():更新记录并同步更新到session缓存. delete():删除记录并同步更新session缓存. get(): ...

  4. Splunk < 6.3 版本 SSL 证书过期事宜

    最近Splunk发出邮件提醒客户SSL证书过期事宜. 问题看起来比较严重,因为所有的实例,包括 forwarder\peernode\indexer\master node 等等都受影响,而且Depl ...

  5. iOS OC开发代码规范

    1.变量.类名.函数名 使用驼峰命名法 2.尽量使用完整的单词命名,尽量不采用 缩写单词 3.类名使用大写字母打头,前缀统一加上HH 例如:HHHomePageController 4.类的成员变量使 ...

  6. nginx图片过滤处理模块http_image_filter_module安装配置笔记

    http_image_filter_module是nginx提供的集成图片处理模块,支持nginx-0.7.54以后的版本,在网站访问量不是很高磁盘有限不想生成多余的图片文件的前提下可,就可以用它实时 ...

  7. 【Java基础】Jar包结构结构分析和操作具体解释

    作者:郭嘉 邮箱:allenwells@163.com 博客:http://blog.csdn.net/allenwells github:https://github.com/AllenWell 一 ...

  8. STM32的优先级NVIC_PriorityGroupConfig的理解及其使用

    写作原由:因为之前有对stm32 优先级做过研究,但是没时间把整理的东西发表,最近项目需要2个串口,但是不是两个串口同时使用,只是随机使用其中一个,程序对2个串口的优先级需要配置: 此文思路:“中断优 ...

  9. windows向ubuntu过渡之常用编程软件安装

    不出意外的上篇文章又被踢出首页了,心情甚是悲桑..希望更多人能看到 1.安装codeblocks 直接在软件中心搜索codeblocks就可以 2.安装jdk并配置环境变量 http://www.li ...

  10. jwPlayer实现支持IE8及以下版本避免出错的方法

    jwplayer在支持Html5的情况下会自动使用html5的video和audio标签进行播放视频和音频.但是在IE中版本低于IE9时 <script src="jwplayer.h ...