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. Ubuntu下Django初体验(二)——创建工程及应用

    一.工程目录详解 创建工程后得到如下目录: 1. manage.py 管理项目.创建数据库.启动服务器等.测试等. 查看子命令: python manage.py 启动服务器: python mana ...

  2. MyEclipse中Web项目的发布和运行

    1.右键对应项目的名称:MyEclipse|Add and Remove Project Deployments... 2.点击Add按钮,选择Tomcat7.x,Deploy type选择Explo ...

  3. 关于list、set、map的几点总结

    用法: 1. 如果涉及到堆栈,队列等操作,应该考虑用List, 对于需要快速插入,删除元素,应该使用LinkedList, 如果需要快速随机访问元素,应该使用ArrayList.2. 如果程序在单线程 ...

  4. 常用对象API、附加:集合补充

    基本数据类型对象包装类: 为了方便操作基本数据类型值,将其封装成了对象,在对象中定义了属性和行为丰富了该数据的操作. 用于描述该对象的类就称为基本数据类型对象包装类. byte——Byte short ...

  5. C#面向对象基础:virtual方法,abstract方法,区别

    virtual 关键字用于修饰方法.属性.索引器或事件声明,并使它们可以在派生类中被重写.默认情况下,类中的方法是非虚的,非虚的方法不能在子类中被覆盖(override),但是可以隐藏(new),但这 ...

  6. PHP环境配置综合篇

    1.WNMP: http://www.wnmp.com.cn/     En: https://www.getwnmp.org/ 2.xampp:https://www.apachefriends.o ...

  7. c#类的初始化顺序

    本文转载:http://www.cnblogs.com/ybhcolin/archive/2010/09/24/1834219.html c#类的初始化顺序 类在初始化时的执行顺序,依次如下: 1: ...

  8. PAT---1050. String Subtraction (20)

    #include<iostream> #include<string.h> #include<stdio.h> using namespace std; #defi ...

  9. 【Android XMPP】 学习资料收集贴(持续更新)

    系列一: 基于xmpp openfire smack开发之openfire介绍和部署[1] 基于xmpp openfire smack开发之smack类库介绍和使用[2] 基于xmpp openfir ...

  10. Android开发_字符串处理类-TextUtils类

    对于字符串处理Android为我们提供了一个简单实用的TextUtils类,如果处理比较简单的内容不用去思考正则表达式不妨试试这个在android.text.TextUtils的类,主要的功能如下: ...