JS之DOM篇-常用节点类型详解

文本节点详解

文本节点由Text类型表示,包含的是纯文本内容,虽然是纯文本但却是对象类型

<div id="test">内容</div>
<script>
  console.log(test.firstChild, typeof test.firstChild) // "内容" "object"
</script>

纯文本内容中的HTML字符会被转义

<div id="test">&lt;内容&gt;</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) //  内容&lt;span style="color:red"&gt;新内容&lt;/span&gt; 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文档节点,其他仅作了解即可

posted @ 2021-09-29 13:04  wmui  阅读(490)  评论(0编辑  收藏  举报