第10章 DOM(一)

        DOM(文档对象模型)是针对 HTML 和 XML 文档的一个 API (应用程序编程接口)。DOM 描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分。

1 节点层次

1.1 节点类型

<html> 
 <head> 
 <title>Sample Page</title> 
 </head> 
 <body> 
 <p>Hello World!</p> 
 </body> 
</html>

文档节点是每个文档的根节点HTML 页面中, 文档元素始终都是 <html>元素。
每一段标记都可以通过树中的一个节点来表示: HTML 元素通过元素节点表示,特性( attribute ) 通过特性节点表示,文档类型通过文档类型节点表示,而注释则通过注释节点表示。总共有 12 种节点 类型,这些类型都继承自一个基类型——Node 类型
Node.ELEMENT_NODE (1)
Node.ATTRIBUTE_NODE (2)
Node.TEXT_NODE (3)
Node.CDATA_SECTION_NODE (4)
Node.ENTITY_REFERENCE_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)

1.2 Node类型

3a2da5692b2e065a06f6b0037844f9da.png

d143a316b83862c8e3d51019f267adba.png

1.2.1 节点属性

每个节点都有一个 nodeType 属性,用于表明节点的类型。
对于元素节点, nodeName 中保存的始终都是元素的标签名,而 nodeValue 的值则始终为 null
if (someNode.nodeType == Node.ELEMENT_NODE){ //在 IE 中无效
 alert("Node is an element."); 
}

if (someNode.nodeType == 1){ //适用于所有浏览器
 alert("Node is an element."); 
}

1.2.2 节点关系

  • 所有节点都有的最后一个属性是 ownerDocument,该属性指向表示整个文档的文档节点。这种关系表示的是任何节点都属于它所在的文档。
  • 每个节点都有一个 parentNode 属性,该属性指向文档树中的父节点
  • 每个节点都有一个 childNodes 属性,其中保存着一个 NodeList 对象。NodeList 是一种类数组对象,用于保存一组有序的节点。可以通过方括号语法来访问 NodeList 的值,而且这个对象也有 length 属性,但它并不是 Array 的实例。hasChildNodes()这个方法在节点包含一或多个子节点的情况下返回 true。
  • 父节点的 firstChild lastChild属性分别指向其 childNodes 列表中的第一个和最后一个节点。如果没有子节点,那么 firstChild lastChild 的值均为 null
  • 列表中第一个节点的 previousSibling 属性值为 null,而列表中最后一个节点的 nextSibling 属性的值同样也为 null。
var firstChild = someNode.childNodes[0]; //可以通过方括号,也可以使用 item()方法
var secondChild = someNode.childNodes.item(1); 
var count = someNode.childNodes.length;

//NodeList转为真数组
function convertToArray(nodes){ 
 var array = null; 
 try { 
 array = Array.prototype.slice.call(nodes, 0); //针对非 IE 浏览器
 } catch (ex) { 
 array = new Array(); 
 for (var i=0, len=nodes.length; i < len; i++){ 
 array.push(nodes[i]); //IE
 } 
 } 
 return array; 
}
Element Traversal API DOM 元素添加了以下 5 个属性。
childElementCount :返回子元素(不包括文本节点和注释)的个数。
firstElementChild :指向第一个子元素; firstChild 的元素版。
lastElementChild :指向最后一个子元素; lastChild 的元素版。
previousElementSibling :指向前一个同辈元素; previousSibling 的元素版。
nextElementSibling :指向后一个同辈元素; nextSibling 的元素版。

1.2.3 操作节点

最常用的方法是appendChild(),用于向 childNodes 列表的末尾添加一个节点。
如果传入到 appendChild() 中的节点已经是文档的一部分了,那结果就是将该节点从原来的位置转移到新位置。
var returnedNode = someNode.appendChild(newNode); 
alert(returnedNode == newNode); //true:返回值为插入的节点 
alert(someNode.lastChild == newNode); //true

//someNode 有多个子节点
var returnedNode = someNode.appendChild(someNode.firstChild); 
alert(returnedNode == someNode.firstChild); //false 
alert(returnedNode == someNode.lastChild); //true:由第一个子节点变成最后一个子节点
如果需要把节点放在 childNodes 列表中某个特定的位置上,那么可以使用insertBefore()方法。这个方法接受两个参数:要插入的节点和作为参照的节点。
如果参照节点是null,则 insertBefore() appendChild() 执行相同的操作。
//插入后成为第一个子节点
var returnedNode = someNode.insertBefore(newNode, someNode.firstChild); 
alert(returnedNode == newNode); //true:返回节点为插入的节点 
alert(newNode == someNode.firstChild); //true

//插入到最后一个子节点前面
returnedNode = someNode.insertBefore(newNode, someNode.lastChild); 
alert(newNode == someNode.childNodes[someNode.childNodes.length-2]); //true

//插入后成为最后一个子节点
returnedNode = someNode.insertBefore(newNode, null); 
alert(newNode == someNode.lastChild); //true

replaceChild() 方法接受的两个参数是:要插入的节点和要替换的节点。
要替换的节点将由这个方法返回并从文档树中被移除,同时由要插入的节点占据其位置。
//替换第一个子节点
var returnedNode = someNode.replaceChild(newNode, someNode.firstChild);
removeChild() 方法。这个方法接受一个参数,即要移除的节点。被移除的节点将成为方法的返回值。
通过 removeChild() 移除的节点仍然为文档所有,只不过在文档中已经没有了自己的位置。
要使用这几个方法必须先取得父节点(使用 parentNode 属性)。
//移除第一个子节点
var formerFirstChild = someNode.removeChild(someNode.firstChild);

cloneNode(),用于创建调用这个方法的节点的一个完全相同的副本在参数为 true的情况下,执行深复制,也就是复制节点及其整个子节点树;在参数为 false 的情况下,执行浅复制,即只复制节点本身。

cloneNode()方法不会复制添加到 DOM 节点中的 JavaScript 属性,例如事件处理程序等。

<ul> 
 <li>item 1</li> 
 <li>item 2</li> 
 <li>item 3</li> 
</ul>

var deepList = myList.cloneNode(true); 
alert(deepList.childNodes.length); //3(IE < 9)或 7(其他浏览器)
var shallowList = myList.cloneNode(false); 
alert(shallowList.childNodes.length); //0
normalize(),这个方法唯一的作用就是处理文档树中的文本节点。如果找到了空文本节点,则删除它;如果找到相邻的文本节点,则将它们 合并为一个文本节点。在该节点的后代节点中查找上述两种情况。 

1.2.4 节点比较

isSameNode()isEqualNode() 。这两个方法都接受一个节点参数,并在传入节点与引用的节点相同或相等时返回 true。所谓相同,指的是两个节点引用的是同一个对象。所谓相等,指的是两个节点是相同的类型,具有相等的属性(nodeName、nodeValue等等),而且它们的 attributes 和 childNodes 属性也相等(相同位置包含相同的值)。
var div1 = document.createElement("div"); 
div1.setAttribute("class", "box"); 
var div2 = document.createElement("div"); 
div2.setAttribute("class", "box"); 

alert(div1.isSameNode(div1)); //true 
alert(div1.isEqualNode(div2)); //true 
alert(div1.isSameNode(div2)); //false

2 Document类型

        JavaScript 通过 Document 类型表示文档。在浏览器中, document 对象是 HTMLDocument (继承 自 Document 类型)的一个实例,表示整个 HTML 页面。而且, document 对象是 window 对象的一个属性
Document 节点具有下列特征:
nodeType 的值为 9
nodeName 的值为 "#document"
nodeValue 的值为 null
parentNode 的值为 null

2.1 文档的子节点

  • documentElement属性,该属性始终指向 HTML 页面中的<html>元素。
  • document 对象还有一个 body 属性,直接指向<body>元素。
  • doctype 属性取得对<!DOCTYPE>的引用。浏览器对 document.doctype 的支持不一致。
我们都用不着在 document 对象上调用 appendChild() removeChild() 和replaceChild()方法,因为文档类型(如果存在的话)是只读的
<html> 
 <body> 
 
 </body> 
</html>

var html = document.documentElement; //取得对<html>的引用
alert(html === document.childNodes[0]); //true 
alert(html === document.firstChild); //true

//head属性
var head = document.head || document.getElementsByTagName("head")[0];

2.2 文档信息

  • 第一个属性就是 title,包含着<title>元素中的文本——显示在浏览器窗口的标题栏或标签页上。
  • 3 个属性都与对网页的请求有关,它们是 URLdomain 和 referrer所有这些信息都存在于请求的 HTTP 头部。
  • document 对象引入了 readyState 属性。 loading,正在加载文档;complete ,已经加载完文档。
  • 在标准模式下,document. compatMode 的值等于"CSS1Compat",而在混杂模式下,document.compatMode 的值等于"BackCompat"。(渲染页面的模式)
  • 通过 document.documentMode 属性可以知道给定页面使用的是什么文档模式文档模式决定了你可以使用哪个级别的 CSS,可以在 JavaScript 中使用哪些 API,以及如何对待文档类型(doctype)
  • charset 属性表示文档中实际使用的字符集

        只有 domain 是可以设置的。但由于安全方面的限制,也并非可以给 domain 设置任何值。如果 URL 中包含一个子域名,例如 p2p.wrox.com,那么就只能将 domain 设置为"wrox.com"。

        浏览器对 domain 属性还有一个限制,即如果域名一开始是“松散的”(loose),那么不能将它再设置为“紧绷的”(tight

//取得文档标题
var originalTitle = document.title; 
//设置文档标题
document.title = "New page title";

//取得完整的 URL
var url = document.URL; 
//取得域名
var domain = document.domain; 
//取得来源页面的 URL
var referrer = document.referrer;

//假设页面来自 p2p.wrox.com 域
document.domain = "wrox.com"; // 成功
document.domain = "nczonline.net"; // 出错!

//假设页面来自于 p2p.wrox.com 域
document.domain = "wrox.com"; //松散的(成功)
document.domain = "p2p.wrox.com"; //紧绷的(出错!)

if (document.readyState == "complete"){ 
 //执行操作
}

alert(document.charset); //"UTF-16" 
document.charset = "UTF-8";

2.3 查找元素

getElementById(),接收一个参数:要取得的元素的 ID。如果找到相应的元素则返回该元素,如果不存在带有相应 ID 的元素,则返回 null

  • 这里的 ID 必须与页面中元素的 id 特性(attribute)严格匹配,包括大小写。
  • 如果页面中多个元素的 ID 值相同,getElementById()只返回文档中第一次出现的元素。
<div id="myDiv">Some text</div>

var div = document.getElementById("myDiv"); //取得<div>元素的引用

getElementsByTagName()。接受一个参数,即要取得元素的标签名,而返回的是包含零或多个元素的 NodeList

  • 可以使用方括号语法或 item()方法来访问 HTMLCollection 对象中的项。而这个对象中元素的数量则可以通过其 length 属性取得。
  • namedItem(),使用这个方法可以通过元素的 name 特性取得集合中的项。对数值索引就会调用 item(),而对字符串索引就会调用 namedItem()
  • 要想取得文档中的所有元素,可以向 getElementsByTagName()中传入"*"
var images = document.getElementsByTagName("img");
alert(images.length); //输出图像的数量
alert(images[0].src); //输出第一个图像元素的 src 特性
alert(images.item(0).src); //输出第一个图像元素的 src 特性

<img src="myimage.gif" name="myImage">
var myImage = images.namedItem("myImage");
//等价于
var myImage = images["myImage"];

var allElements = document.getElementsByTagName("*");
getElementsByName() 这个方法会返回带有给定 name 特性的所有元素
<fieldset> 
 <legend>Which color do you prefer?</legend> 
 <ul> 
 <li><input type="radio" value="red" name="color" id="colorRed"> 
 <label for="colorRed">Red</label></li> 
 <li><input type="radio" value="green" name="color" id="colorGreen"> 
 <label for="colorGreen">Green</label></li> 
 <li><input type="radio" value="blue" name="color" id="colorBlue"> 
 <label for="colorBlue">Blue</label></li> 
 </ul> 
</fieldset>

var radios = document.getElementsByName("color");
querySelector() 方法接收一个 CSS 选择符返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回 null
通过 Document 类型调用 querySelector() 方法时,会在文档元素的范围内查找匹配的元素。而
通过 Element 类型调用 querySelector() 方法时,只会在该元素后代元素的范围内查找匹配的元素。
//取得 body 元素
var body = document.querySelector("body"); 
//取得 ID 为"myDiv"的元素
var myDiv = document.querySelector("#myDiv");

querySelectorAll()方法接收的参数是一个 CSS 选择符,返回的是一个 NodeList 的实例。

要取得返回的 NodeList 中的每一个元素,可以使用 item()方法,也可以使用方括号语法

//取得所有<p>元素中的所有<strong>元素
var strongs = document.querySelectorAll("p strong");

var i, len, strong; 
for (i=0, len=strongs.length; i < len; i++){ 
 strong = strongs[i]; //或者 strongs.item(i) 
 strong.className = "important"; 
}
matchesSelector() 这个方法接收一个参数,即 CSS 选择符,如果调用元素与该选择符匹配,返回 true ;否则,返回 false 不同浏览器实现有所不同。
function matchesSelector(element, selector){ 
 if (element.matchesSelector){ 
 return element.matchesSelector(selector); 
 } else if (element.msMatchesSelector){ 
 return element.msMatchesSelector(selector); 
 } else if (element.mozMatchesSelector){ 
 return element.mozMatchesSelector(selector); 
 } else if (element.webkitMatchesSelector){ 
 return element.webkitMatchesSelector(selector); 
 } else { 
 throw new Error("Not supported."); 
 } 
} 
if (matchesSelector(document.body, "body.page1")){ 
 //执行操作
}
getElementsByClassName() 方法接收一个参数,即一个包含一或多个类名的字符串,返回带有指定类的所有元素的 NodeList 。(H5)
document 对象上调用getElementsByClassName()始终会返回与类名匹配的所有元素,在元素上调用该方法就只会返回后代元素中匹配的元素。
//取得所有类中包含"username"和"current"的元素,类名的先后顺序无所谓
var allCurrentUsernames = document.getElementsByClassName("username current"); 
//取得 ID 为"myDiv"的元素中带有类名"selected"的所有元素
var selected = document.getElementById("myDiv").getElementsByClassName("selected");

2.4 特殊集合

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

2.5 DOM 一致性检测

DOM1 级只为 document.implementation 规定了一个方法,即 hasFeature() 。这个方法接受两个参数:要检测的 DOM 功能的名称及版本号。最好除了检测hasFeature()之外,还同时使用能力检测。
var hasXmlDom = document.implementation.hasFeature("CSS", "2.0");
var supportsDOM2Core = document.implementation.hasFeature("Core", "2.0");

isSupported()方法用于确定当前节点具有什么能力。两个参数:特性名和特性版本号。

if (document.body.isSupported("HTML", "2.0")){ 
 //执行只有"DOM2 级 HTML"才支持的操作
}

2.6 文档写入

write()原样写入,而 writeln()则会在字符串的末尾添加一个换行符(\n)。如果在文档 加载结束后再调用 document.write(),那么输出的内容将会重写整个页面

  • 方法 open()close()分别用于打开和关闭网页的输出流。
<html> 
<head> 
 <title>document.write() Example</title> 
</head> 
<body> 
 <p>The current date and time is: 
 <script type="text/javascript"> 
 <!-- 原样输出 -->
 document.write("<strong>" + (new Date()).toString() + "</strong>"); 
 <!-- 字符串"</script>"需加入转义字符\ -->
 document.write("<script type=\"text/javascript\" src=\"file.js\">" + 
 "<\/script>");
 <!-- Hello world!重写整个页面 -->
 window.onload = function(){ 
   document.write("Hello world!"); 
 };
 </script> 
 </p> 
</body> 
</html>
读模式下, innerHTML 属性返回与调用元素的所有子节点(包括元素、注释和文本节点)对应的 HTML 标记。在写模式下, innerHTML 的值会被解析为 DOM 子树,替换调用元素原来的所有子节点。
  • 在大多数浏览器中,通过 innerHTML 插入<script>元素并不会执行其中的脚本。但是,大多数浏览器都支持以直观的方式通过 innerHTML 插入<style>元素。
  • 并不是所有元素都支持 innerHTML 属性。不支持 innerHTML 的元素有:<col><colgroup><frameset><head><html><style><table><tbody><thead><tfoot><tr>
  • 在设置 innerHTML outerHTML 时,就会创建一个 HTML解析器。这个解析器是在浏览器级别的代码(通常是 C++ 编写的)基础上运行的,因此比执行 JavaScript快得多
  • 最好的做法是单独构建字符串,然后再一次性地将结果字符串赋值给 innerHTML
div.innerHTML = "Hello world!";

div.innerHTML = "Hello & welcome, <b>\"reader\"!</b>";
//解析后
<div id="content">Hello &amp; welcome, <b>&quot;reader&quot;!</b></div>

//插入<style>
div.innerHTML = "<style type=\"text/css\">body {background-color: red; }</style>";
读模式下, outerHTML 返回调用它的元素及所有子节点 HTML 标签。在写模式下, outerHTML会根据指定的 HTML 字符串创建新的 DOM 子树,然后用这个 DOM 子树完全替换调用元素。
div.outerHTML = "<p>This is a paragraph.</p>";
插入标记的最后一个新增方式是 insertAdjacentHTML()方法,它接收两个 参数:插入位置和要插入的 HTML 文本。
//作为前一个同辈元素插入
element.insertAdjacentHTML("beforebegin", "<p>Hello world!</p>"); 
//作为第一个子元素插入
element.insertAdjacentHTML("afterbegin", "<p>Hello world!</p>"); 
//作为最后一个子元素插入
element.insertAdjacentHTML("beforeend", "<p>Hello world!</p>"); 
//作为后一个同辈元素插入
element.insertAdjacentHTML("afterend", "<p>Hello world!</p>");
innerText 读取值时,它会按照由浅入深的顺序,将子文档树中的所有文本拼接起来。在通过innerText 写入值时,结果会删除元素的所有子节点,插入包含相应文本值的文本节点。
  • 设置innerText属性的同时,也对文本中存在的 HTML 语法字符(小于号、大于号、引号及和号)进行了编码
  • Firefox 虽然不支持 innerText,但支持作用类似的 textContent 属性。innerText 会忽略行内的样式和脚本,而 textContent 则会像返回其他文本一样返回行内的样式和脚本代码。
<div id="content"> 
 <p>This is a <strong>paragraph</strong> with a list following it.</p> 
 <ul> 
 <li>Item 1</li> 
 <li>Item 2</li> 
 <li>Item 3</li> 
 </ul> 
</div>

//读取
This is a paragraph with a list following it. 
Item 1 
Item 2 
Item 3

//设置
div.innerText = "Hello world!";
//运行后
<div id="content">Hello &amp; welcome, &lt;b&gt;&quot;reader&quot;!&lt;/b&gt;</div>

//兼容性处理
function setInnerText(element, text){ 
 if (typeof element.textContent == "string"){ 
 element.textContent = text; 
 } else { 
 element.innerText = text; 
 } 
}
读取文本值时, outerText innerText 的结果完全一样。但在模式下, outerText 就完全不同了:outerText 不只是替换调用它的元素的子节点,而是会替换整个元素。
div.outerText = "Hello world!";
//等价于
var text = document.createTextNode("Hello world!"); 
div.parentNode.replaceChild(text, div);

2.7 焦点管理

document.activeElement 属性,这个属性始终会引用 DOM 中当前获得了焦点的元素
默认情况下,文档刚刚加载完成时, document.activeElement 中保存的是 document.body
素的引用。文档加载期间 document.activeElement 的值为 null
var button = document.getElementById("myButton"); 
button.focus(); 
alert(document.activeElement === button); //true
document.hasFocus() 方法,这个方法用于确定文档是否获得了焦点
var button = document.getElementById("myButton");
button.focus(); 
alert(document.hasFocus()); //true

Element类型

Element 节点具有以下特征:
nodeType 的值为 1
nodeName 的值为元素的标签名;(大写)
nodeValue 的值为 null
parentNode 可能是 Document Element
要访问元素的标签名,可以使用 nodeName 属性,也可以使用 tagName 属性。
HTML 中,标签名始终都以全部大写表示;而在 XML (有时候也包括 XHTML ) 中,标签名则始终会与源代码中的保持一致。
<div id="myDiv"></div>

var div = document.getElementById("myDiv"); 
alert(div.tagName); //"DIV" 
alert(div.tagName == div.nodeName); //true

if (element.tagName.toLowerCase() == "div"){ //这样最好(适用于任何文档)
 //在此执行某些操作
}

3.1 HTML 元素

id ,元素在文档中的唯一标识符。
title ,有关元素的附加说明信息,一般通过工具提示条显示出来。
className ,与元素的 class 特性对应,即为元素指定的 CSS 类。
上述这些属性都可以用来取得或修改相应的特性值
<div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>
//读取
var div = document.getElementById("myDiv"); 
alert(div.id); //"myDiv"" 
alert(div.className); //"bd" 
alert(div.title); //"Body text" 
alert(div.lang); //"en" 
alert(div.dir); //"ltr"
//设置
div.id = "someOtherId"; 
div.className = "ft"; 
div.title = "Some other text"; 
div.lang = "fr"; 
div.dir ="rtl";

3.2 元素特性

此要想得到 class 特性值,应该传入"class" 而不是 "className",也可以取得自定义特性。如果给定名称的特性不存在, getAttribute()返回 null。
  • 特性的名称是不区分大小写的。
  • 属性与相应的特性一一对应。有两类特殊的特性,第一类特性就是 style,通过 getAttribute()访问时,返回的 style 特性值中包含的是 CSS 文本,而通过属性来访问它则会返回一个对象。第二类与众不同的特性是 onclick 这样的事件处理程序。通过 getAttribute()访问,则会返回相应代码的字符串。而在访问onclick 属性时,则会返回一个 JavaScript 函数。
var div = document.getElementById("myDiv"); 
alert(div.getAttribute("id")); //"myDiv" 
alert(div.getAttribute("class")); //"bd" :取得类名
alert(div.getAttribute("title")); //"Body text" 
alert(div.getAttribute("lang")); //"en" 
alert(div.getAttribute("dir")); //"ltr"

<div id="myDiv" my_special_attribute="hello!"></div>
var value = div.getAttribute("my_special_attribute");//取得自定义属性
alert(div.my_special_attribute); //undefined(IE 除外)
setAttribute(),这个方法接受两个参数:要设置的特性名和值。
  • DOM 元素添加一个自定义的属性,该属性不会自动成为元素的特性。
  • 通过 setAttribute()方法既可以操作 HTML 特性也可以操作自定义特性。通过这个方法设置的特性名会被统一转换为小写形式,即"ID"最终会变成"id"
div.setAttribute("id", "someOtherId"); 
div.setAttribute("class", "ft"); 
div.setAttribute("title", "Some other text"); 
div.setAttribute("lang","fr"); 
div.setAttribute("dir", "rtl");

div.id = "someOtherId"; 
div.align = "left";
div.mycolor = "red"; 
alert(div.getAttribute("mycolor")); //null(IE 除外)
removeAttribute() ,这个方法用于彻底删除元素的特性。调用这个方法不仅会清除特性的值,而且也会从元素中完全删除特性。
div.removeAttribute("class");

HTML5 规定可以为元素添加非标准的属性,但要添加前缀 data-。添加了自定义属性之后,可以通过元素的 dataset 属性来访问自定义属性的值,只不过属性名没有 data-前缀。

通过自定义数据属性能方便地知道点击来自页面中的哪个部分

<div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>

var div = document.getElementById("myDiv"); 
//取得自定义属性的值
var appId = div.dataset.appId; 
var myName = div.dataset.myname; 
//设置值
div.dataset.appId = 23456; 
div.dataset.myname = "Michael";

setUserData()方法会将数据指定给节点,它接受 3 个参数:要设置的键、实际的数据(可以是任何数据类型)和处理函数。处理函数接受 5 个参数:表示操作类型的数值(1 表示复制,2 表示导入,3 表示删除,4 表示重命名)、数据键、数据值、源节点和目标节点。

document.body.setUserData("name", "Nicholas", function(){});
var value = document.body.getUserData("name");

var div = document.createElement("div"); 
div.setUserData("name", "Nicholas", function(operation, key, value, src, dest){ 
 if (operation == 1){ 
 dest.setUserData(key, value, function(){}); }
}); 
var newDiv = div.cloneNode(true); //cloneNode()复制这个元素时,就会调用处理函数
alert(newDiv.getUserData("name")); //"Nicholas"

3.3 attributes 属性

attributes 属性中包含一个 NamedNodeMap,元素的每一个 特性都由一个 Attr 节 表示,每个节点都保存在 NamedNodeMap 对象中。
下列方法等价于getAttribute()、 removeAttribute() setAttribute() 方法:
getNamedItem (name) :返回 nodeName 属性等于 name 的节点;
removeNamedItem (name) :从列表中移除 nodeName 属性等于 name 的节点;
setNamedItem (node) :向列表中添加节点,以节点的 nodeName 属性为索引;
attributes 属性中包含一系列节点,每个节点的 nodeName 就是特性的名称,而节点的 nodeValue就是特性的值。
//读取
var id = element.attributes.getNamedItem("id").nodeValue;
//等价于
var id = element.attributes["id"].nodeValue;

//设置
element.attributes["id"].nodeValue = "someOtherId";

var oldAttr = element.attributes.removeNamedItem("id");

element.attributes.setNamedItem(newAttr);
如果想要遍历元素的特性 attributes 属性倒是可以派上用场。通过 attributes.length 属性,for 循环会遍历每个特性,将特性的名称和值输出为字符串。
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.join(" "); 
}

3.4 创建元素

使用 document.createElement() 方法可以创建新元素。这个方法只接受一个参数,即要创建元素的标签名。这个标签名在 HTML 文档中不区分大小写。
var div = document.createElement("div");
div.id = "myNewDiv"; //添加特性
div.className = "box";
document.body.appendChild(div);//添加到文档树

var div = document.createElement("<div id=\"myNewDiv\" class=\"box\"></div >");//IE
元素的childNodes 属性中包含了它的所有子节点,这些子节点有可能是元素、文本节点、注释或处理指令。
对于元素间的空格 IE9 及之前版本不会返回文本节点,而其他所有浏览器都会返回文本节点。
<ul id="myList"> 
 <li>Item 1</li> 
 <li>Item 2</li> 
 <li>Item 3</li> 
</ul>

//检查一下 nodeTpye 属性
for (var i=0, len=element.childNodes.length; i < len; i++){ 
 if (element.childNodes[i].nodeType == 1){ 
 //执行某些操作
 } 
}
如果是 IE 来解析这些代码,那么 <ul> 元素会有 3 个子节点,分别是 3 <li> 元素。但如果是在其
他浏览器中, <ul> 元素都会有 7 个元素,包括 3 <li> 元素和 4 个文本节点(表示 <li> 元素之间的空白符)。
children 属性是 HTMLCollection 的实例,只包含元素中同样还是元素的子节点。除此之外, children 属性与 childNodes 没有什么区别。
var childCount = element.children.length; 
var firstChild = element.children[0];

如果想通过某个特定的标签名取得子节点或后代节点该怎么办呢?实际上,元素也支持 getElementsByTagName()方法。
var ul = document.getElementById("myList"); 
var items = ul.getElementsByTagName("li");
调用 contains()方法的应该是祖先节点,接收一个参数,即要 检测的后代节点。如果被检测的节点是后代节点,该方法返回 true;否则,返回 false。
alert(document.documentElement.contains(document.body)); //true
compareDocumentPosition() 也能够确定节点间的关系
 
        在操作类名时,需要通过 className属性添加、删除和替换类名。因为 className 中是一个字符串,所以即使只修改字符串一部分,也必须每次都设置整个字符串的值
        classList 属性是新集合类型 DOMTokenList 的实例。DOMTokenList 有一个表示自己包含多少元素的 length 属性,而要取得每个元素可以使用 item()方法,也可以使用方括号语法。
add( value ) :将给定的字符串值添加到列表中。如果值已经存在,就不添加了。
contains( value ) :表示列表中是否存在给定的值,如果存在则返回 true ,否则返回 false
remove( value ) :从列表中删除给定的字符串。
toggle( value ) :如果列表中已经存在给定的值,删除它;如果列表中没有给定的值,添加它。
//删除"disabled"类
div.classList.remove("disabled"); 
//添加"current"类
div.classList.add("current"); 
//切换"user"类
div.classList.toggle("user"); 
//确定元素中是否包含既定的类名
if (div.classList.contains("bd") && !div.classList.contains("disabled")){ 
 //执行操作
) 
//迭代类名
for (var i=0, len=div.classList.length; i < len; i++){ 
 doSomething(div.classList[i]); 
}

4 Text类型

Text 节点具有以下特征:
nodeType 的值为 3
nodeName 的值为 "#text"
nodeValue 的值为节点所包含的文本;
  • 可以通过 nodeValue 属性或 data 属性访问 Text 节点中包含的文本。在修改文本节点时还要注意,此时的字符串会经过 HTML(或 XML,取决于文档类型)编码。
  • 文本节点还有一个 length 属性,保存着节点中字符的数目。每个可以包含内容的元素最多只能有一个文本节点,而且必须确实有内容存在。
div.firstChild.nodeValue = "Some other message";

//输出结果是"Some &lt;strong&gt;other&lt;/strong&gt; message" 
div.firstChild.nodeValue = "Some <strong>other</strong> message";

<!-- 没有内容,也就没有文本节点 --> 
<div></div> 
<!-- 有空格,因而有一个文本节点 --> 
<div> </div> 
<!-- 有内容,因而有一个文本节点 --> 
<div>Hello World!</div>

4.1 创建文本节点

可以使用 document.createTextNode() 创建新文本节点,这个方法接受一个参数——要插入节点中的文本。
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);

4.2 规范化文本节点

在一个包含两个或多个文本节点的父元素上调用 normalize() 方法,则会将所有文本节点合并成一个节点,结果节点的 nodeValue 等于将合并前每个文本节点的 nodeValue 值拼接起来的值。
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);
 
alert(element.childNodes.length); //2 
element.normalize(); 
alert(element.childNodes.length); //1 
alert(element.firstChild.nodeValue); // "Hello world!Yippee!"

4.3 分割文本节点

splitText()原来的文本节点将包含从开始到指定位置之前的内容,新文本节点将包含剩下的文本。这个方法会 返回一个新文本节点
var element = document.createElement("div"); 
element.className = "message"; 
var textNode = document.createTextNode("Hello world!"); 
element.appendChild(textNode); 
document.body.appendChild(element); 

var newNode = element.firstChild.splitText(5); 
alert(element.firstChild.nodeValue); //"Hello" 
alert(newNode.nodeValue); //" world!" 
alert(element.childNodes.length); //2

5 Comment类型

Comment 节点具有下列特征:
nodeType 的值为 8
nodeName 的值为 "#comment"
nodeValue 的值是注释的内容;
parentNode 可能是 Document Element
Comment 类型与 Text 类型继承自相同的基类,因此它拥有 splitText() 之外的所有字符串操作方法。与 Text 类型相似,也可以通过 nodeValue data 属性来取得注释的内容。
<div id="myDiv"><!--A comment --></div>
var div = document.getElementById("myDiv"); 
var comment = div.firstChild; 
alert(comment.data); //"A comment"
使用 document.createComment() 并为其传递注释文本也可以创建注释节点。如果要访问注释节点,一定要保证它们是 <html> 元素的后代。
var comment = document.createComment("A comment ");

DocumentFragment类型

DOM 规定文档片段 (document fragment)是一种“轻量级”的文档,可以包含和控制节点,但会像完整的文档那样占用额外的资源。虽然不能把文档片段直接添加到文档中,但可以将它作为一个“仓库”来使用。( 内存中更新,再一次性更新页面 )
nodeType 的值为 11
nodeName 的值为 "#document-fragment"
nodeValue 的值为 null
parentNode 的值为 null
创建文档片段,可以使用document.createDocumentFragment() 方法。
var fragment = document.createDocumentFragment();
  • 文档片段继承了 Node 的所有方法。
  • 添加到文档片段中的新节点同样也不属于文档树。实际上只会将文档片段的所有子节点添加到相应位置上;文档片段本身永远不会成为文档树的一部分。
  • 可以像下面这样使用一个文档片段来保存创建的列表项,然后再一次性将它们添加到文档中。
<ul id="myList"></ul>

var fragment = document.createDocumentFragment(); 
var ul = document.getElementById("myList"); 
var li = null; 
for (var i=0; i < 3; i++){ 
 li = document.createElement("li"); 
 li.appendChild(document.createTextNode("Item " + (i+1))); 
 fragment.appendChild(li); 
} 
ul.appendChild(fragment);//ul中插入文档片段


//创建fragment 
var fragment = document.createDocumentFragment(); 
//ul子节点保存到fragment
let child;
while(child=ul.firstChild){//一个节点只能有一个父亲
    fragment.appendChild(child);
}
//更新frament中li的文本
Array.prototype.slice.call(fragment.childNodes).forEach(node=>{
    if(node.nodeType===1){
        node.textContent='test'
    }
})
//ul中插入文档片段
ul.appendChild(fragment);

Attr类型

特性节点具有下列特征:
nodeType 的值为 2
nodeName 的值是特性的名称;
nodeValue 的值是特性的值;
parentNode 的值为 null
  • Attr 对象有 3 个属性:namevalue specified。其中,name 是特性名称(与 nodeName 的值相同),value 是特性的值(与 nodeValue 的值相同),而 specified 是一个布尔值,用以区别特性是在代码中指定的,还是默认的。
  • 使用 document.createAttribute()并传入特性的名称可以创建新的特性节点
  • 尽管它们也是节点,但特性却不被认为是 DOM 文档树的一部分。开发人员最常使用的是 getAttribute()setAttribute()remveAttribute()方法,很少直接引用特性节点。
var attr = document.createAttribute("align"); 
attr.value = "left"; 
element.setAttributeNode(attr); //特性添加到元素
alert(element.attributes["align"].value); //"left" 
alert(element.getAttributeNode("align").value); //"left" 
alert(element.getAttribute("align")); //"left"
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值