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. openstack libtray

    OpenStack packages¶ Distributions release OpenStack packages as part of the distribution or using ot ...

  2. /usr/bin/ld: cannot find *** 的处理

    /usr/bin/ld: cannot find *** 的处理

  3. NTP DDOS攻击

    客户端系统会ping到NTP服务器来发起时间请求更换,同步通常每隔10分钟发生: 从NTP服务器发回到客户端的数据包可能比初始请求大几百倍.相比之下,通常用于放大攻击中的DNS响应被限制仅为8倍的带宽 ...

  4. Shell until循环

    until 循环执行一系列命令直至条件为 true 时停止.until 循环与 while 循环在处理方式上刚好相反.一般while循环优于until循环,但在某些时候,也只是极少数情况下,until ...

  5. js_面向对象编程

    主要内容 值类型与引用类型的特征 深拷贝与浅拷贝 对象的动态特性 构造函数的执行过程 异常处理 dom操作(略) <!DOCTYPE html> <html> <head ...

  6. C# 自己对delegate的总结和认识

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  7. 【转】SVN:Android Studio设置忽略文件

    Android Studio创建的Android项目一般需要忽略 参考: http://blog.csdn.net/qq_22780533/article/details/51965007 1..id ...

  8. 如何让Windows程序只运行一个程序实例?

    要实现VC++或者MFC只运行一个程序实例,一般采用互斥量来实现,即首先用互斥量封装一个只运行一个程序实例的函数接口: HANDLE hMutex = NULL; void MainDlg::RunS ...

  9. Java基础知识强化之集合框架笔记59:Map集合之TreeMap(TreeMap<String,String>)的案例

    1. TreeMap类的概述: 键是红黑树结构,可以保证键的排序和唯一性. 2. TreeMap案例: TreeMap<String, String> 代码示例: package cn.i ...

  10. WPF – 使用触发器

    WPF – 使用触发器 WPF提供了很重要的一个东西就是绑定Binding, 它帮助我们做了很多事情,这个我们在WPF学习之绑定这篇里边有讲过.对于Binding我们可以设置其绑定对象,关系,并通过某 ...