使用 Javascript 操作 DOM - 如何选择节点(第 1 部分)👨🏼🔬🎯
最初,网站完全由 HTML 构成,只能显示文本(90 年代初,计算机显示器仅支持 16 种颜色)。浏览器下载 HTML 文档,进行渲染,最终将内容显示在用户屏幕上。文本无法更改,因此可以说,它是固定不变的。
但人们想要的不仅仅是显示枯燥的文字,所以他们开始创建交互式网站。1995年,Internet Explorer 发布,Javascript 也应运而生。这种令人兴奋的新脚本语言开始用于网页,但由于 UI 是使用 HTML 生成的,而 HTML 文件下载后无法更改,因此其提供的交互性非常有限(这种非常有限的交互性最终被称为DOM Level 0
或Legacy DOM
)。
出于能够在页面加载后更改 UI(在 HTML 文档中添加、删除、编辑或移动元素)的需求,DOM 的第一个标准化版本DOM
诞生于 1998 年,名为DOM Level 1
。更改(操作)DOM 突然打开了无限可能的大门。现在,我们可以创建可由用户自定义的应用程序,这些应用程序可以根据用户的输入做出反应,甚至无需刷新页面即可更新我们在屏幕上看到的数据(因此无需额外访问服务器)。我们可以在屏幕上拖动或移动元素,根据需要删除某些元素或添加新元素。
DOM 操作的一些具体示例如下:
- 点击按钮后更改其内容/颜色
- 将鼠标悬停在段落上时更改段落的内容
- 在我们检查某项已完成后,将其从“待办事项”列表中删除
- 在输入框中输入新项目并点击“添加”按钮后,将其添加到“待办事项”列表中
- 提交表单后导航到其他页面
DOM(文档对象模型)
The Document Object Model is a cross-platform and language-independent interface that treats an XML or HTML document as a tree structure wherein each node is an object representing a part of the document. The DOM represents a document with a logical tree.
简单来说,这意味着浏览器下载 HTML 文档后,会将其内容转换为称为的树状结构DOM (Document Object Model)
并将其存储在内存中。
重要提示:
DOM 并非编程语言,也不是 JavaScript 的一部分。它是 Web 浏览器内置的众多 Web API 之一,并且被设计为独立于任何语言(可以将 Web API 视为函数的集合)。除了 JavaScript 之外,还可以使用其他脚本语言构建 DOM 的实现。每个非空网页都有一个 DOM,即使没有使用任何 JavaScript 的网页也是如此。例如,如果您的页面仅显示文本,则无需修改 DOM。但如果您需要交互性,则可能需要使用 DOM(JavaScript 提供的一些交互性也可以使用 CSS 实现,但这是另一个话题)。
这听起来可能有点抽象,所以在进一步讨论之前,我们先看看这个 DOM 实际上是什么样子的。我们有一个非常简单的 HTML 代码片段:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Simple DOM example</title>
</head>
<body>
<section>
<h1>This is a header!</h1>
<h4>This is a smaller header!</h4>
<p>This is a paragraph!</p>
<img src="mountains.jpg" alt="Mountains covered in snow">
</section>
<section>
<h2>This is another header!</h2>
<h4>This is another small header!</h4>
<p>This is a paragraph!</p>
<p>This is another paragraph!</p>
</section>
<script src="index.js"></script>
</body>
</html>
下面我们可以看到DOM
上面的 HTML 代码是什么样的(如果您想尝试一下这种视觉表现,您可以使用这个Live DOM 查看器)。
HTML 被翻译成树状结构后,其结构如下。这棵树由 组成nodes
。一些节点代表 HTML 元素(HTML, HEAD, BODY, SECTION
例如 ),另一些节点代表文本(以 表示的文本)。所有节点类型#text
的完整列表可在此处找到。
根据节点在树中的位置,节点可以是:
根节点
这是树的顶级节点,在 HTML 中为HTML node
。
父节点
其中包含其他节点的节点。例如,BODY
是其内部所有节点的父节点。
子节点
直接位于另一个节点内的节点。在我们的示例中,H1 node
是 的子节点SECTION node
。
兄弟节点
这些是在 DOM 中位于同一级别的节点。H1, H4, P and IMG nodes
由于它们在 内位于同一级别,因此它们都是兄弟节点SECTION node
。
后代节点
这是可以在另一个节点内的任何位置找到的节点。H4
例如, 的后代节点BODY
。
操作 DOM
操作 DOM 意味着什么?这意味着我们可以利用控制 HTML 和页面样式的 API 来更改刚才看到的树中的节点。每个节点都有自己的属性和方法,可以使用 JavaScript 进行操作。
所有可用于操作和创建网页的属性、方法和事件都被组织成对象,我们称之为接口。DOM 接口有很多,但我们最常用的是Window
和Document
。完整的 DOM 接口列表可以在这里找到。
- Window - Window 接口表示一个包含 DOM 文档的窗口(浏览器中打开的窗口)。它在 DOM 层次结构中占据最高位置,因为它是
Document object
及其所有子元素的父元素。 - Document - Document 接口代表浏览器中加载的任何网页,并作为网页内容(即 DOM 树)的入口点。
1. 定位节点
为了与树中的任何节点进行交互,我们首先需要定位(选择)它。我们可以使用 DOM API 提供的多种方法之一来实现这一点(请注意,所有这些方法都是document
使用点符号在对象上调用的):
- getElementById()。我们利用其来选择 HTML 元素
id attribute
。它返回与指定 ID 匹配的元素,如果在文档中未找到匹配元素,则返回 null。
<div id="idSelector">I will be selected based on id.</div>
const elementById = document.getElementById("idSelector");
console.log(elementById );
// will return <div id="idSelector"></div>
- getElementsByClassName()。我们根据其 选择一个 HTML 元素
class attribute
。此方法返回一个包含 HTML 元素的实时 HTMLCollection(类似数组的列表)。如果未找到匹配的元素,则长度可能为 0。
<p class="classSelector">I am a paragraph.</p>
<p class="classSelector">I am too a paragraph.</p>
<p class="classSelector">I am, you guessed it, a paragraph.</p>
const elementByClassName = document.getElementsByClassName("classSelector");
console.log(elementByClassName);
// will return HTMLCollection {0: HTMLParagraphElement {...},
// 1: HTMLParagraphElement {...},
// 2: HTMLParagraphElement {...}}
// 0:<p class="classSelector"></p>
// 1:<p class="classSelector"></p>
// 2:<p class="classSelector"></p>
- getElementsByTagName()。我们根据 HTML 元素的 来定位它们
tag names
。此方法返回所有匹配 HTML 元素的实时 HTMLCollection,如果没有找到匹配项,则长度可能为 0。
<p>This is fun!</p>
<p>I like writing this article!</p>
<h4>The DOM is so interesting!</h4>
const elementByTagName = document.getElementsByTagName("p");
console.log(elementByTagName);
// will return HTMLCollection {0: HTMLParagraphElement {...},
// 1: HTMLParagraphElement {...}}
// 0:<p ></p>
// 1:<p ></p>
- getElementsByName()
name attribute
。此方法返回文档中给定元素的实时 NodeList 集合。如果未找到匹配项,则集合为空。
<input type="text" name="someInput" />
const elementsByName = document.getElementsByName("someInput");
console.log(elementsByName);
// will return NodeList {0: HTMLInputElement {...}}
// 0:<input type="text" name="someInput"></input>
- querySelector()。该方法返回文档中第一个与
specified selector
、 或匹配的元素group of selectors
。如果未找到匹配项,则返回 null。我们可以将任何所需的选择器作为参数(类、ID 等)。
<div class="divClass">This is just a div!</div>
<div id="thisIsAnId">This is another div!</div>
<p name="numberOnePara">This is just a paragraph!</p>
const querySelectionByClass = document.querySelector(".divClass");
console.log(querySelectionByClass);
// will return <div class="divClass"></div>
const querySelectionById = document.querySelector("#thisIsAnId");
console.log(querySelectionById);
// will return <div id="thisIsAnId"></div>
const querySelectorByName = document.querySelector("[name='numberOnePara']");
console.log(querySelectorByName);
// will return <p name="numberOnePara"></p>
- querySelectorAll()。此方法返回一个静态(非实时)的 NodeList,表示与指定选择器组匹配的文档元素列表。如果未找到匹配项,则 NodeList 将为空。
<p>Paragraph number 1!</p>
<p>Paragraph number 2!</p>
<p>Paragraph number 3!</p>
<p>Paragraph number 4!</p>
<p>Paragraph number 5!</p>
const queryAllParas = document.querySelectorAll("p");
console.log(queryAllParas);
// will return NodeList {0: HTMLParagraphElement {...},
// 1: HTMLParagraphElement {...},
// 2: HTMLParagraphElement {...},
// 3: HTMLParagraphElement {...},
// 4: HTMLParagraphElement {...}}
// 0:<p ></p>
// 1:<p ></p>
// 2:<p ></p>
// 3:<p ></p>
// 4:<p ></p>
词汇表
HTML 集合- 简单来说,HTML 集合是一个类似数组的对象,用于保存从文档中提取的 HTML 元素。HTML 集合只能包含Element Nodes
。NodeList - 它是
节点的集合。它类似于 HTML 集合,但它可以包含所有类型的节点(Element, Text and Attribute
),而不仅仅是元素节点。
实时 HTML 集合- 当 DOM 更新时,集合也会更新。
静态 HTML 集合- 如果 DOM 更新,则更改不会反映在集合中。
实时 NodeList - 当 DOM 更新时,集合也会更新。
静态 NodeList - 如果 DOM 更新,则更改不会反映在集合中。
资源参考:
标题图片来源:Unsplash上的 Jackson So/@jacksonsophat
文章来源:https://dev.to/arikaturika/manipulate-the-dom-using-javascript-how-to-select-nodes-part-1-38j