在 JavaScript 中,HTML DOM (Document Object Model) 是用于访问和操作 HTML 文档的标准编程接口。它将 HTML 文档结构化为树状形式,使得开发者可以轻松地通过 JavaScript 来改变文档的内容、结构和样式。

HTML DOM 是关于如何获取、更改、添加或删除 HTML 元素的标准。

DOM 节点

DOM 将 HTML 文档视为树结构,其中每个部分都是一个节点(node),节点类型包括:

  • 文档节点:代表整个 HTML 文档(document)。
  • 元素节点:代表文档中的 HTML 元素(如 <p><div>)。
  • 属性节点:代表元素的属性(如 class="myClass")。
  • 文本节点:代表存放在元素和属性节点中的文本。
  • 注释节点:代表 HTML 中的注释(<!-- Comment -->)。

需要注意 Element Node 不含有 Text,具体参考:JS Element Node & Node Values

节点属性

  • nodeName 属性,只读,值为 tag name。
  • nodeValue 属性,element node = null,text node = text itself。
  • nodeType 属性,只读,节点类型,几种重要的 nodeType 数值如下:
NodeTypeExample
ELEMENT_NODE1<h1 class="heading">W3Schools</h1>
ATTRIBUTE_NODE2class = “heading” (deprecated)
TEXT_NODE3W3Schools
COMMENT_NODE8<!-- This is a comment -->
DOCUMENT_NODE9The HTML document itself (the parent of <html>)
DOCUMENT_TYPE_NODE10<!Doctype html>
<h1 id="id01">My First Page</h1>
<p id="id02">Hello</p>
 
<script>
  <!-- H1 -->
  var nodeName = document.getElementById("id01").nodeName;
  <!-- null -->
  var nodeValue = document.getElementById("id01").nodeValue;
  <!-- Hello -->
  var nodeValue = document.getElementById("id02").firstNode.nodeValue;
</script>

访问元素

通过 DOM 提供的方法,可以访问 HTML 文档中的元素,常用方法包括:

  • getElementById(id): 通过元素 ID 获取单个元素。
  • getElementsByTagName(name): 通过标签名称获取一组元素。
  • getElementsByClassName(name): 通过类名获取一组元素。
  • querySelector(selector): 返回文档中匹配指定 CSS 选择器的第一个元素。
  • querySelectorAll(selector): 返回文档中匹配指定 CSS 选择器的所有元素的 NodeList。
// 通过元素ID获取元素
var elementById = document.getElementById("myElement");
// 通过标签名称获取元素集合
var elementsByTagName = document.getElementsByTagName("p");
// 通过类名获取元素集合
var elementsByClassName = document.getElementsByClassName("myClass");
// 使用CSS选择器获取第一个匹配元素
var firstElementBySelector = document.querySelector(".myClass");
// 使用CSS选择器获取所有匹配元素的NodeList
var allElementsBySelector = document.querySelectorAll("div.myClass");

getElementsByTagName() 方法返回一个 HTMLCollection 对象。
HTMLCollection 对象是 HTML 元素的类似数组的集合。
但是 HTMLCollection  对象并不是数组,不能直接用数组的函数,如不能直接用 valueOf()、pop()、push() 或 join()。

NodeList 对象是从文档中提取的节点集合,与 HTMLCollection 对象几乎相同。
所有浏览器都会为属性 childNodes 返回一个 NodeList 对象。
大多数浏览器为 querySelectorAll() 方法返回 NodeList 对象。

操作元素属性

可以通过各种 DOM 属性和方法更改 HTML 元素:

  • innerHTML: 获取或设置元素的 HTML 内容。
  • textContent: 设置或获取元素内的文本内容。
  • setAttribute(name, value): 设置元素的属性值。
  • removeAttribute(name): 删除元素的属性。
  • .attribute: 直接修改元素属性
  • getAttribute(): xxx
  • removeAttribute(): xxx
  • hasAttribute(): xxx
// 获取元素
var element = document.getElementById("myElement");
// 设置属性
element.setAttribute("type", "button");
// 删除属性
element.removeAttribute("style");
// 获取属性
var elementClass = element.getAttribute("class");
// 更改HTML内容
element.innerHTML = '<a href="#">Click me!</a>';
// 更改文本内容
element.textContent = "Hello, World!";
// 也可以直接 .attribute 修改元素内容
document.getElementById("myImage").src = "landscape.jpg";

操作 CSS 样式

JavaScript 也可以操作元素的 CSS 样式:

  • style: 通过该属性可以更改元素的样式(如元素的 style.color = ‘red’)。
  • className: 获取或设置元素的 class。
  • classList: 提供了对类名的各种操作,如添加、移除、切换类样式。
  • getComputedStyle(ele).attr: 获取元素的 CSS 样式,带 attr 则获取更具体的样式
// 获取元素
var element = document.getElementById("myElement");
// 修改样式
element.style.color = "blue";
element.style.fontSize = "14px";
// 添加类
element.classList.add("new-class");
// 移除类
element.classList.remove("old-class");
// 切换类
element.classList.toggle("active-class");
// 检查类是否存在
var hasClass = element.classList.contains("another-class");
 
// 需要驼峰形式
getComputedStyle(oBox).backgroundColor;

创建和删除元素

  • createElement(element): 创建一个 HTML 元素
  • createTextNode(text): 创建一个 text node
  • appendChild(child): 向元素添加新的子节点。
  • removeChild(child): 移除元素的子节点。
  • remove(): 删除当前节点。
  • insertBefore(new, element): 将新元素插入到某元素之前
  • replaceChild(new, old): 替换元素
  • cloneNode(bool): 复制元素,1/true 还会复制子元素。
  • write(text): 写入 HTML 输出流
// 创建一个新的 div 元素
var newDiv = document.createElement("div");
newDiv.id = "newDivId";
newDiv.className = "new-div-class";
newDiv.innerHTML = "This is a new div element";
 
// 创建一个包含 "This is a new paragraph." 文本的 p 节点
const para = document.createElement("p");
const node = document.createTextNode("This is a new paragraph.");
para.appendChild(node);
 
// 将新元素添加到文档
element.appendChild(newDiv);
// 移除子元素
element.removeChild(newDiv);
// 删除当前节点
element.remove();
// 插入元素
document.body.insertBefore(newP, firstDiv);

Events 事件处理

DOM 允许你给元素分配事件处理程序,响应用户操作:

  • addEventListener(type, listener, useCapture=False): 添加事件监听器。
  • removeEventListener(type, listener): 移除事件监听器。
  • onclick, onmouseover, onmouseout, onkeydown, onload 等: 分配或处理事件。

常见的 Event 事件有 JS Events 常见事件
添加事件监听器的时候,还可以配置事件传播机制,详见 JS Events 事件传播

function handleClick() {
  alert("Element was clicked!");
}
// 获取元素
var button = document.getElementById("myButton");
// 添加事件监听器
button.addEventListener("click", handleClick);
// 移除事件监听器
button.removeEventListener("click", handleClick);
// 添加事件监听器
document.getElementById(id).onclick = handleClick;
// 不止 document 中的元素可以添加 EventListener
window.addEventListener("resize", function () {
  document.getElementById("demo").innerHTML = _sometext_;
});

遍历 DOM 节点

  • parentNode: 访问元素的父节点。
  • childNodes[index]: 获取元素的子节点列表。
  • firstChildlastChild: 分别访问元素的第一个和最后一个子节点。
  • nextSiblingpreviousSibling: 分别访问元素的下一个和上一个兄弟节点。
// 获取元素
var list = document.getElementById("myList");
// 获取父元素
var parentOfList = list.parentNode;
// 遍历子节点
for (var i = 0; i < list.childNodes.length; i++) {
  console.log(list.childNodes[i]);
}
// 获取并遍历兄弟元素
var sibling = list.nextSibling;
while (sibling) {
  if (sibling.nodeType === 1) {
    // Element node
    console.log(sibling);
  }
  sibling = sibling.nextSibling;
}

HTML Objects

The first HTML DOM Level 1 (1998), defined 11 HTML objects, object collections, and properties. These are still valid in HTML5.

Later, in HTML DOM Level 3, more objects, collections, and properties were added.

PropertyDescriptionDOM
document.anchorsReturns all <a> elements that have a name attribute1
document.appletsDeprecated1
document.baseURIReturns the absolute base URI of the document3
document.bodyReturns the <body> element1
document.cookieReturns the document’s cookie1
document.doctypeReturns the document’s doctype3
document.documentElementReturns the <html> element3
document.documentModeReturns the mode used by the browser3
document.documentURIReturns the URI of the document3
document.domainReturns the domain name of the document server1
document.domConfigObsolete.3
document.embedsReturns all <embed> elements3
document.formsReturns all <form> elements1
document.headReturns the <head> element3
document.imagesReturns all <img> elements1
document.implementationReturns the DOM implementation3
document.inputEncodingReturns the document’s encoding (character set)3
document.lastModifiedReturns the date and time the document was updated3
document.linksReturns all <area> and <a> elements that have a href attribute1
document.readyStateReturns the (loading) status of the document3
document.referrerReturns the URI of the referrer (the linking document)1
document.scriptsReturns all <script> elements3
document.strictErrorCheckingReturns if error checking is enforced3
document.titleReturns the <title> element1
document.URLReturns the complete URL of the document1

HTML Form Validation

JavaScript Form Validation

JS 动画小示例

点击按钮后,会有一个小红色矩形从左上角运动到右下角。W3Schools Tryit Editor

<!DOCTYPE html>
<html>
  <style>
    #container {
      width: 400px;
      height: 400px;
      position: relative;
      background: yellow;
    }
    #animate {
      width: 50px;
      height: 50px;
      position: absolute;
      background-color: red;
    }
  </style>
 
  <body>
    <p><button onclick="myMove()">Click Me</button></p>
 
    <div id="container">
      <div id="animate"></div>
    </div>
 
    <script>
      function myMove() {
        let id = null;
        const elem = document.getElementById("animate");
        let pos = 0;
        clearInterval(id);
        id = setInterval(frame, 5);
        function frame() {
          if (pos == 350) {
            clearInterval(id);
          } else {
            pos++;
            elem.style.top = pos + "px";
            elem.style.left = pos + "px";
          }
        }
      }
    </script>
  </body>
</html>