文本节点详解
文本节点由Text类型表示,包含的是纯文本内容,虽然是纯文本但却是对象类型
<div id="test">内容</div>
<script>
console.log(test.firstChild, typeof test.firstChild) // "内容" "object"
</script>
纯文本内容中的HTML字符会被转义
<div id="test"><内容></div>
<script>
console.log(test.firstChild) // "<内容>"
</script>
当代码换行后会存在空白文本节点
<div id="test">
<span>内容</span>
</div>
<script>
console.log(test.childNodes) // [text, span, text]
</script>
属性
data属性:文本节点的data属性与nodeValue属性相同
<div id="test">内容</div>
<script>
var txt = test.firstChild
console.log(txt.data, txt.nodeValue, txt.data === txt.nodeValue) // 内容 内容 true
</script>
wholeText属性:wholeText属性把当前文本节点和毗邻的文本节点作为一个整体返回
<div id="test">内容</div>
<script>
var txt = test.firstChild
console.log(txt.wholeText, txt.data) // 内容 内容
txt.splitText(1)
console.log(txt.wholeText, txt.data) // 内容 内
</script>
length属性:length属性保存着文本节点字符的数目。nodeValue.length和data.length也保存着相同的值
<div id="test">内容</div>
<script>
var txt = test.firstChild
console.log(txt.length, txt.nodeValue.length, txt.data.length) // 2 2 2
</script>
方法
createTextNode():createTextNode(text)方法用于创建文本节点,它接收一个参数,表示要插入节点的文本
<div id="test">内容</div>
<script>
var txtNode = document.createTextNode('<span style="color:red">新内容</span>')
test.appendChild(txtNode)
console.log(test.innerHTML, test.childNodes.length) // 内容<span style="color:red">新内容</span> 2
</script>
只是作为文本插入,所以文字不会应用样式
normalize():normalize()方法可以合并相邻的文本节点,该方法需要在文本节点的父节点上调用
<div id="test">0</div>
<script>
var t1 = document.createTextNode('1')
var t2 = document.createTextNode('2')
test.appendChild(t1)
test.appendChild(t2)
console.log(test.childNodes.length) // 3
test.normalize()
console.log(test.childNodes.length, test.childNodes[0]) // 1 "012"
</script>
注意: IE9+浏览器无法正常使用该方法
splitText():splitText(pos)方法与normalize()方法作用相反,该方法将一个文本节点分成两个文本节点,并返回一个包含剩余文本的新节点,该方法会改变原始节点
<div id="test">012</div>
<script>
var txt = test.firstChild
var newTxtNode = txt.splitText(1)
console.log(newTxtNode) // "12"
console.log(test.firstChild, test.lastChild) // "0" "12"
</script>
appendData(): appendData(text)方法将text添加到节点的末尾,无返回值
<div id="test">012</div>
<script>
var txt = test.firstChild
txt.appendData('3')
console.log(txt.data) // "0123"
</script>
deleteData():deleteData(offset, count)方法从offset指定的位置开始,删除count个字符,无返回值
<div id="test">012</div>
<script>
var txt = test.firstChild
txt.deleteData(1,1)
console.log(txt.data) // "02"
</script>
insertData():insertData(offset,text)方法在offset指定的位置插入text,无返回值
<div id="test">012</div>
<script>
var txt = test.firstChild
txt.insertData(1,'hello')
console.log(txt.data) // "0hello12"
</script>
replaceData(): replaceData(offset,count,text)方法用text替换从offset指定位置开始到offset+count为止的文本,无返回值
<div id="test">012</div>
<script>
var txt = test.firstChild
txt.replaceData(1,2,'hello')
console.log(txt.data) // "0hello"
</script>
substringData(): substringData(offset, count)方法提取从offset指定的位置开始到offset+count为止处的字符串,并返回该字符串。不改变原来的文本节点
<div id="test">012</div>
<script>
var txt = test.firstChild
var ret = txt.substringData(1,2)
console.log(ret, txt.data) // "12" "012"
</script>
说明: 文本节点的操作与字符串的操作方法比较类似,上面列出的方法并不常用。直接通过字符串的方法去操作文本更方便些,而且性能也更好
注释节点详解
注释节点Comment与文本节点Text继承自相同的基类,因此它拥有除了splitText()之外的所有字符串操作方法。
属性
data属性:data属性与nodeValue属性相同,返回注释内容
length属性: length属性保存着节点字符的数目,nodeValue.length和data.length也保存着相同的值
<div id="test"><!--注释内容--></div>
<script>
var txt = test.firstChild
console.log(txt.nodeValue,txt.data,txt.data == txt.nodeValue) // 注释内容 注释内容 true
console.log(txt.length,txt.nodeValue.length,txt.data.length) // 4 4 4
</script>
方法
createComment(): createComment(text)方法用于创建注释节点,这个方法接收一个参数,表示要插入节点中的注释文本
<div id="test"></div>
<script>
var txt = document.createComment('注释内容')
test.insertBefore(txt, test.firstChild)
console.log(test.firstChild) // <!--注释内容-->
</script>
appendData(): appendData(text)方法将text添加到节点的末尾,无返回值
<div id="test"><!----></div>
<script>
var txt = test.firstChild
txt.appendData('注释内容')
console.log(txt.data) // 注释内容
</script>
deleteData(): deleteData(offset,count)方法从offset指定的位置开始删除count个字符,无返回值
<div id="test"><!--注释内容--></div>
<script>
var txt = test.firstChild
txt.deleteData(2,2)
console.log(txt.data) // 注释
</script>
insertData(): insertData(offset,text)方法在offset指定的位置插入text
<div id="test"><!--注释内容--></div>
<script>
var txt = test.firstChild
txt.insertData(2,'hello')
console.log(txt.data) // 注释hello内容
</script>
replaceData(): replaceData(offset,count,text)方法用text替换从offset指定的位置开始到offset+count处为止处的文本,无返回值
<div id="test"><!--注释内容--></div>
<script>
var txt = test.firstChild
txt.replaceData(2,2,'hello')
console.log(txt.data) // 注释hello
</script>
substringData(): substringData(offset,count)方法提取从offset指定的位置开始到offset+count为止处的字符串,返回提取内容
<div id="test"><!--注释内容--></div>
<script>
var txt = test.firstChild
var ret = txt.substringData(2,2)
console.log(txt.data, ret) // 注释内容 内容
</script>
文档类型节点详解
文档类型节点DocumentType的父节点是Document,它没有子节点。文档类型节点有一个快捷写法document.doctype。
属性
文档类型节点DocumentType对象有3个属性:name、entities、notations
name属性:name表示文档类型的名称,与nodeName的属性相同
entities属性:entities表示由文档类型描述的实体的NamedNodeMap对象
notations属性:notations表示由文档类型描述的符号的NamedNodeMap对象
通常浏览器中的文档使用的都是HTML或XHTML文档类型,因而entites和notations都是空列表
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<script>
var doc = document.doctype
console.log(doc.name, doc.nodeName) // "html" "html"
console.log(doc.entities, doc.notations) // undefined undefined
</script>
</body>
</html>
文档片段节点详解
12种节点类型中,只有文档片段节点(DocumentFragment)在文档中没有对应的标记。文档片段是一种“轻量级”的文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源
可以使用document.createDocumentFragment()方法创建文档片段,文档片段继承了Node的所有方法,通常用于执行那些针对文档的DOM操作,比如列表渲染
<!-- 使用DocumentFragment -->
<ul id="list"></ul>
<script>
console.time('time')
var fragment = document.createDocumentFragment()
for (var i = 0; i < 50000; i++) {
fragment.appendChild(document.createElement('li'))
}
list.appendChild(fragment)
console.timeEnd('time')
</script>
<!-- 传统写法 -->
<ul id="list"></ul>
<script>
console.time('time')
for (var i = 0; i < 50000; i++) {
list.appendChild(document.createElement('li'))
}
console.timeEnd('time')
</script>
在Chrome浏览器下测试,5万次循环,使用DocumentFragment耗时110ms左右,使用传统写法耗时160ms左右
元素节点详解
元素节点主要提供了对元素标签名、子节点及属性的访问
属性
tagName属性:要访问元素节点的标签名可以使用nodeName,也可以使用tagName属性
<div id="test">012</div>
<script>
console.log(test.nodeName, test.tagName) // 'DIV' 'DIV'
</script>
childNodes属性: 元素可以有任意数目的子节点和后代节点,元素的childNodes属性包含了它的所有子节点,这些子节点可能是元素、文本、注释、处理指令节点
<div id="test">
<span>1</span>
<!-- 注释 -->
<span>2</span>
</div>
<script>
console.log(test.childNodes, test.childNodes.length) // [text, span, text, comment, text, span, text] 7
</script>
方法
hasAttribute():hasAttribute(attrName)方法返回一个布尔值,表示当前元素节点是否包含指定属性
<div id="test" class="test">012</div>
<script>
console.log(test.hasAttribute('class'), test.hasAttribute('id')) // true true
</script>
getAttribute(): getAttribute(attrName)方法取得属性值,如果给定的属性不存在或者无参数则返回null
<div id="test">012</div>
<script>
console.log(test.getAttribute('id'),test.getAttribute('class')) // test null
</script>
setAttribute(): setAttribute(attrName, attrValue)方法接收两个参数,要设置的属性名和值。如果属性值已存在,就替换现有的值。无返回值
<div id="test" class="test">012</div>
<script>
test.setAttribute('class', 'box')
test.setAttribute('title', '标题')
console.log(test) // <div id="test" class="box" title="标题">012</div>
</script>
removeAttribute(): removeAttribute(attrName)方法用于彻底删除元素的属性。无返回值
<div id="test" class="test">012</div>
<script>
test.removeAttribute('class')
console.log(test.getAttribute('class')) // null
</script>
attributes属性
元素节点是唯一一个拥有attributes属性的DOM节点类型,attributes属性中包含一个NamedNodeMap,它与NodeList类似,也是一个动态集合。
关于NamedNodeMap、NodeList、HTMLCollection的介绍移步于此
attributes属性包含以下四个方法
getNamedItem(): getNamedItem(name)方法返回nodeName属性等于name的节点
<div id="test" class="test" title="标题">012</div>
<script>
console.log(test.attributes) // NamedNodeMap {0: id, 1: class, 2: title, id: id, class: class, title: title, length: 3}
console.log(test.attributes.getNamedItem('class')) // class="test"
console.log(test.attributes.class) // class="test"
console.log(test.attributes.getNamedItem('class').nodeName) // class
console.log(test.attributes.getNamedItem('class').nodeValue) // test
</script>
removeNamedItem(): removeNamedItem(name)方法从列表中移除nodeName属性等于name的节点,并返回该节点
<div id="test" class="test" title="标题">012</div>
<script>
console.log(test.attributes.removeNamedItem('class')) // class="test"
console.log(test.attributes.getNamedItem('class')) // null
</script>
setNamedItem(): setNamedItem(node)方法向列表中添加节点,该方法无返回值
<div id="test" class="test" title="标题">012</div>
<script>
let node = test.attributes.removeNamedItem('class')
test.attributes.setNamedItem(node)
console.log(test.attributes.getNamedItem('class')) // class="test"
</script>
item(): item(pos)方法返回位于数字pos位置处的节点,也可以用方括号法[]简写
<div id="test" class="test" title="标题">012</div>
<script>
console.log(test.attributes.item(1), test.attributes[1]) // class="test" class="test"
</script>
属性节点详解
属性节点是存在于元素的属性中的节点,虽然它是节点,但却不是DOM节点树的一部分
属性
name: name是属性名称,与nodeName值相同
value: value是属性值,与nodeValue值相同
specified: specified是一个布尔值,用以区别属性是在代码中指定的,还是默认的。如果为true,则意味着要么是在HTML中指定了相应属性,要么是通过setAttribute()方法设置了该属性
<div id="test" class="test" title="标题">012</div>
<script>
console.log(test.attributes) // NamedNodeMap {0: id, 1: class, 2: title, id: id, class: class, title: title, length: 3}
console.log(test.attributes.class.name) // class
console.log(test.attributes.class.value) // test
console.log(test.attributes.class.specified) // true
</script>
方法
createAttribute(): createAttribute(attrName)方法传入属性名称并创建新的属性节点
setAttributeNode(): setAttributeNode(attr)方法传入属性节点并将属性添加到元素上,无返回值
getAttributeNode(): getAttributeNode(attrName)方法传入属性名并返回属性节点
removeAttributeNode(): removeAttributeNode(attr)方法删除并返回传入的属性节点
<div id="test">012</div>
<script>
var attr = document.createAttribute('title') // 创建
attr.value = '标题' // 添加值
test.setAttributeNode(attr)
console.log(test.getAttributeNode('title')) // title="标题"
console.log(test.removeAttributeNode(attr)) // title="标题"
console.log(test.getAttributeNode('title')) // null
</script>
文档节点详解
文档节点(document)表示网页页面,也叫作根节点,它是浏览器window对象的一个属性。由于已经是根节点了,所以其父节点指向null,ownerDocument也指向null
快捷访问
<!DOCTYPE>
: document.doctype属性指向<!DOCTYPE>
标签
<html>
: document.documentElement属性指向<html>
元素
<body>
: document.body属性指向<body>
元素
<head>
: document.head属性指向文档的<head>
元素
console.log(document.doctype.nodeName) // 'html'
console.log(document.documentElement.nodeName) // 'HTML'
console.log(document.body.nodeName) // 'BODY'
console.log(document.head.nodeName) // 'HEAD'
文档信息
<title>
: document.title包含着<title>
元素中的文本,这个属性可读写
console.log(document.title) // 'Document'
document.title = '新标题'
console.log(document.title) // '新标题'
URL
: 页面的完整地址
domain
: domain与URL是相互关联的,包含页面的域名
referrer
: 表示链接到当前页面的上一个页面的URL,在没有来源页面时,值为空
console.log(document.URL) // https://blog.86886.wang/posts/5b38d0098c98760acf25bfac
console.log(document.domain) // www.86886.wang
console.log(document.referrer) // https://www.86886.wang/
// 子域名 www.86886.wang, 主域名 86886.wang
document.domain = '86886.wang'
这3个属性中,只有domain是可以设置值,并且只能是子域名设置成主域名,不允许跨域设置
baseURI
: document.baseURI返回<base>
标签中的URL,如果没有设置<base>
,则该值与document.URL相同
console.log(document.baseURI) //'https://www.86886.wang/'
charset
: document.charset表示文档中实际使用的字符集
console.log(document.charset) //'UTF-8'
defaultView
: document.defaultView保存着一个指针,指向拥有给定文档的窗口或框架
console.log(document.defaultView) // Window
compatMode
: document.compatMode表示文档的模式,在标准模式下值为"CSS1Compat",在兼容模式下值为"BackCompat"
documentMode
: document.documentMode属性表示当前的文档模式(该属性只有IE11-浏览器支持)
//IE11返回11,IE10返回10,IE9返回9,IE8返回8,IE7返回7,IE6返回6
console.log(document.documentMode)
lastModified
: document.lastModified属性返回当前文档最后修改的时间戳,格式为字符串
console.log(document.lastModified) // 13/07/2018 18:50:32
节点集合
anchors
: document.anchors包含文档中所有带name特性的<a>
元素
links
: document.links包含文档中所有带href特性的<a>
元素
forms
: document.forms包含文档中所有的<form>
元素
images
: document.images包含文档中所有的<img>
元素
scripts
: document.scripts包含文档中所有的<script>
元素
<!DOCTYPE html>
<html lang="en">
<head>
<title>文章标题</title>
</head>
<body>
<a href="#" name="a1">anchor</a>
<a href="#">link</a>
<form action="#">form</form>
<img src="#" alt="image">
<script>
console.log(document.anchors.length) // 1
console.log(document.links.length) // 2
console.log(document.forms.length) // 1
console.log(document.images.length) // 1
console.log(document.scripts.length) // 1
</script>
</body>
</html>
以上五个属性返回的都是HTMLCollection对象实例,由于HTMLCollection
实例可以通过HTML元素的id或name属性引用,因此上面的元素如果有id或name属性,可以直接获得引用
console.log(document.links instanceof HTMLCollection) // true
console.log(document.images instanceof HTMLCollection) // true
console.log(document.forms instanceof HTMLCollection) // true
console.log(document.anchors instanceof HTMLCollection) // true
console.log(document.scripts instanceof HTMLCollection) // true
<a href="#" name="n1" id="i1">anchor</a>
<form action="#" name="n2" id="i2">form</form>
<img src="#" alt="image" name="n3" id="i3">
<script name="n4" id="i4">
console.log(document.anchors.n1)
console.log(document.anchors.i1)
console.log(document.links.n1)
console.log(document.links.i1)
console.log(document.forms.n2)
console.log(document.forms.i2)
console.log(document.images.n3)
console.log(document.images.i3)
console.log(document.scripts.n4)
console.log(document.scripts.i4)
</script>
写入方法
将输出流写入到网页的方法有四个: write()、writeIn()、open()、close()
write()和writeIn(): write()和writeIn()都接受一个字符串参数,表示要写入输出流的文本。write()方法会原样写入,而writeIn()方法则在字符串末尾添加一个换行符(/n),但是换行符会被网页解析成空格。在网页加载过程中,可以用这两个方法动态写入内容
<button type="button" id="btn">写入</button>
<script>
btn.onclick=functon() {
document.write('write')
document.writeIn('writeIn')
document.write('write')
}
</script>
结果: writewriteIn write
open()和close():open()和close()方法分别用于打开和关闭网页的输出流。open()方法实际上是新建了一个空白文档,在表现效果上像清空了当前文档
<button type="button" id="btn">新建空白文档</button>
<script>
btn.onclick=function() {
document.open()
}
</script>
结果: 点击“新建空白文档”按钮会清空当前文档
close()方法用于关闭open()方法新建的文档,关闭后将无法在这个新建的文档上写入内容。如果再次调用write()方法,等同于又调用了open()方法,新建了一个空白文档再写入内容。
<button type="button" id="btn">写入</button>
<script>
btn.onclick=function() {
document.open()
document.write('hello')
document.close()
document.write('world')
}
</script>
结果: world
如果不调用close()方法,结果是“helloworld”。调用close()方法后,相当于“world”覆盖了“hello”,所有最后只有“world”
通常open()方法和close()一起使用,先使用open()方法新建一个文档,然后使用write()和writeln()方法写入文档,最后使用close()方法,停止写入
<button id="btn">写入</button>
<script>
btn.onclick = function(){
document.open()
document.writeln('hello')
document.write('world')
document.close()
}
</script>
结果: hello world
如果是在页面加载期间使用write()和writeln()方法,则不需要用到这两个方法
<button id="btn">内容</button>
<script>
document.writeln('hello')
document.write('world')
</script>
结语
DOM的12中节点类型中,常用的只有Element元素节点、Attribute属性节点、Text文本节点、Comment注释节点、Document文档节点,其他仅作了解即可