1 测试准备
<!DOCTYPE html>
<html>
<head>
<title>page title</title>
</head>
<body>
</body>
</html>
// variable for test
let d1 = document.createElement('div')
let d2 = document.createElement('div')
let p1 = document.createElement('p')
let p2 = document.createElement('p')
let txt1 = document.createTextNode('text one')
let txt2 = document.createTextNode('text two')
let cmt1 = document.createComment('comment one')
let cmt2 = document.createComment('comment two')
let body = document.body
body.appendChild(d1)
d1.append(p1, p2, txt1, txt2)
2 方法和属性 API
- nodeType nodeName
d1.nodeType === Node.ELEMENT_NODE // true, 1
d1.nodeName // "DIV"
txt1.nodeType === Node.TEXT_NODE // true, 3
txt1.nodeName // "#text"
cmt1.nodeType === Node.COMMENT_NODE // true, 8
cmt1.nodeName // "#comment"
document.nodeType === Node.DOCUMENT_NODE // true, 9
document.nodeName // "#document"
let docType = document.firstChild // <!DOCTYPE html>
docType.nodeType === Node.DOCUMENT_TYPE_NODE // true, 10
docType.nodeName // "html"
- childNodes firstChild lastChild nextSibling previousSibling parentNode parentElement
d1.childNodes // NodeList(4) [p, p, text, text], 伪数组
d1.firstChild === p1 // true, <p></p>
d1.lastChild === txt2 // true, "text two"
d1.childNodes[2] // "text one", === txt1
p2.nextSibling === txt1 // true
p2.previousSibling === p1 // true
p1.parentNode // d1
p1.parentElement // d1
document.parentNode // null
document.parentElement // null
- baseURI isConnected ownerDocument
// represent the base URL(protocol, domain name, directory structure)
body.baseURI = "http://localhost:8081/one.html"
// 是否添加至上下文
// whether the Node is connected (directly or indirectly) to the context object
txt1.isConnected // true
cmt1.isConnected // false
// 无论isConnected是否为真
txt1.ownerDocument // #document
cmt1.ownerDocument // #document
document.ownerDocument // null
- nodeValue
txt1.nodeValue // "text one"
cmt1.nodeValue // "comment one"
document.nodeValue // null
document.docType.nodeValue // null
d1.nodeValue // null
// When nodeValue is defined to be null, setting it has no effect.
d1.nodeValue = "d1d1"
d1.nodeValue // null, 设置无效
- textContent
txt1.textContent // "text one"
cmt1.textContent // "comment one"
document.textContent // null
document.docType.textContent // null
document.documentElement.textContent // 整个<html></html>中文本的连接
// 不包含Comment,包含<script>和<style>中的text
p1.append(txt1, cmt1)
p1.textContent // "text one"
d1.textContent // "text onetext two"
// 移除所有childNodes,然后append("d1d1")
d1.textContent = "d1d1"
- appendChild() removeChild() replaceChild() insertBefore()
// DOMException: The node to be removed is not a child of this node
// 如果要操作的node不是当前node的child,其他的方法报类似的异常
d1.removeChild(cmt1)
d1.removeChild(p2) === p2 // true, 返回被移除的node
// relacedNode = Node.replace(newNode, oldNode)
d1.replaceChild(p2, p1) === p1 // true, 返回被替换的node
// removeChild和appendChild方法都返回被操作的node
d1.appendChild(p2) // 如果node已在DOM中,先执行remove
// insertedNode = Node.insertBefore(newNode, refNode)
d1.insertBefore(p1, p2) // p1, 返回新插入的node
d1.insertBefore(p1, null) // 允许null,相当于执行appendChild,但refNode必须是child
// 移除d1的所有childNode
d1.clearChildNodes()
Node.prototype.clearChildNodes = function () {
Array.from(this.childNodes).forEach(child => child.remove())
}
- hasChildNodes() contains() getRootNode()
d1.hasChildNodes() // true
// directly or indirectly
body.contains(d1) // true
body.contains(p1) // true
// 注意: only validate the first param
d1.contains(txt1, cmt1) // true
d1.contains(cmt1, txt1) // false
p1.getRootNode() // document
document.getRootNode() // document
- isEqualNode() isSameNode() cloneNode()
d2.append(txt1)
let d3 = d2.cloneNode() // <div></div>,不包含childNode
let d4 = d2.cloneNode(true) // <div>text one</div>,包含childNode
d2.isEqualNode(d3) // false
d2.isEqualNode(d4) // true
d2.isSameNode(d3) // false
d2.isSameNode(d4) // false
- normalize()
The Node.normalize() method puts the specified node and all of its sub-tree into a “normalized” form. In a normalized sub-tree, no text nodes in the sub-tree are empty and there are no adjacent text nodes.
// 移除空文本节点,合并相邻的文本节点
d1.normalize()
3 ParentNode mixins
The ParentNode mixin contains methods and properties that are common to all types of Node objects that can have children. It’s implemented by Element, Document, and DocumentFragment objects.
- append() prepend() querySelector() querySelectorAll()
// #document DIV P等实现了ParentNode mixin,#text #comment没有实现
p1.children // HTMLCollection []
txt1.children // undefined
// TypeError: parameter 1 is not of type 'Node'
d1.appendChild("some txt")
// 允许多个param,允许DOMString
d1.append(p1, p2, txt1, "some text")
d1.prepend(p1, p2, "some text")
d1.lastChild.nodeName // "#text", 文本node
// 注意: append和prepend方法是实验性(experimental)API,不应该在生产环境中使用
d1.querySelectorAll("p") // NodeList [p, p],所有匹配的Element
d1.querySelector("p") === p1 // true,第一个匹配的Element
// 移除d1的所有children
d1.clear()
Node.prototype.clear = function () {
Array.from(this.children).forEach(child => child.remove())
}
- childElementCount children firstElementChild lastElementChild
d1.childElementCount // 2
d1.children // HTMLCollection(2) [p, p], 伪数组
d1.firstElementChild === p1 // true, <p></p>
d1.lastElementChild === p2 // true, <p></p>
4 ChildNode interface
The ChildNode interface contains methods that are particular to Node objects that can have a parent.
ChildNode is a raw interface and no object of this type can be created; it is implemented by Element, DocumentType, and CharacterData objects.
- remove() after() before() replaceWith()
// Element DocType CharacterData实现ChildNode interface
// 4个方法都是实验性(experimental)API,不应该在生产环境中使用
// 4个方法都返回undefined,DOMString相当于Text Node
p1.remove()
p2.after(p1, txt1, cmt1, "some text")
p2.before(p1, txt1, cmt1, "some text")
txt1.repalceWith(cmt1, p1, "some text")
5 NonDocumentTypeChildNode
The NonDocumentTypeChildNode interface contains methods that are particular to Node objects that can have a parent, but not suitable for DocumentType.
NonDocumentTypeChildNode is a raw interface and no object of this type can be created; it is implemented by Element, and CharacterData objects.
- previousElementSibling nextElementSibling
txt1.previousElementSibling // p2
txt1.nextElementSibling // null