浏览器中的JavaScript:文档对象模型与 DOM 操作

519 阅读5分钟

翻译:疯狂的技术宅 原文:www.valentinog.com/blog/dom/

JavaScript 并没有那么糟糕。作为运行在浏览器中的脚本语言,它对于网页操作非常有用。在本文中,我们将看到可以用哪些手段来修改 HTML 文档和交互。

什么是文档对象模型?

文档对象模型是在浏览器中一切的基础。但它究竟是什么呢?

当我们访问网页时,浏览器会计算出如何解释每个 HTML 元素。这样它就可以创建 HTML 文档的虚拟表示,并保存在内存中。 HTML 页面被转换为树状结构并且每个 HTML 元素都变成一个叶子结点,连接到父分支。看一下这个简单的 HTML 页面:

<!DOCTYPE html>
<html lang="en">
  <head>
		<title>A super simple title!</title>
  </head>
  <body>
  	<h1>A super simple web page!</h1>
  </body>
</html>

在这个结构的顶部有一个文档,也称为根元素,它包含另一个元素:html。 html 元素包含一个 head ,而 head 内又有一个 title。然后 body 中包含一个 h1。每个 HTML 元素都由特定类型(也称为接口)表示,并且可以包含文本或其他嵌套元素:

document (HTMLDocument)
  |
  | --> html (HTMLHtmlElement)
          |  
          | --> head (HtmlHeadElement)
          |       |
          |       | --> title (HtmlTitleElement)
          |                | --> text: "A super simple title!"
          |
          | --> body (HtmlBodyElement)
          |       |
          |       | --> h1 (HTMLHeadingElement)
          |              | --> text: "A super simple web page!"

每个HTML元素都来自 Element,但其中很大一部分都是专用的。你可以通过检查原型以查找元素所属的“种类”。例如,h1元素是 HTMLHeadingElement:

document.querySelector('h1').__proto__
// Output: HTMLHeadingElement

而 HTMLHeadingElement 又是 HTMLElement 的“后代”:

document.querySelector('h1').__proto__.__proto__
// Output: HTMLElement

这时(特别是初学者)可能会对 document 和 window 之间的区别产生一些混淆。让我们看看它们有什么不同!

window和document之间的区别

window 是指浏览器,而 document 是你当前正在操作的 HTML 页面,即当前文档。文档界面有许多实用功能,比如 querySelector(),一种用于选择给定页面内任何 HTML 元素的方法:

document.querySelector('h1');

window 表示当前窗口的浏览器,以下代码效果与上述相同:

window.document.querySelector('h1');

无论如何,以下语法更常见,你还会看到更多:

document.methodName();

DOM 操作

DOM中的每个 HTML 元素也都是“节点”,实际上我们可以像这样去检查节点类型:

document.querySelector('h1').nodeType;

上面的代码会返回 1,它是 Element 类型的节点的标识符。你还可以检查节点名称:

document.querySelector('h1').nodeName;
"H1"

上面的例子用大写的形式返回节点名称。需要理解的也是最重要的概念是,我们主要使用 DOM 中的两种类型的节点:

  • Element 类型的节点(HTML 元素)
  • Text 类型的节点(文本节点)

为了创建 Element 类型的新节点,本机 DOM API 为我们提供了 createelement 方法,你通常会这样调用:

var heading = document.createElement('h1');

为了创建文本,我们可以用 createTextNode

var text = document.createTextNode('Hello world');

通过在新的 HTML 元素中附加文本,可以将两个节点组合在一起。最后需要注意的是,我们还可以将标题元素附加到根文档:

var heading = document.createElement('h1');
var text = document.createTextNode('Hello world');
heading.appendChild(text);
document.body.appendChild(heading);

在浏览器中使用 JavaScript 时,你需要了解这三种方法。在技术圈中,我们将这些指令称为 DOM 操作

当以这种方式创建和操作元素时,我们谈论的是“命令式” DOM操作。现代前端库正在通过支持“声明”方法来解决这个问题。我们不是一步一步地去命令浏览器,而是声明我们需要什么 HTML 元素,而库可以处理剩下的部分。

DOM 操作和 jQuery

此时你可能会想:“我可以只使用jQuery吗?为什么要用 createElement?“ 我经常会被问到这些问题。

好吧,请注意 jQuery 正逐渐消失。 Bootstrap 5 将从依赖项中删除它,还有更多的库或框架正在删除它。这背后有一个十分正当的理由:原生 DOM API 已经非常完整且成熟到足以使 jQuery 过时

如果你想坚持用原生 JavaScript 实现简单的交互和操作。甚至可以创建自己的迷你框架来抽象出最常见的操作:创建元素、追加、创建文本等。

结论

文档对象模型是浏览器创建并保留在内存中的网页的虚拟副本。在创建、修改、删除 HTML 元素时,我们会碰到 “DOM 操作”。在过去即使对于更简单的任务,我们也要依赖于 jQuery,但今天本机 API 已经互相兼容并且足够成熟以使 jQuery 过时。

虽然 jQuery 不会很快的消失,但每个 JavaScript 程序员都必须知道该如何使用本机 API 去操作 DOM。这样做有很多理由,其他库会增加 JavaScript 程序的加载时间和大小,更不用说 DOM 操作在技术面试中出现的越来越多。

DOM 中可用的每 个HTML 元素都有一个暴露一定数量属性和方法的接口。如果对使用什么方法有疑问,可以参考 MDN上的优秀文档。

操作 DOM 最常用的方法是 document.createElement() 用于创建新的 HTML 元素,document.createTextNode() 用于在 DOM 内创建文本节点。需要注意的是 .appendChild() 用于将新的 HTML 元素或文本节点附加到现有元素。

虽然很好的了解本机 API 是很好的,但是现代前端库也提供了无可置疑的好处。尽管用“原生” JavaScript 去构建大型JavaScript 程序确实是可行的,但有时 Angular、React、Vue可以提供很多帮助。仅使用 JavaScript 来处理更简单的原型和中小型应用也是明智之举。

资源

如果你想了解更多关于文档对象模型的内容,那么 Aderinokun 还有另一篇好文章。非常详细,值得一读:文档对象模型究竟是什么

如果你想回到基础知识,请查看如何使用原生 JavaScript 生成表格 一文!在没有任何前端框架的帮助的情况下,你会发现实现它都需要什么。

欢迎关注前端公众号:前端先锋,获取更多前端干货。