在本单元中,你将学习如何使用 JavaScript 构建交互式网站。
本单元的目标是了解 JavaScript 如何为网站添加交互体验。
完成本单元后,你将能够:
- 为网站添加 JavaScript 以实现交互功能
- 描述什么是 DOM
- 解释什么是 DOM 事件
- 使用 HTML 创建表单,并用 JavaScript 对其进行验证
JavaScript and HTML
HTML 使用页面元素作为构建模块来定义网页的结构。然而,仅靠 HTML 并不能实现网页的交互功能,这正是 JavaScript 发挥作用的地方。
下面我们看到一张便签纸,上面画着一个典型的小火柴人。我们可以把它看作 HTML,其中的头部、身体和四肢就像网页上的元素:

在网页开发中,CSS 为 HTML 的结构添加样式。如下图所示,小火柴人现在穿上了一套漂亮的礼服:

如果说 HTML 和 CSS 分别提供了网页的"结构"和"样式",那么 JavaScript 则赋予了网页"交互性",让小火柴人动起来。下面,小火柴人开始上下摆动,这就是 JavaScript 的功劳:
网页开发者使用 JavaScript 让网页变得动态且具有交互性。这种强大的脚本语言通过一个专属的 HTML 元素来嵌入页面:<script>
元素。你可以把 <script>
元素看作 HTML 连接 JavaScript 的"门户"。本课将深入讲解 <script>
元素在网页中能发挥什么作用,以及在 HTML 文件中插入 JavaScript 的最佳实践。
script标签
<script>
元素允许你在 HTML 文件中添加 JavaScript 代码。下面的例子展示了如何使用 <script>
元素嵌入合法的 JavaScript 代码:
html
<h1>This is an embedded JS example</h1>
<script>
function Hello() {
alert('Hello World');
}
</script>
说实话,没有 <script>
标签,网站将变得无法点击,甚至有些无趣。
<script>
元素和大多数 HTML 元素一样,有一个开始和结束的尖括号(标签)。结束标签标志着 <script>
元素中内容的结束。就像我们用 <style>
标签嵌入 CSS 代码一样,你可以使用 <script>
标签嵌入合法的 JavaScript 代码。
例如:
html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class = "container">
<img src = "normal.png" id= "myImage">
<p onclick="blooming()">Codecademy</p>
</section>
<!-- Paste your code in the script element below: -->
<script>
function blooming() {
var image = document.getElementById('myImage');
if (image.src.match("normal")) {
image.src = "flower.png";
} else {
image.src = "normal.png";
}
}
</script>
</body>
</html>
src属性
既然你已经知道如何在 <script>
元素中嵌入代码,现在我们来说说"链接"代码。链接代码更受欢迎,是因为一个编程概念:关注点分离(Separation of Concerns,简称 SoC)。与其把所有混乱的代码都写在一个文件里,Web 开发者更倾向于将代码拆分到不同的文件中,这样每一部分的"职责"就更清晰,也更方便在需要更改时进行维护。
在本练习中,我们不会在 HTML 文件里写 JavaScript,而是会把它写进自己的文件中,然后通过文件路径来引用这段代码。我们会用到一个你可能已经熟悉的属性:src
属性!
如果你觉得这个属性眼熟,那是因为你可能已经用 <img>
和 <link>
元素链接过外部文件了。这个属性的用法是一样的,只不过这次它的值指定的是脚本文件的位置。
如果脚本文件和 HTML 文件在同一个项目文件夹中,src
的值就会是一个相对路径名。下面是一个为 JavaScript 文件提供相对路径的例子:
html
<script src="./exampleScript.js"></script>
上面的 <script>
标签会去查找一个名为 exampleScript.js
的文件,该文件应当和 index.html
文件位于同一文件夹或目录中。
如果你需要引用托管在外部(如 CDN)上的 JavaScript 文件,你也可以将 src
设置为该文件的完整链接地址。
script是如何加载的?
快速回顾一下:<script>
元素允许 HTML 文件加载并执行 JavaScript。JavaScript 可以直接写在 <script>
标签内部,也可以通过引用外部文件来加载脚本。在深入了解之前,我们先花点时间了解一下浏览器是如何将 HTML 文件解析为网页的,这会帮助我们明白该把 <script>
标签放在哪里。
浏览器内置了 HTML 解析器,用来帮助浏览器按照规则渲染网页中的各个元素。HTML 文件中的元素(包括 <script>
元素)默认是按照它们在 HTML 文件中出现的顺序 进行解析的。当解析器遇到一个 <script>
元素时,它会先加载并执行该脚本的内容,然后才继续解析 HTML 的其余部分。
这里有两个重点要注意:
- HTML 解析器在加载并执行
<script>
元素之前,不会处理下一个 HTML 元素,这会造成网页加载的延迟,从而带来不好的用户体验。 - 脚本是按顺序加载的,所以如果某个脚本依赖于另一个脚本,那么它们在 HTML 中的顺序也必须正确。
defer属性
当 HTML 解析器遇到一个 <script>
元素时,它会暂停解析 HTML,去加载该脚本的内容。脚本加载完成后,JavaScript 代码会立即执行,然后 HTML 解析器才会继续处理接下来的内容。这种行为可能导致网页加载速度变慢。
为了解决这个问题,HTML4 引入了 <script>
元素的两个新属性:defer
和 async
,它们可以根据不同的场景来优化网站的加载体验,减少用户等待时间。
defer
属性的作用是:在 HTML 文件完全解析完成之后再执行脚本 。当 HTML 解析器遇到带有 defer
属性的 <script>
元素时,它会开始加载脚本文件,但不会立刻执行,而是等到整个 HTML 都解析完毕后再执行该脚本。
下面是一个使用 defer
属性的例子:
css
<script src="example.js" defer></script>
当脚本中包含需要与 DOM 交互的功能时,使用 defer
是非常合适的。这样可以确保整个 HTML 文件已经解析完成,脚本执行时 DOM 是完整可用的。
async属性
async
属性可以异步加载并执行脚本 ,与网页的其他部分同时进行。也就是说,与 defer
属性类似,HTML 解析器在加载脚本的同时还会继续解析 HTML 页面,不会暂停等待脚本加载完成。
但与 defer
不同的是 ,使用 async
属性时,脚本在下载完成后就会立刻执行 ,不等 HTML 页面完全解析完成。
下面是一个使用 async
属性的例子:
html
<script src="example.js" async></script>
async什么时候用?
async
非常适用于不依赖其他脚本,也不需要等待 DOM 加载完成的脚本,比如第三方广告、数据统计工具(如 Google Analytics)等。
如果脚本的执行时机无所谓,并且它是独立的、不影响页面主功能,那么使用 async
是最合适的方式,可以有效优化网页加载速度。
总结:
-
HTML 构建网页的骨架 ,但 JavaScript 引入了交互性。
-
<script>
元素有开始标签和结束标签。你可以在这两个标签之间嵌入 JavaScript 代码。 -
如果要链接外部的 JavaScript 文件,可以在
<script>
标签的开始标签中使用src
属性。 -
默认情况下 ,浏览器的 HTML 解析器在遇到
<script>
标签时,会立即加载并执行其中的脚本,然后才继续解析页面中剩余的元素。 -
使用
defer
属性,可以确保整个 HTML 文件解析完成后再执行脚本。 -
使用
async
属性,浏览器在下载脚本的同时会继续解析 HTML 页面,一旦脚本下载完成就立即执行,而不是等待页面解析完。 -
旧的做法是将
<script>
标签放在</body>
标签之前,以防止脚本阻塞页面加载。现在的推荐做法 是将<script>
标签放在<head>
中,并结合使用defer
或async
属性。
dom
什么是dom
dom = document object model
dom是浏览器对网页的内部表示,每个页面都依赖于dom来准确描述页面上的内容,以及这些内容与其他内容之间的关系。
web page = document
网页简称为文档,文档一词实际上指的是任何构建信息的方式,书籍、文章、论文等等。但从文档开发的角度来看,文档是网页的另一种说法,因此,dom是网页或文档中所有内容的模型。
网页上的内容就是对象,至少dom是这么称呼它们的。你可能听说过节点或者元素,它们用来描述网页上的内容,这些都是对象的类型,但这些对象到底是什么呢?
网页上最明显的东西就是内容,每个页面都有文字内容,还包括图片、视频、按钮等,所有这些都被视为对象。你可能也听说过这些东西被称为元素,它是一种特定的对象。
另一种东西是结构元素,比如div容器,你可能真的能看到网页上所有的结构对象,也可能看不到,但它们是组织内容所必需的。
剩下的东西主要是属性,每个元素都具有属性,例如html元素可以有类、样式、大小等。所有这些属性都是文档对象模型中的对象,但它们不是像内容或者结构这样的元素。
model:某种东西的表示,它可以帮助我们理解某种东西是如何组合在一起的。你能想象到的任何东西都有模型,因为复杂的东西需要某种方式来被普遍理解、分析和使用。
dom是网页的模型,是一种对文档中的对象进行建模的方法。或者更简单的说,dom代表网页上的元素和属性。
dom是一种树形数据结构,这意味着每个对象都在另一个对象下有层次。一个对象可以有多个子对象,但只能有一个父对象。当我们讨论父对象和子对象时,我们指的是对象之间的关系。
父对象拥有其子对象列表,如果从这棵树上移除任何对象,它的所有子对象,子对象的子对象都会被移除


浏览器通过实现 DOM,使得 JavaScript 可以以有组织的方式访问、修改和更新 HTML 网页的结构。
因此,我们可以把 DOM 看作 HTML 网页与脚本语言之间的桥梁。

dom作为树形结构
树状建模在许多领域中都有应用,包括进化科学和数据分析。也许你已经熟悉"家谱"这一概念:它通过图表来展示某个家族中后代之间的亲属关系。
DOM 树的逻辑与家谱图类似。家谱由家庭成员及其与家族姓氏的关系构成。在计算机科学中,我们会将每个家庭成员称为一个"节点"。
我们将"节点"定义为树状结构中的交叉点,每个节点都包含数据。
在 DOM 树中,最顶层的节点被称为"根节点"(root node),它代表整个 HTML 文档。根节点的后代是文档中的 HTML 标签,从 <html>
标签开始,接着是 <head>
和 <body>
标签,依此类推。

父节点(parent node) :指的是某个节点的直接上级节点,也就是它的祖先之一。
子节点(child node) :指的是某个节点的直接下级节点,其上级被称为父节点。
了解这些术语有助于你理解并讨论 DOM 这种树状结构。事实上,当我们讨论 HTML 代码的嵌套结构时,也会使用这些术语。程序员通常将嵌套在其他元素内部的元素称为"子元素",而包含它们的元素称为"父元素"。
dom中的节点和元素
如前所述,节点就相当于家谱中的每一个家庭成员。节点是树状结构中的一个交叉点,同时也包含数据。
在 DOM 树中存在多种类型的节点对象。在我们的示意图中,带有尖角矩形的表示元素节点(Element nodes) ,而带有圆角矩形的表示文本节点(Text nodes) ,因为它们代表的是 HTML 段落元素中的文字内容。
在修改网页时,脚本通常主要与 DOM 中的元素节点 交互,有时也会操作文本节点。

元素节点的属性
DOM 中的元素节点用于模拟 HTML 文档中的各个元素。
就像 HTML 页面中的元素一样,DOM 允许我们访问节点的各种属性,比如它的 class
、id
和行内样式(inline style)。
在右侧的示意图中,我们高亮显示了 HTML 文档中一个 id
为 'bio'
的段落元素。如果我们在脚本中访问这个元素节点,DOM 就可以让我们修改这些属性,或者直接读取它们的值以供代码使用。

总结
让我们回顾一下你目前学到的内容:
- DOM 是网页的结构化模型,它允许脚本语言访问该页面。
- DOM 的组织系统模仿了 HTML 文档的嵌套结构。
- 被嵌套在某个元素中的元素称为该元素的子元素 ,而包含它们的元素则被称为它们的父元素。
- DOM 还允许访问 HTML 元素的各种属性,比如
style
、id
等。
通过这些知识,你就可以开始运用脚本语言的强大功能来创建 、更新 和维护网页啦!

修改元素
在脚本中使用 DOM 访问某个 HTML 元素时,无论是一个 <li>
元素,还是整个 <body>
元素,你都可以访问该元素的所有属性。
这意味着你可以修改该元素的内容、属性以及其他特性,比如更改 <p>
元素中的文字,或为 <div>
元素设置新的背景颜色。例如,.innerHTML
属性可以让你访问或设置一个元素的内容。
来看一个例子,我们将 <body>
元素的内容重新赋值为文本 'The cat loves the dog.'
:
javascript
document.body.innerHTML = 'The cat loves the dog.';
.innerHTML
属性也可以插入任何合法的 HTML 元素。下面这个例子将 <body>
元素的内容替换为一个 <h2>
元素,也就是给 <body>
添加了一个子元素:
js
document.body.innerHTML = '<h2>This is a heading</h2>';
选择并修改元素
在上一个练习中,我们使用 document
关键字访问了 <body>
元素!
那么,如果我们想选择 <body>
之外的某个特定元素该怎么办呢?DOM 接口允许我们使用 CSS 选择器 来访问特定的元素。
CSS 选择器通常用于定义哪些元素应用某组 CSS 样式,但我们也可以使用这些相同的选择器,通过 JavaScript 来访问 DOM 元素!选择器可以是标签名、类名,或 ID。
.querySelector()
方法允许我们将一个 CSS 选择器作为字符串传入,并返回匹配该选择器的第一个元素 。下面的代码将返回文档中的第一个段落元素:
javascript
document.querySelector('p');
除了 .querySelector()
之外,JavaScript 还提供了更多有针对性的方法,允许我们根据元素的类名、ID 或标签名来选择元素。
例如,如果你想通过元素的 ID 直接访问它,可以使用命名直观的 .getElementById()
方法:
js
document.getElementById('bio').innerHTML = 'The description';
在这个例子中,我们选中了 ID 为 'bio'
的元素,并将它的 .innerHTML
设置为 'The description'
。注意,这里的 ID 是以字符串形式传入的(用引号括起来)。
此外,还有 .getElementsByClassName()
和 .getElementsByTagName()
方法,这两个方法返回的是一个元素数组,而不是单个元素。你可以使用中括号([])来访问数组中的某个具体元素:
js
// 将第一个 class 为 student 的元素内容设置为 'Not yet registered'
document.getElementsByClassName('student')[0].innerHTML = 'Not yet registered';
// 将第二个 <li> 标签的内容设置为 'Cedric Diggory'
document.getElementsByTagName('li')[1].innerHTML = 'Cedric Diggory';
在上面的示例中,我们修改了第一个类名为 'student'
的元素和第二个 <li>
元素的 HTML 内容。
给元素设置样式
另一种修改元素的方法是更改它的 CSS 样式。DOM 元素的 .style
属性提供了对该 HTML 标签内联样式的访问。
语法遵循 element.style.property
的格式,其中 property
表示一个 CSS 属性。例如,以下代码选择了第一个类名为 blue
的元素,并将其 background-color
设置为蓝色:
js
let blueElement = document.querySelector('.blue');
blueElement.style.backgroundColor = 'blue';
与 CSS 不同的是,DOM 中的 .style
属性不使用连字符 (如 background-color
),而是使用驼峰式命名法(camelCase),即 backgroundColor
。你可以参考 W3C 的 HTML DOM Style 对象文档,了解各种 CSS 属性在 JavaScript 中是如何转换的。
下面这种链式写法也是可以的:
css
document.querySelector('.blue').style.fontFamily = 'Roboto';
遍历 DOM
让我们来回顾一下 DOM 层级结构中的父子关系:
- 父节点(parent node) 是某个节点的直接祖先;
- 子节点(child node) 是某个节点的直接后代,该节点称为该子节点的父节点。
这种关系遵循 HTML 代码的嵌套结构:如果某个元素嵌套在另一个 HTML 元素中,那么它就是该元素的子元素。
每个元素都有 .parentNode
和 .children
属性:
.parentNode
返回指定元素在 DOM 层级中的父节点。注意:document
元素是根节点,因此它的.parentNode
返回null
。.children
返回该元素的所有子节点组成的 类数组对象 (不是标准数组)。如果该元素没有任何子节点,则返回null
。
来看下面这段 HTML:
html
<ul id='groceries'>
<li id='must-have'>Toilet Paper</li>
<li>Apples</li>
<li>Chocolate</li>
<li>Dumplings</li>
</ul>
在上面的代码中,有一个 ID 为 groceries
的 <ul>
元素,内部包含了四个 <li>
元素。
对应的 JavaScript 代码如下:
js
let parentElement = document.getElementById('must-have').parentNode;
// 返回 <ul> 元素
let childElements = document.getElementById('groceries').children;
// 返回一个包含四个 <li> 元素的"类数组"
解释:
parentElement
获取的是 ID 为must-have
的<li>
元素的父节点,也就是 ID 为groceries
的<ul>
元素;childElements
获取的是 ID 为groceries
的<ul>
元素的子节点们,即四个<li>
元素。
创建并插入元素
就像 DOM 允许脚本修改已有元素一样,它也允许创建新的元素。
.createElement()
方法可以根据传入的标签名参数创建一个新的元素。不过,它不会自动将这个元素添加到文档中。它只会创建一个没有内部 HTML 内容的空元素。
js
let paragraph = document.createElement('p');
在上面的示例代码中,.createElement()
方法传入 'p'
作为参数,这将创建一个空的 <p>
元素,并将其赋值给变量 paragraph
。
我们可以像以前修改已有元素一样,为新创建的元素设置属性:
js
paragraph.id = 'info';
paragraph.innerHTML = 'The text inside the paragraph';
上面的代码中,我们使用 .id
属性将 'info'
设置为这个元素的 ID,并使用 .innerHTML
属性设置 <p>
元素的内容为 'The text inside the paragraph'
。
为了将新创建的元素添加到网页中,必须将其指定为一个已存在的 DOM 元素的子元素,我们称这个已有元素为"父元素"。这个过程称为"追加"。.appendChild()
方法会将子元素添加为父元素的最后一个子节点。下面的代码将存储在 paragraph
变量中的 <p>
元素追加到 document.body
上:
js
document.body.appendChild(paragraph);
.appendChild()
方法不会替换父元素(在这个例子中是 body
)中的内容,而是将新元素追加为该父元素的最后一个子元素。
移除元素
除了可以修改或从头创建一个元素,DOM 还允许我们移除某个元素。.removeChild()
方法可以从父元素中移除指定的子元素。
javascript
let paragraph = document.querySelector('p');
document.body.removeChild(paragraph);
在上面的示例代码中,.querySelector()
方法返回文档中的第一个 <p>
元素。然后,这个 paragraph
元素作为参数传递给其父元素(document.body
)调用的 .removeChild()
方法,从而将这个段落从文档的 <body>
中移除。
如果你只是想隐藏一个元素,而不是完全删除它,可以使用 .hidden
属性。通过将这个属性设置为 true
或 false
,可以控制元素的显示与隐藏:
js
document.getElementById('sign').hidden = true;
上面的代码并没有从 DOM 中移除 ID 为 'sign'
的元素,而是将它隐藏了起来。
添加点击交互
你可以通过为 DOM 元素指定一个函数,在特定事件发生时运行,从而为它添加交互功能。事件可以包括点击、鼠标悬停等操作。我们将在后面的"使用 JavaScript 操作 DOM 事件"课程中更深入地了解事件的使用。现在,我们先来看一下在点击事件发生时如何修改一个元素。
.onclick
属性允许你为元素指定一个在点击事件发生时执行的函数:
js
let element = document.querySelector('button');
element.onclick = function() {
element.style.backgroundColor = 'blue';
};
你也可以将 .onclick
属性赋值为一个已命名的函数:
javascript
let element = document.querySelector('button');
function turnBlue() {
element.style.backgroundColor = 'blue';
}
element.onclick = turnBlue;
在上面的示例代码中,当 <button>
元素检测到点击事件时,其背景颜色会变成 'blue'
。
总结
在本节课中,你通过 JavaScript 的 DOM(文档对象模型)接口操作了网页的结构。
我们来回顾一下学到的内容:
document
关键字可以让你访问 JavaScript 中 DOM 的根节点。- DOM 接口允许你使用
.querySelector()
方法,通过 CSS 选择器选中一个特定的元素。 - 你可以使用
.getElementById()
方法直接通过元素的 ID 获取该元素,该方法返回一个单独的元素。 - 你可以使用
.getElementsByClassName()
和.getElementsByTagName()
方法获取一个元素的数组,然后通过数组下标来引用其中的某个元素。 .innerHTML
和.style
属性分别可以修改元素的内容和样式。- 你可以使用
.createElement()
、.appendChild()
和.removeChild()
方法分别来创建、添加和移除元素。 .onclick
属性可以为 DOM 元素添加点击事件,实现交互功能。.children
属性返回一个元素的所有子元素列表,而.parentNode
属性则返回该元素向上查找的最近的父节点。
这些知识点可以帮助你用 JavaScript 动态地操作网页内容和结构,打造更加丰富的用户体验。
js的dom事件
什么是事件
当你刷新邮箱、双击帖子,或滚动浏览新闻推送时------浏览器里就会发生一些很酷的事情。这些操作就叫做"事件"!
网页上的事件是指用户的交互行为或浏览器的动作,你可以通过编程方式来响应这些事件,从而触发相应的功能。下面是一些常见事件的例子:
- 鼠标点击按钮
- 网页文件在浏览器中加载完成
- 用户在图片上向右滑动
当用户执行上述任意操作时,他们就"触发"了一个事件。比如,"点击按钮时触发了一个点击事件"。能够响应这些事件的网页,才是有交互性和动态体验的网页。
触发事件
在文档对象模型(DOM)中的某个特定元素上触发特定事件后,可以创建一个**事件处理函数(event handler function)**来作为响应执行操作。在本课中,我们将学习这些事件处理函数是如何在事件触发后修改和更新 DOM 元素的。
我们可以将事件的触发类比为一个更熟悉的场景:一只听到铃声就会开始吃东西的狗!(这被称为巴甫洛夫条件反射。)
如图所示,铃声的响起就像是 JavaScript 中事件的触发。而狗狗被训练去响应铃声,这就好比是在设置一个事件监听器(event listener) 。当狗狗听到铃声后,它就会走过来吃食物!这个反应就类似于事件处理函数的执行,它会运行代码,比如在网页上改变元素的颜色、文本,等等。
大多数浏览器中的事件都会悄悄发生------因为没有绑定事件处理函数,这些事件就不会被"察觉"或响应。而事件处理函数正是使用 JavaScript 创建交互式网站的关键所在。
注册事件处理程序
现在是时候深入了解如何使用事件处理函数来创建交互效果了。
使用 .addEventListener()
方法,我们可以让一个 DOM 元素监听某个特定事件 ,并在该事件被检测到时执行一段代码。这个监听事件的 DOM 元素被称为事件目标(event target) ,而当事件发生时运行的那段代码被称为事件处理函数(event handler) 。
我们来看下面这段代码:
js
let eventTarget = document.getElementById('targetElement');
eventTarget.addEventListener('click', function() {
// 当 eventTarget 元素上发生点击事件时,这段代码会被执行
});
我们来逐步解析一下这段代码:
- 我们使用
document.getElementById('targetElement')
从 DOM 中选中了我们的事件目标。 - 然后在这个
eventTarget
元素上使用了.addEventListener()
方法。 .addEventListener()
方法接受两个参数:一个是表示事件名称的字符串,另一个是事件处理函数。我们将在后面的课程中了解可以使用哪些不同的事件名称。- 在这个例子中,我们使用了
'click'
事件,也就是当用户点击eventTarget
元素时会触发的事件。 - 当监听到
'click'
事件时,事件处理函数中的代码块就会被执行。
虽然在 .addEventListener()
方法中直接使用**匿名函数(anonymous function)是可以的,但最佳实践是使用具名函数(named function)**来作为事件处理函数。这样你的代码会更加有条理、更易复用,即使代码变得复杂也更容易维护。
来看使用具名函数的语法示例:
javascript
function eventHandlerFunction() {
// 当点击事件发生时,这段代码将被执行
}
eventTarget.addEventListener('click', eventHandlerFunction);
在这个例子中,我们将具名函数 eventHandlerFunction
作为 .addEventListener()
方法的第二个参数传入,而不是在方法内部定义一个匿名函数!
addEventListener('click', eventHandlerFunction)和onclick(eventHandlerFunction)有什么区别
- 是否可以绑定多个事件处理函数
onclick
只能绑定一个 函数。后绑定的会覆盖掉前面的:
js
eventTarget.onclick = function () { console.log('第一次'); };
eventTarget.onclick = function () { console.log('第二次'); }; // 覆盖了上面的
// 点击时只会打印「第二次」
addEventListener
可以绑定多个函数,互不影响:
js
eventTarget.addEventListener('click', function () { console.log('第一次'); });
eventTarget.addEventListener('click', function () { console.log('第二次'); });
// 点击时会依次打印「第一次」「第二次」
- 支持的时间类型和高级功能
addEventListener
支持更多功能,比如监听事件捕获阶段(第三个参数),或指定只触发一次({ once: true }
)等高级配置。
javascript
eventTarget.addEventListener('click', handler, { once: true });
onclick
只支持冒泡阶段,不能配置这些高级功能。
- 移除事件监听的方式不同
addEventListener
绑定后可以用 removeEventListener
精确移除:
javascript
function handleClick() {
console.log('clicked');
}
eventTarget.addEventListener('click', handleClick);
eventTarget.removeEventListener('click', handleClick);
onclick
想"移除"只能设置为 null
或重新赋值:
javascript
eventTarget.onclick = null;
添加事件处理程序
我们已经学习了如何使用 .addEventListener()
方法来注册事件处理程序,但其实还有另一种方法!
事件处理程序也可以通过在 DOM 元素(事件目标)上设置 .onevent
属性的方式来注册。注册特定事件的模式是:给一个元素添加 .on
加上小写的事件类型名称 。
例如,如果我们想要注册一个点击事件(click event),可以这样写:
js
eventTarget.onclick = eventHandlerFunction;
在这个例子中,我们给 DOM 元素 eventTarget
设置了 .onclick
属性,并将其值设置为事件处理函数 eventHandlerFunction
。
需要注意的是:.onevent
属性和 .addEventListener()
方法都可以注册事件监听器。但是:
- 使用
.onevent
(比如.onclick
)的方式只能为一个事件目标附加一个事件处理函数,后添加的会覆盖前一个; - 而使用
.addEventListener()
方法,可以附加多个事件处理函数,它们都会被依次调用。
在后续的练习中,我们会主要使用 .addEventListener()
的语法,不过我们也想介绍 .onevent
的用法,因为这两种方式在实际开发中都非常常见。
移除事件处理程序
.removeEventListener()
方法用于撤销 .addEventListener()
方法的效果。这个方法可以让事件目标不再"监听"某个事件的触发,当事件监听不再需要时,就可以使用它。
.removeEventListener()
方法也需要两个参数:
- 事件类型(以字符串形式表示)
- 要移除的事件处理函数
来看一个使用 .removeEventListener()
方法移除点击事件的语法示例:
js
eventTarget.removeEventListener('click', eventHandlerFunction);
由于一个特定事件可能绑定了多个事件处理函数,.removeEventListener()
必须提供完全相同的事件类型名称 和你想移除的事件处理函数的函数名,才能成功移除。
⚠️ 注意:如果你在 .addEventListener()
中使用的是匿名函数 ,那么这个事件监听器是无法被移除的。
事件对象的属性
JavaScript 会将事件保存为 事件对象(Event object) ,其中包含与该事件相关的数据和功能,这些内容以属性和方法的形式存在。
当某个事件被触发时,事件对象可以作为一个 参数 传递给事件处理函数。
js
function eventHandlerFunction(event){
console.log(event.timeStamp);
}
eventTarget.addEventListener('click', eventHandlerFunction);
在上面的示例中,当 eventTarget
上触发 'click'
事件时,eventHandlerFunction
函数会接收一个名为 event
的参数。这个参数就是一个 事件对象 ,**它包含了关于 'click'
事件的相关信息。 ** 接着,我们通过访问事件对象的 .timeStamp
属性,打印出从文档加载完成到该事件被触发所经过的时间(以毫秒为单位)。
事件对象中有一些预定义的属性,你可以调用它们来查看与事件有关的信息,例如:
.target
属性:引用事件被注册的那个元素;.type
属性:获取事件的名称(比如'click'
);.timeStamp
属性:获取从文档加载完成到事件触发之间经过的毫秒数。
隐藏注册的元素:
js
event.target.style.display = 'none';
事件类型
除了点击(click)事件之外,浏览器中还有各种各样的 DOM 事件可以被触发!
了解这一点很重要:大多数 DOM 中的事件都会在没有被察觉的情况下发生,这是因为没有为它们绑定事件处理器。
同样也要注意,有些注册的事件不依赖用户的交互 也能被触发。
例如,load
事件会在网站的文件完全加载到浏览器之后自动触发。
浏览器还可以在没有用户操作的情况下触发很多其他事件 ------ 你可以在 MDN 的 Events Reference 页面 上查看这些事件的列表。
当然,很多事件还是需要用户与 DOM 进行交互后才会触发。
你已经熟悉的一个用户交互事件就是 click
事件 ------ 当用户在 DOM 元素上按下并释放鼠标按钮 时,click
事件就会被触发。
鼠标事件
当你在网站上使用鼠标设备时,会触发各种鼠标事件。你已经见过 click
和 wheel
事件,但实际上,还有更多鼠标相关的事件可以探索!
-
mousedown
事件 会在用户按下鼠标按钮 时触发。这和
click
事件不同,因为mousedown
不需要等到鼠标按钮释放就会触发。 -
mouseup
事件 会在用户松开鼠标按钮 时触发。它和
click
或mousedown
都不同,因为mouseup
不依赖鼠标是否按下才能触发。 -
mouseover
事件 会在鼠标进入某个元素的内容区域时触发。 -
mouseout
事件 会在鼠标离开某个元素时触发
js
function increaseWidth() {
itemOne.style.width = '401px';
}
itemOne.addEventListener('mouseover', increaseWidth);
function changeBackground(){
itemTwo.style.backgroundColor = 'blue';
}
itemTwo.addEventListener('mouseup', changeBackground);
function changeText(){
itemThree.innerHTML = 'The mouse has left the element';
}
itemThree.addEventListener('mouseout', changeText);
function showItem(){
itemFive.style.display = 'block';
}
itemFour.addEventListener('mousedown', showItem);
键盘事件
除了鼠标事件,键盘事件 也是非常常见的一类事件!
键盘事件是由用户在浏览器中与键盘键交互时触发的。
-
keydown
事件 会在用户按下某个键 时触发。
(Key Down 事件图示) -
keyup
事件 会在用户松开某个键 时触发。
(Key Up 事件图示) -
keypress
事件 会在用户按下并松开一个键 时触发。它不同于
keydown
和keyup
组合起来的效果,因为keypress
是一个完整的事件。
键盘事件拥有其独特的事件对象属性,比如 .key
属性,它用于存储用户按下的键的值。
你可以在事件处理函数中编程,让它:
- 对某个特定键作出响应,或者
- 对任意键盘操作都作出响应。
js
let ball = document.getElementById('float-circle');
// Write your code below
function up(){
ball.style.bottom = '250px';
}
function down(){
ball.style.bottom = '50px';
}
document.addEventListener('keydown', up);
document.addEventListener('keyup', down);
document
代表整个文档对象模型(DOM)------将 document
作为事件目标,意味着你可以在 DOM 的任何地方触发事件。
你可以使用 .addEventListener()
方法或 .on[event]
属性来为事件类型 keydown
注册你的事件处理函数。
总结
我们来回顾一下你学到的内容:
- 你可以使用
.addEventListener()
方法将事件注册到 DOM 元素上。 .addEventListener()
方法接受两个参数:事件类型 和 事件处理函数。- 当事件在事件目标上被触发时,注册的事件处理函数会被执行。
- 事件处理函数也可以作为事件目标的
.onevent
属性值进行注册。 - 事件对象的属性(如
.target
、.type
和.timeStamp
)可以提供关于事件的信息。 .addEventListener()
方法可以为同一个事件添加多个事件处理函数。.removeEventListener()
方法可以停止特定的事件处理器监听特定的事件。