《JavaScript高级程序设计(第3版)》第10章 DOM总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010011236/article/details/86547112

DOM 描述了一个层次化的节点树,允许开发人员添加、移除修改页面的某一部分。

10.1、节点层次

DOM 可以将任何 HTML 或 XML 文档描绘成一个由多层节点构成的结构。

所有页面标记则表现为一个以特定节点为根节点的树形结构。

HTML 中的每一段标记都可以通过树中的一个节点来表示:HTML 元素通过元素节点表示,特性通过特性节点表示,文档类型通过文档类型节点表示,注释则通过注释节点表示。

10.1.1、Node 类型

JS 中的所有节点类型都继承自 Node 类型,因此所有节点类型都共享着相同的基本属性和方法。

每个节点都有一个 nodeType 属性,用于表明节点的类型。用来表示节点类型的 Node 类型下的12个数值常量:

  • Node.ELEMENT_NODE(1);
  • Node.ATTRIBUTE_NODE(2);
  • Node.TEXT_NODE(3);
  • Node.CDATA_SECTION_NODE(4);
  • Node.ENTITY_PEFERENCE_NODE(5);
  • Node.ENTITY_NODE(6);
  • Node.PROCESSING_INSTRUCTION_NODE(7);
  • Node.COMMENT_NODE(8);
  • Node.DOCUMENT_NODE(9);
  • Node.DOCUMENT_TYPE_NODE(10);
  • Node.DOCUMENT_FRAGMENT_NODE(11);
  • Node.NOTATION_NODE(12);
console.log(document.nodeType);  // 9

1. nodeName 和 nodeValue 属性

注意:对于元素节点,nodeName 中保存的始终都是元素的标签名,而 nodeValue 的值则始终为 null。

<h1>Hello world!</h1>
<script>

  var h1 = document.getElementsByTagName('h1');
  if (h1[0].nodeType == 1) {
    console.log(h1[0].nodeName); // H1
  }
  
</script>

2.节点关系

每个节点都有 childNodes 属性,其中保存着一个 NodeList 对象。

注意:NodeList 是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。

<div id="container">
  <h1>Wiki</h1>
  <p>A wiki is run using wiki software, otherwise known as a wiki engine. A wiki engine is a type of content management system.</p>
</div>
<script>

  var div = document.getElementById('container');
  var firstChild = div.childNodes[0];
  var secondChild = div.childNodes.item(0);
  console.log(firstChild === secondChild);  // true
  var count = div.childNodes.length;
  console.log(div.childNodes);  // NodeList(5) [text, h1, text, p, text]
  console.log(count);                       // 5

</script>

每一个节点都有 parentNode 属性,该属性指向文档树中的父节点。

  • previousSibling:和该节点在同一列表中的前一个节点,该列表中第一个节点的 previousSibling 为 null;
  • nextSibling:和该节点在同一列表中的后一个节点,该列表中最后一个节点的 nextSibling 为 null。

当节点包含一个或多个子节点时,hasChildNodes() 方法返回 true。

<div id="container">
  <h1>Wiki</h1>
  <p>A wiki is run using wiki software, otherwise known as a wiki engine. A wiki engine is a type of content management system.</p>
</div>
<script>
  var div = document.getElementById('container');
  console.log(div.hasChildNodes());  // true
</script>

3.操作节点

(1)appendChild() 方法,用于向 childNodes 列表的末尾添加一个节点。

注意:如果传入 appendChild() 中的节点已经是文档的一部分,那结果就是将该节点从原来的位置转移到新位置。

(2)insertBefore() 把节点放在 childNodes 列表中某个特定的位置,该方法接受两个参数:要插入的节点作为参照的节点

(3)replaceChild() 替换节点,该方法接受两个参数:要插入的节点要替换的节点;该方法返回要替换的节点

(4)removeChild() 移除节点,该方法只接受一个参数:要移除的节点;该方法返回移除的节点

<div id="container">
    <h1>Wiki</h1>
    <p>A wiki is run using wiki software</p>
    <p>otherwise known as a wiki engine</p>
</div>
<script>
    var div = document.getElementById('container');
    var h1 = document.getElementsByTagName('h1')[0];
    var p =document.getElementsByTagName('p');
    //div.appendChild(h1); // h1会在第三行显示
    div.insertBefore(h1, p[1]); // h1会在第二行显示
    h2.innerHTML = 'Baidu';
    div.replaceChild(h2, h1); // 替换节点,该方法返回被替换的节点
    div.removeChild(h2);  // h2元素被移除
</script>

4.其他方法

所有节点类型都有的两个方法:(1)cloneNode();(2)normalize()。

(1)cloneNode() 用于复制节点,该方法只接受一个布尔值参数。如果为 true,则表示执行深复制(复制节点及子节点);如果为 false,则表示执行浅复制(只复制节点本身)。

<body>
    <div id="container">
        <ul>
            <li>item 1</li>
            <li>item 2</li>
            <li>item 3</li>
        </ul>
    </div>
<script>

    var body = document.body;
    var div = document.getElementById('container');

    var deepList = div.cloneNode(true);
    console.log(deepList);
    body.appendChild(deepList);

    var shallowList = div.cloneNode(false);
    console.log(shallowList);

</script>

(2)normalize() 处理文档树中的文本节点。当某个节点调用该方法时,就会在该节点的后代节点中查找 出现文本节点不包含文本 或 接连出现两个文本节点 的情况,则进行删除。

10.1.2、Document 类型

document 对象是 HTMLDocument(继承自 Document 类型)的一个实例,表示整个HTML页面。而且,document 对象是 window 对象的一个属性,因此可以将其作为全局对象来访问。Document 节点具有下列特征:

  • nodeType 的值为 9
  • nodeName 的值为 "#document"
  • nodeValue 的值为 null
  • parentNode 的值为 null
  • ownerDocument 的值为 null
  • 其子节点可能是一个 DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction 或 Comment。

1.文档的子节点

documentElement 属性:无论 HTML 页面中是否存在 <!DOCTYPE> ,该属性始终指向 <html> 元素。

<html>
    <body>
        
    </body>
    <script>
        
        var rootHtml = document.documentElement;
        console.log(rootHtml === document.childNodes[0]); // true
        console.log(rootHtml === document.firstChild);    // true
        
    </script>
</html>

body 属性直接指向 <body> 元素。

注意:所有浏览器都支持 document.documentElement 和 document.body 属性。

可以通过 docoument.doctype 属性来获取 <!DOCTYPE> 标签

2.文档信息

document  对象还有一些标准的 Document 对象所没有的属性:

(1)title:<title>

(2)与网页请求有关:URL、domain、referrer

URL 属性包含页面完整的 URL;

domain 属性中只包含页面的域名;

referrer 属性中则保存着链接到当前页面的那个页面的 URL。

3.查找元素

getElementById():只返回文档中第一次出现的元素

getElementsByTagName():返回文档中所有同名元素,并返回一个 HTMLCollection 对象。 HTMLCollection 对象可以通过调用 namedItem() 方法来根据 name 特性取得集合中的项。

getElementsByName():返回带有给定 name 特性的所有元素。

4.特殊集合

除了属性和方法,document 对象还有一些特殊的集合:

  • document.anchors,包含文档中所有带 name 特性的 <a> 元素
  • document.forms,包含文档中所有的 <form> 元素,与 document.getElementsByTagName("form")结果相同
  • document.images,包含文档中所有的 <img> 元素,与 document.getElementsByTagName("img")结果相同
  • document.links,包含文档中所有带 href 特性的 <a> 元素。

6.文档写入

将输出流写入到网页中:(1)write()、(2)writeln()、(3)open、(4)close()。

(1)write():原样写入

(2)writeln():在字符串的末尾添加一个换行符(\n)

注意:上述两个方法在页面被加载的过程中,可以使用这两个方法向页面中动态地加入内容。

注意:如果在文档加载结束后在调用 document.write() ,那么输出的内容将会重写整个页面。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Js高级程序设计 第10章测试</title>
</head>
<body>
  <p>The current date and time is:</p>
  <script>
    document.write("<strong>" + (new Date()).toString() + "</strong>"); // 输出内容添加到<p>元素的下一行

    // 当文档加载结束后调用 document.write(),则会重写这个页面
    window.onload = function() {
      document.write("<strong>" + (new Date()).toString() + "</strong>"); // 整个页面只显示该内容
    };
  </script>
</body>
</html>

open() 和 close() 方法分别用于打开和关闭网页的输出流。如果是在页面加载期间使用 write() 或 writeln() 方法,则不需要用到这两个方法。

10.1.3、Element 类型

Element 类型用于表现 XML 或 HTML 元素,提供了对元素标签名子节点特性的访问。Element 节点具有如下特征:

  • nodeType 的值为 1;
  • nodeName 的值为元素的标签名;
  • nodeValue 的值为 null;
  • parentNode 可能是 Document 或 Element;
  • 其子节点可能是 Element、Text、Comment、ProcessingInstruction、CDATASection 或 EntityReference。

访问元素的标签名可以使用属性:nodeName 或 tagName

<div id="myDiv"></div>
<script>
  var myDiv = document.getElementById('myDiv');
  console.log(myDiv.nodeName);                    // DIV
  console.log(myDiv.nodeName === myDiv.tagName);  // true
</script>

1.HTML 元素

所有 HTML 元素都由 HTMLElement 类型表示,不是直接通过这个类型,也是通过它的子类型来表示。HTMLElement 类型直接继承自 Element 类型并添加了一些属性。添加的属性分别对应于每个 HTML 元素中都存在的下列标准特性:

  • id,元素在文档中的唯一标识符
  • title,有关元素的附加说明信息,鼠标移动到该元素显示的提示信息
  • lang,元素内容的语言代码,很少使用
  • dir,语言的方向,值为 "ltr"(left-to-right,从左至右)或 "rtl"(right-to-left,从右至左),很少使用。修改后即可体现。
  • className,与元素的 class 特性对应
<div id="myDiv" class="bd" title="body text" lang="en" dir="ltr">测试</div>
<script>
  var myDiv = document.getElementById('myDiv');
  console.log(myDiv.nodeName); // DIV
  console.log(myDiv.id);       // 'myDiv'
  console.log(myDiv.className);    // 'bd'
  console.log(myDiv.title);    // 'body text'
  console.log(myDiv.lang);     // 'en'
  console.log(myDiv.dir);      // 'ltr'
</script>

2.提取特性

操作元素特性的三个方法:(1)getAttribute();(2)setAttribute();(3)removeAttribute()。

(1)getAttribute() :获取元素特性的值,如果该特性不存在,则返回 null。元素公认的特性可以通过属性来访问,自定义的特性则只能通过该方法来访问。

注意:根据 H5 规范,自定义特性应该加上 data- 前缀以便验证。

<div id="myDiv" class="bd" title="body text" lang="en" dir="ltr" my_special_attribute="hello!">测试</div>
<script>
  var myDiv = document.getElementById('myDiv');

  console.log(myDiv.id);  // 'myDiv'
  console.log(myDiv.className); // 'bd'
  console.log(myDiv.getAttribute('my_special_attribute')); // 'hello!'
</script>

有两类特殊的特性,它们虽然有对于的属性名,单属性的值与通过 getAttribute() 返回的值并不相同。

第一类特性就是 style,用于通过 CSS 为元素指定样式。在通过 getAttribute() 访问时,返回的是 style 特性值中包含的是 CSS 文本;而通过属性来访问它则返回一个对象。

第二类特性就是 onclick 这样的事件处理程序。通过 getAttribute() 访问时,返回的是 onclick 特性值中包含相应代码的字符串;而通过属性来访问它则会返回一个 JS 函数(如果未在元素中指定相应特性,则返回 null)。

<div id="myDiv2" style="width:400px;height:400px;background-color:red;">测试2</div>
<button id="button" onclick="alert('hello!');">按钮</button>
<script>
  // 特殊的特性:style
  var myDiv2 = document.getElementById('myDiv2');

  console.log(myDiv2.getAttribute('style'));  // 'width:400px;height:400px;background-color:red;'
  console.log(myDiv2.style);  // 返回对象
  
  // 特殊特性:onclick(时间处理程序)
  var button = document.getElementById('button');
  console.log(button.getAttribute('onclick'));  // 返回代码
  console.log(button.onclick);  // 返回函数
</script>

3.设置特性

setAttribute() 设置特性,该方法接受两个参数:要设置的特性 和 值。

注意:通过该方法设置的特性名会被同一转换为小写。

removeAttribute() 彻底删除特性。

4.attributes 属性

Element 类型是使用 attributes 属性的唯一一个 DOM 节点类型。attributes 属性中包含一个 NamedNodeMap,与 NodeList 类似,也是一个 “动态” 的集合。NamedNodeMap 对象拥有下列方法:

  • getNamedItem(name):返回 nodeName 属性等于 name 的节点;
  • removeNamedItem(name):从列表中移除 nodeName 属性等于 name 的节点;
  • setNamedItem(name):向列表中添加节点,以节点的 nodeName 属性为索引;
  • item(pos):返回位于数字 pos 位置处的节点。

attributes 属性中包含一系列节点,每个节点的 nodeName 就是特性的名称,而节点的 nodeValue 就是特性的值。

注意:遍历元素的特性,则使用 attributes 属性非常方便。

<div id="myDiv" class="bd" title="body text" lang="en" dir="ltr" my_special_attribute="hello!">测试</div>
<script>
  var myDiv = document.getElementById('myDiv');

  function outputAttributes(element) {
    var pairs = new Array(),
      attrName,
      attrValue,
      i,
      len;

    for (i = 0, len = element.attributes.length; i < len; i++) {
      attrName = element.attributes[i].nodeName;
      attrValue = element.attributes[i].nodeValue;
      pairs.push(attrName + "\"" + attrValue + "\"");
    }

    return pairs;
  }

  console.log(outputAttributes(myDiv));
</script>

注意

  • 针对 attributes 对象中的特性,不同浏览器返回的顺序不同。
  • IE7 及更早的版本会返回 HTML 元素中所有可能的特性,包括没有指定的特性。而每个特性节点有一个 specified 属性,如果这个属性值为 true,则表示在元素中指定了该特性;如果这个属性值为 false,则表示在元素中没有指定该特性。

5.创建元素

使用 document.createElement() 方法可以创建新元素,该方法只接受一个参数:要创建元素的标签名。

在使用 createElement() 方法创建新元素的同时,也为新元素设置了 ownerDocument 属性。

在 IE 中可以为这个方法传入完整的元素标签,也可以包含属性。

6.元素的子节点

元素可以有任意树木数目的子节点和后代节点,因为元素可以是其他元素的子节点。元素的 childNodes 属性中包含了它的所有子节点,这些子节点可能是元素、文本节点、注释或处理指令。

10.1.4、Text 类型

文本节点由 Text 类型表示,包含的是可以照字面解释的纯文本内容。纯文本中可以包含转义后的 HTML 字符,但不能包含 HTML 代码。Text 节点具有如下特征:

  • nodeType 的值为 3;
  • nodeName 的值为 "#text";
  • nodeValue 的值为节点所包含的文本;
  • parentNode 是一个 Element;
  • 不支持(没有)子节点。

可以通过 nodeValue 属性或 data 属性访问 Text 节点中包含的文本,这两个属性中包含的值相同。

可以使用下列方法操纵节点中的文本:

  • appendData(text):将 text 添加到节点的末尾;
  • deleteDate(offset, count):从 offset 指定的位置开始删除 count 个字符;
  • insertData(offset, text):在 offset 指定的位置插入 text;
  • replaceData(offset, count, text):用 text 替换从 offset 指定的位置开始到 offset + count 之前的文本;
  • splitText(offset):从 offset 指定的位置将当前文本节点分成两个文本节点;
  • substringData(offset, count):提取从 offset 指定的位置开始到 offset+count 之前处的字符串。

此外,文本节点还有一个 length 属性,保存着节点中字符的数目。且 nodeValue.length = data.length。

默认情况下,每个可以包含内容的元素最多只能有一个文本节点,而且必须确实有内容存在。

<div id="text">there is a boy.</div>
<script>
  var text = document.getElementById('text').firstChild;
  console.log(text.nodeValue.length);  // 15
  console.log(text.nodeType);  // 3
  console.log(text.nodeName);  // "#text"
  console.log(text.nodeValue); // "there is a boy."
  console.log(text.parentNode); // div
  text.deleteData(0, 5);
  console.log(text.nodeValue); // " is a boy."
  text.insertData(0, 'there');
  console.log(text.nodeValue); // "there is a boy."
  text.replaceData(0, 5, 'abcdefg');
  console.log(text.nodeValue); // "abcdefg is a boy."
  text.splitText(4);
  console.log(text.nodeValue); // "abcd"
  console.log(text.substringData(0, 1)); // "a"
</script>

1.创建文本节点

document.createTextNode():接受一个参数——要插入节点中的文本。

注意:一般情况下,每个元素只有一个文本子节点。如果两个文本节点是同胞节点,那么这两个节点中的文本就会连起来显示,中间不会有空格。

<script>
  var div = document.createElement('div');
  div.className = 'addText';

  var oneTextNode = document.createTextNode('hello world!');
  div.appendChild(oneTextNode);

  var anotherTextNode = document.createTextNode('google!');
  div.appendChild(anotherTextNode);

  document.body.appendChild(div);
</script>

2.规范化文本节点

相邻文本节点合并:在一个包含两个或多个文本节点的父元素上调用 normalize() 方法,会将所有文本节点合并成一个节点。

<script>
  var element = document.createElement('div');
  element.className = 'message';

  var textNode = document.createTextNode('Hello world!');
  element.appendChild(textNode);

  var anotherTextNode = document.createTextNode('Yippee!');
  element.appendChild(anotherTextNode);

  document.body.appendChild(element);

  console.log(element.childNodes.length); // 2

  element.normalize();

  console.log(element.childNodes.length);  // 1
  console.log(element.firstChild.nodeValue); // 'Hello world!Yippee!'
</script>

注意:浏览器在解析文档时永远不会创建相邻的文本节点。这种情况只会在作为执行 DOM 操作的结果出现。

3.分割文本节点

splitText():分割文本节点,原来的文本节点将包含从开始到指定位置之前的内容,新文本节点将包含剩下的文本。

10.1.5、Comment 类型

注释在 DOM 中是通过 Comment 类型来表示的。Comment 节点具有下列特征:

  • nodeType 的值为 8;
  • nodeName 的值为 "#comment";
  • nodeValue 的值为注释的内容;
  • parentNode 可能是 Document 或 Element;
  • 不支持(没有)子节点。

Comment 类型与 Text 类型继承自相同的基类,因此它拥有除 splitText() 之外的所有字符串操作方法。

10.1.6、 CDATASection 类型

CDATASection 类型继承自 Text 类型,因此拥有除 splitText() 之外的所有字符串操作方法。CDATASection 节点具有下列特征:

  • nodeType 的值为 4;
  • nodeName 的值为 "#cdata-section";
  • nodeValue 的值是 CDATA 区域中的内容;
  • parentNode 可能是 Document 或 Element;
  • 不支持(没有)子节点。

参考文献

[1]《JavaScript高级程序设计(第3版)》

猜你喜欢

转载自blog.csdn.net/u010011236/article/details/86547112