文档对象模型
用来描述文档,特指HTML文档,同时又是一个“对象模型”,意味着它使用的是对象这样的概念来描述HTML文档。
DOM API大致包含4个部分
- 节点:DOM 树形结构中的节点相关API
- 事件:触发和监听事件相关API
- Range:操作文字范围相关API
- 遍历:遍历DOM 需要的API
节点
节点.pngElement: <tagname>...</tagname>
Text: text
Comment: <!-- comments -->
DocumentType: <!Doctype html>
ProcessingInstruction: <?a 1?>
我们编写HTML代码运行后,就会在内存中得到这样一颗DOM树,HTML的写法会被转化成对应的文档模型,而我们则可以通过JS等语言来访问这个文档模型
Node
Node是DOM树继承关系的根节点,提供了一组属性,来表示在DOM树中的关系
- parentNode
- childNodes
- firstChild
- lastChild
- nextSibling
- previousSibling
也提供了操作DOM树的API
- appendChild
- insertBefore
- removeChild
- replaceChild
除此之外,Node还提供了一些高级的API
- compareDocumentPosition 用于比较两个节点中关系的函数
- contains 检查一个节点是否包含另一个节点
- isEqualNode 检查两个节点是否完全相同
- isSameNode 检查两个节点是否是同一个节点
- cloneNode 复制一个节点
DOM标准规定了节点必须从文档create方法创建出来。于是document有了这些方法
- createElement
- createTextNode
- createCDATASection
- createComment
- createProcessingInstruction
- createDocumentFragment
- createDocumentType
Element和Attribute
Node提供了树形结构上节点相关的操作。
Element表示元素,是Node的子类,既有子节点,又有属性
对于DOM而言,Attribute和 Property是完全不同的定义
把元素的Attrbute当作字符串来看,则有:
- getAttribute
- setAttribute
- removeAttribute
- hasAttribute
- getAttributeNode
- setAttributeNode
查找元素
document节点提供了查找元素的能力
- querySelector(性能较低)
- querySelectorAll
- getElementById
- getElementByName
- getElementByTagName
- getElementsByClassName
遍历
DOM还提供了NodeIterator和TreeWalker来遍历树,同时具有过滤功能
NodeIterator的基本用法
var iterator = document.createNodeIterator(document.body, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT, null, false);
var node;
while(node = iterator.nextNode())
{
console.log(node);
}
以及TreeWalker的用法
var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, null, false)
var node;
while(node = walker.nextNode())
{
if(node.tagName === "p")
node.nextSibling();
console.log(node);
}
Range
Range较为专业化,主要是富文本编辑类业务
var range = new Range(),
firstText = p.childNodes[1],
secondText = em.firstChild
range.setStart(firstText, 9) // do not forget the leading space
range.setEnd(secondText, 4)
var fragment = range.extractContents()
range.insertNode(document.createTextNode("aaaa"))
补充算法
// 深度优先
function deepLogTagNames(parentNode){
console.log(parentNode.tagName)
const childNodes = parentNode.childNodes
// 过滤没有 tagName 的节点,遍历输出
Array.prototype.filter.call(childNodes, item=>item.tagName)
.forEach(itemNode=>{
deepLogTagNames(itemNode)
})
}
deepLogTagNames(document.body)
// 广度优先
function breadLogTagNames(root){
const queue = [root]
while(queue.length) {
const currentNode = queue.shift()
const {childNodes, tagName} = currentNode
tagName && console.log(currentNode.tagName)
// 过滤没有 tagName 的节点
Array.prototype.filter.call(childNodes, item=>item.tagName)
.forEach(itemNode=>{
queue.push(itemNode)
})
}
}
breadLogTagNames(document.body)
参考原文: 浏览器DOM:你知道HTML的节点有哪几种吗?
网友评论