每个 DOM 节点都属于相应的内建类。
层次结构(hierarchy)如下:
![[Pasted image 20240426175513.png]]
parentNode,nextSibling,childNodes 等(它们都是 getter)。Node 类的对象从未被创建。但是还有一些继承自它的其他类(因此继承了 Node 的功能)。HTMLDocument 继承(尽管最新的规范没有规定)—— 是一个整体的文档。
document 就是属于这个类。它作为 DOM 的入口。nextElementSibling,children,以及搜索方法,如 getElementsByTagName 和 querySelector。Element 类充当的是更具体的类的基础:SVGElement,XMLElement 和 HTMLElement。<span>、<section>、<article> 等,没有任何特定的属性和方法,所以它们没有更具体的 HTML 继承元素,而是 HTMLElement 类的实例console.dir() 与 console.log()
console.log:友好方式输出到控制台
console.dir:输出到控制台原始值
对于 DOM 元素:
console.log(elem) 显示元素的 DOM 树
console.dir(elem) 将元素显示为对象
对于函数:
console.log(func) 显示函数定义字符串console.dir(func) 将函数显示为对象HTML/XML 文档在浏览器内均被表示为 DOM 树。
HTML 以外其他网页上常见的 XML:
对应的命名空间:
http://www.w3.org/1999/xhtmlhttp://www.w3.org/2000/svghttp://www.w3.org/1998/Math/MathMLDOM 的很多方法都有相对应的命名空间方法 *NS(namespace, ...) 用来处理非 HTML 的 Element
Node 和 ElementNode:在 DOM 树中,所有的节点都是 Node,包括 Element,也就是说 Node 包含了 HTML/XML 元素标签、text、注释等内容,它是所有 DOM 的基类Element:在 DOM 树中,Element 是所有 HTML/XML 元素的基类nodeTypenodeType 属性提供了一种“过时的”用来获取 DOM 节点类型的方法。
它有一个数值型值:
elem.nodeType === document.ELEMENT_NODE // 1elem.nodeType === document.TEXT_NODE // 3document 对象:document === document.DOCUMENT_NODE // 9,elem.nodeType === document.COMMENT_NODE // 8一共有 12 种节点类型
nodeName 和 tagName给定一个 DOM 节点,可以从 nodeName 或者 tagName 属性中读取它的标签名:
document.body.nodeName // BODY
document.body.tagName // BODY
tagName 属性仅适用于 ElementnodeName 是为任意 Node 定义的:
tagName 相同document.tagName // undefined,document 不是 Element,是 Node
浏览器有两种处理文档(document)的模式:HTML 和 XML。通常,HTML 模式用于网页。只有在浏览器接收到带有 Content-Type: application/xml+xhtml header 的 XML-document 时,XML 模式才会被启用。
tagName/nodeName 始终是大写的innerHTMLinnerHTML 属性仅对元素节点有效,其他节点使用 [[#nodeValue/data|nodeValue/data]]
注意:
innerHTML 将一个 <script> 标签插入到 document 中 —— 它会成为 HTML 的一部分,但是不会执行。innerHTML += ... 并不是追加,而是完全重写。
innerHTML(新旧结合)<input> 的 value 等outerHTMLinnerHTML 加上元素本身一样(删除所有空白字符,保留标签,保留换行)innerHTML 不同,写入 outerHTML 不会改变元素。而是在 DOM 中替换它<div>Hello, world!</div>
<script>
let div = document.querySelector('div');
// 使用 <p>...</p> 替换 div.outerHTML
div.outerHTML = '<p>A new element</p>';
// 蛤!'div' 还是原来那样!
// 但是页面 DOM 已经变成了 <p>
console.log(div.outerHTML); // <div>Hello, world!</div>
</script>
在 div.outerHTML = ... 中发生的事情是:
div 被从文档(document)中移除<p>A new element</p> 被插入到其位置上div 仍拥有其旧的值nodeValue/data[[#innerHTML|innerHTML]] 属性仅对元素节点有效
文本节点、注释节点,具有它们的对应项:nodeValue 和 data 属性。这两者在实际使用中几乎相同,只有细微规范上的差异。同样,可读可写
元素节点没有 nodeValue 和 data 属性,或者为 null
innerText 和 outerText只有元素节点有
innerText:
outerText:
textContent所有 Node 都有
以上所有属性 document 节点都没有,或者为 null
hidden 特性(attribute)和 DOM 属性(property)指定元素是否可见。
可以在 HTML 中使用它,或者使用 JS 对其进行赋值:
<div>Both divs below are hidden</div>
<div hidden>With the attribute "hidden"</div>
<div id="elem">JavaScript assigned the property "hidden"</div>
<script>
elem.hidden = true
</script>
从技术上来说,hidden 与 style="display:none" 做的是相同的事。
NodeList 和 HTMLCollectionNodeList:
document.getElementsByNamedocument.querySelectorAllelem.childNodesHTMLCollection:
document.formsdocument.imageselem.getElementsByTagNameelem.getElementsByTagNameNSelem.getElementsByClassNameelem.childrenNodeListNode 的集合Node 是响应式的:修改文档对象,相应的 DOM 视图也会发生更新NodeList 会即时更新
document.querySelectorAll 惰性机制,DOM 增删节点不会即时更新返回的集合属性和方法:
[index]:通过下标索引,越界返回 undefinedlength:节点集合的长度item(index):通过下标索引,越界返回 nullforEach(cb):遍历方法entries():返回 key-value 的迭代器keys():返回 key 的迭代器,也就是索引values():返回 value 的迭代器,也就是节点Symbol(Symbol.iterator):迭代器,for...offorEach 执行流程:
// forEach 执行流程模拟
NodeList.prototype.forEach = function forEach(cb) {
const len = this.length // 先获取到 length 进行保存,之后及时 length 更新了也不会改变
for (let i = 0; i < len; i++) { // 就遍历到 len
if (i in this) { // 当前遍历的元素存在
cb(this[i], i, this)
}
}
}
迭代器执行流程:
// 迭代器执行流程模拟
NodeList.prototype[Symbol.iterator] = function* iterator() {
for (let i = 0; i < this.length; i++) {
yield this[i]
}
}
// 或
NodeList.prototype[Symbol.iterator] = function iterator() {
let i = -1
let self = this
return {
next: () => {
i++ // 每次调用 next,游标往下指
return { value: self[i], done: i === self.length }
}
}
}
所以:
forEach 只遍历到一开始的长度;迭代器会无限迭代HTMLCollectionElement 的集合Element 是响应式的(Element 属于 Node):修改文档对象,相应的 DOM 视图也会发生更新HTMLCollection 会即时更新属性和方法:
[index]:通过下标索引,越界返回 undefinedlength:节点集合的长度item(index):通过下标索引,越界返回 nullnamedItem(name):传入节点的 name 属性,返回特定的节点,不存在返回 nullSymbol(Symbol.iterator):迭代器,`for...ofHTML5 之前基本没有开放 Node 相关的接口,和 Node 和 NodeList 相关的 API 基本都是 HTML5 新增的(不绝对),如:elem.childNodes、querySelector* 等