1.何为DOM

DOM是“Document Object Model”的缩写,中文译为“文档对象模型”。它是一种跨平台、跨语言的编程接口,将HTML,XHTML,XML文档映射成树形结构,树的每一个节点都是一个对象。正因如此,面向对象的编程语言(如javascript)可以通过DOM对HTML,XHTML,XML文档进行操作。对于HTML文档来说,它的根结点为document对象,HTML元素为element对象,HTML元素的属性为attr对象。

2.何为DOM事件及如何对其作出响应

在浏览网页时,我们常常需要页面对用户的操作作出响应,比如点击“阅读全文”后我们期望页面展示被折叠的文本,按下回车键后浏览器提交已填好的表单。用户的各种操作都是“事件”。事件都是在对象上发生的,可能是DOM对象、BOM对象,等等。事件发生后,对象可能会作出响应,也有可能“无动于衷”。我们希望DOM元素对事件作出响应,一般而言有两种方法:
i.事件属性
事件属性是一种特殊的属性,它的值规定了对应事件发生时需要执行的javascript脚本。例:

```<button onclick="console.log('button clicked!')"></button>
```

上面为button标签添加了事件属性onclick,其值为"console.log('button clicked!')",它规定了当元素被鼠标点击时,控制台输出'button clicked'。
ii.addEventListener()方法
EventTarget.addEventListener()方法将指定的监听器注册到EventTarget上,当该对象触发指定的事件时,指定的回调函数就会被执行。EventTarget可以是element对象,document对象或者任何其他支持事件的对象。例:

```<!--html文件中-->
<button id='mybutton'></button>
```


//脚本中
var mybutton=document.getElementById('mybutton');
mybutton.addEventListener('click',function(e){console.log('button clicked!');});

上例为button元素注册了click事件的监听器,并规定事件时触发控制台输出'button clicked'。

3.DOM事件模型

在讲解DOM事件模型前,再用一个例子作为引入。请看下面的html文件:

```<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>DOM Event Model</title>
<style>
div{position: absolute;}
#outer{
top: 100px;
left: 100px;
width: 600px;
height: 400px;
background-color: #aff;
}
#inner1,#inner2{
top: 50px;
width: 200px;
height: 300px;
background-color: #f9a;
}
#inner1{left: 50px;}
#inner2{left: 350px;}
#core{
left: 50px;
top: 50px;
width: 100px;
height: 150px;
background-color: #f50;
}
</style>
</head>
<body>
<div id='outer' onclick="console.log(this.id)">
<div id='inner1' onclick="console.log(this.id)"></div>
<div id='inner2' onclick="console.log(this.id)">
<div id='core' onclick="console.log(this.id)"></div>
</div>
</div>
</body>
</html>
```

这里为id分别为outer,inner1,inner2,core的4个元素定义了事件属性,元素被点击后将在控制台输出它的id。现在问题来了:
如果我点击core元素,控制台将会输出什么?
点击core元素时,由于core元素包含在inner2元素里,inner2元素同样被点击了;同理,inner2元素包含在outer元素里,那么outer元素也被点击了。这种情况下哪一个元素的click事件将会被触发,或者说三者都被触发?如果说三者都被触发,那么又是以怎样的顺序被触发?
我在火狐浏览器做了一次实验,控制台输出结果如下:

```core
inner2
outer
```

也就是说,三者的事件都被触发了,且是“由内向外”触发的。
下面我们再做一个有趣的实验:我们将上面的html文件再做一个小小的改动,将core元素的样式


left: 50px;

改为


left: -250px;

此时观察页面我们会发现,尽量core是inner2的子节点,但由于我们定义了“怪异”的样式,它跑到了inner1里面。现在我们再次用鼠标点击core,观察控制台的输出:

```core
inner2
outer
```

和刚才的结果一模一样!尽管表面上inner1似乎被点击了,但它的click事件并没有触发;反而是看似未被点击的inner2元素的click事件被触发了。仿佛core元素的click事件被触发后,click事件一层一层向上“传播”给了父节点。
为了解释刚才的实验结果,是时候开始讲解DOM事件模型了。
当一个事件发生时,事件会在DOM树中进行传播。传播分为两个阶段:
i.捕获阶段
在此阶段,事件从根结点(即document结点)开始向下传播,直到事件源所在元素。
ii.冒泡阶段
在此阶段,事件从事件源开始向上传播,直到根结点。
拿刚才的例子来说,事件传播的顺序为:
document捕获->html捕获->body捕获->outer捕获->inner2捕获->core捕获->core冒泡->inner2冒泡->outer冒泡->html冒泡->document冒泡
对于事件属性,默认在冒泡阶段触发事件。如果用addEventListener()方法注册监听器,则可以指定在捕获阶段还是冒泡阶段触发事件:如果最后一个参数为false(默认值),则在冒泡阶段触发事件;如果为true,则在捕获阶段触发事件。
一般来说,我们推荐采用addEventListener()方法来注册监听器,而尽量不用事件属性。因为事件属性不利于行为与结构的分离,使代码难以维护。

原文地址:https://segmentfault.com/a/1190000016748916

最新文章

  1. 修改Coney主题之侧边栏移位
  2. web项目中的跨域问题解决方法
  3. QQ空间直播秒开优化实践[读]
  4. Symmetry(对称轴存在问题)
  5. EA强大的画图工具---设计数据库表格
  6. js 获取mac地址
  7. Ice笔记-利用Ice::Application类简化Ice应用
  8. 用SCMD2.0.8.0汉化版制作OB地图简易教程
  9. &lt;转&gt; 30 个有关 Python 的小技巧
  10. java 学习资源
  11. Angularjs1.2版本与1.3版本中控制器的问题
  12. (转)Spring Bean Scope 有状态的Bean 无状态的Bean
  13. RabbitMQ安装以及java使用(一)
  14. pdf去水印
  15. C#编写的艺术字类方法
  16. obj-c编程07:异常处理
  17. idea工具的快捷方式
  18. Java复制、移动和删除文件
  19. JEECG 上传插件升级-标签
  20. python字符串类型

热门文章

  1. typescript学习笔记(三)---接口
  2. cmd 查看端口占用情况
  3. C# 基础之密封类
  4. Guard Duty (hard) Codeforces - 958E3 || uva 1411
  5. 转 Linux SendMail发送邮件失败诊断案例(四)
  6. pycharm 虚拟环境virtualenv迁移到别的机器 无法读取包的问题
  7. [已读]CSS禅意花园
  8. 编写可执行程序,其它程序调用,并返回数据,C#
  9. Java项目接入阿里云OSS存储
  10. 一个普通Java程序包含哪些线程??