JavaScript 高级程序设计(第10章 DOM)

第10章 DOM

1. 节点层次

文档节点是每个文档的根节点。

(1) Node 类型
  1. 每个节点都有一个 nodeType 属性,用于表明节点的类型。
  2. 节点类型由在 Node 类型中定义的下列 12 个数值常量来表示,任何节点类型必居其一:

(1) Node.ELEMENT_NODE(1);
(2) Node.ATTRIBUTE_NODE(2);
(3) Node.TEXT_NODE(3);
(4) Node.CDATA_SECTION_NODE(4);
(5) Node.ENTITY_REFERENCE_NODE(5);
(6) Node.ENTITY_NODE(6);
(7) Node.PROCESSING_INSTRUCTION_NODE(7);
(8) Node.COMMENT_NODE(8);
(9) Node.DOCUMENT_NODE(9);
(10) Node.DOCUMENT_TYPE_NODE(10);
(11) Node.DOCUMENT_FRAGMENT_NODE(11);
(12) Node.NOTATION_NODE(12)。

  1. IE 没有公开 Node 类型的构造函数,为了确保跨浏览器兼容,最好还是将nodeType 属性与数字值进行比较。
nodeNamenodeValue 属性
* 节点关系
    1. 每个节点都有一个 childNodes 属性,其中保存着一个 NodeList 对象。
  • NodeList 是一种类数组 对象,用于保存一组有序的节点,可以通过位置来访问这些节点。
  • 虽然可以通过方括号语法来 访问 NodeList 的值,而且这个对象也有length 属性,但它并不是 Array 的实例
  • NodeList 对象的独特之处在于,它实际上是基于 DOM 结构动态执行查询的结果,因此 DOM 结构的变化能够自动反映在 NodeList 对象中。
  • 访问保存在 NodeList 中的节点——可以通过方括号,也可以使用 item() 方法。
var firstChild = someNode.childNodes[0];
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]);
            }
}
        return array;
    }
    1. 每个节点都有一个 parentNode属性,该属性指向文档树中的父节点。

包含在 childNodes 列表中 的所有节点都具有相同的父节点,因此它们的 parentNode 属性都指向同一个节点。

    1. 包含在 childNodes 列表中的每个节点相互之间都是同胞节点。通过使用列表中每个节点的 previousSiblingnextSibling 属性,可以访问同一列表中的其他节点。
    1. 父节点的 firstChildlastChild 属性分别指向其 childNodes 列表中的第一个和最后一个节点。
      节点关系
  • 5.hasChildNodes()方法在节点包含一或多个子节点的情况下返回 true。

    1. ownerDocument属性指向表示整个文档的文档节点。
* 操作节点
  1. appendChild()方法:用于向 childNodes 列表的末尾添加一个节点。

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

//someNode 有多个子节点
var returnedNode = someNode.appendChild(someNode.firstChild);
alert(returnedNode == someNode.firstChild); //false 
alert(returnedNode == someNode.lastChild); //true
  1. insertBefore()方法:接受两个参数:要插入的节点作为参照的节点。插入节点后,被插 入的节点会变成参照节点的前一个同胞节点(previousSibling),同时被方法返回。
    如果参照节点是 null,则 insertBefore()与 appendChild()执行相同的操作

3.replaceChild()方法:接受的两个参数是:要插入的节点要替换的节点。要替换的节点将由这个 方法返回并从文档树中被移除,同时由要插入的节点占据其位置。

4.removeChild()方法:接受一个参数,即要移除 的节点。被移除的节点将成为方法的返回值。

* 其他方法
  1. cloneNode()方法:用于创建调用这个方法的节点的一个完全相同的副本。接受一个布尔值参数,表示是否执行深复制。在参数为 true 的情况下,执行深复制,也就是复制节点及其整个子节点树;在参数为 false 的情况下,执行浅复制, 即只复制节点本身。

2.normalize()方法:由于解析器的实现或 DOM 操作等原因,可能会出现文本节点不包含文本,或者接连出现两个文本节点 的情况。当在某个节点上调用这个方法时,就会在该节点的后代节点中查找上述两种情况。如果找到了空文本节点,则删除它;如果找到相邻的文本节点,则将它们合并为一个文本节点。

(2) Document类型
  1. JavaScript 通过 Document 类型表示文档。
  2. 在浏览器中,document 对象是 HTMLDocument(继承自 Document 类型)的一个实例,表示整个 HTML 页面。
  3. document 对象是 window 对象的一个 属性,因此可以将其作为全局对象来访问。

Document 节点具有下列特征:

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

* 文档的子节点

Document 节点的子节点可以是DocumentType、Element、ProcessingInstruction 或 Comment。

1.两个内置的访问其子节点的快捷方式

  1. documentElement 属性,该属性始终指向 HTML 页面中的<html>元素。
  2. 通过 childNodes 列表访问文档元素。
  1. document.body,body 属性,直接指向<body>元素。

3.Document 另一个可能的子节点是 DocumentType。通常将<!DOCTYPE>标签看成一个与文档其他 部分不同的实体,可以通过 doctype 属性(在浏览器中是 document.doctype)来访问它的信息。

* 文档信息
  1. title属性:可以取得当前页面的标题,也可以修改当前页面的标题并反映在浏览器的标题栏中。(document.title)

  2. URL属性:包含页面完整的 URL(即地址栏中显示的 URL)。(document.URL)

  3. domain 属性:只包含页面的域名。(document.domain)

  4. referrer 属性: 保存着链接到当前页面的那个页面的 URL。在没有来源页面的情况下,referrer 属性中可能 会包含空字符串。(document.referrer)

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

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

(2) 浏览器对 domain 属性还有一个限制,即如果域名一开始是“松散的”(loose),那么不能将它再设 置为“紧绷的”(tight)。换句话说,在将 document.domain 设置为"wrox.com"之后,就不能再将其 设置回"p2p.wrox.com",否则将会导致错误。

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

(1) 接收一个参数:要取得的元素的 ID。如果找到相应的元素则返回该元素,如果不存在带有相应 ID 的元素,则返回 null。
(2) 如果页面中多个元素的 ID 值相同,getElementById()只返回文档中第一次出现的元素
(3) ID 必须与页面中元素的 id 特性(attribute)严格匹配,包括大小写

  1. getElementsByTagName():

(1) 接受一个参数,即要取得元素的标签名,而返回的是包含零或多个元素的 NodeList。
(2) 在 HTML 文档中,这个方法会返回一 个 HTMLCollection 对象,作为一个“动态”集合,该对象与 NodeList 非常类似。
(3) 与 NodeList 对象类似,可以 使用方括号语法或item()方法来访问 HTMLCollection 对象中的项。而这个对象中元素的数量则可以 通过其length 属性取得。

var images = document.getElementsByTagName("img");
alert(images.length);//输出图像的数量
alert(images[0].src); //输出第一个图像元素的 src 特性
alert(images.item(0).src);//输出第一个图像元素的 src 特性 

(4) HTMLCollection 对象还有一个方法,叫做namedItem(),使用这个方法可以通过元素的 name 特性取得集合中的项。

<img src="myimage.gif" name="myImage">
var myImage = images.namedItem("myImage");

(5) HTMLCollection 还支持按名称访问项,对命名的项也可以使用方括号语法来访问。

var myImage = images["myImage"];

对 HTMLCollection 而言,我们可以向方括号中传入数值或字符串形式的索引值。在后台,对数 值索引就会调用 item(),而对字符串索引就会调用 namedItem()。

(6) 要想取得文档中的所有元素,可以向 getElementsByTagName()中传入"*"。

3.getElementsByName():

(1) 只有 HTMLDocument 类型才有的方法,这个方法会返回带有给定 name 特性的所有元素。

* 特殊集合

(1) document.anchors,包含文档中所有带 name 特性的<a>元素;
(2) document.applets,包含文档中所有的<applet>元素,因为不再推荐使用<applet>元素,所以这个集合已经不建议使用了;
(3) document.forms,包含文档中所有的<form>元素,与 document.getElementsByTagName("form")得到的结果相同;
(4) document.images,包含文档中所有的<img>元素,与 document.getElementsByTagName("img")得到的结果相同;
(5) document.links,包含文档中所有带 href 特性的<a>元素。

* DOM 一致性检测

由于 DOM 分为多个级别,也包含多个部分,因此检测浏览器实现了 DOM 的哪些部分就十分必要 了。document.implementation 属性就是为此提供相应信息和功能的对象,与浏览器对 DOM 的实现直接对应。

(1) DOM1 级只为 document.implementation 规定了一个方法,即 hasFeature()。这个方 法接受两个参数:要检测的 DOM 功能的名称及版本号。如果浏览器支持给定名称和版本的功能,则该方法返回 true。

var hasXmlDom = document.implementation.hasFeature("XML", "1.0");
DOM 功能
* 文档写入

write()writeln()方法都接受一个字符串参数,即要写入到输出流中的文本。write()会原样写入,而 writeln()则会 在字符串的末尾添加一个换行符(\n)。

(1) 在页面被加载的过程中,可以使用这两个方法向页面中动态地加入内容。

<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>
        </p>
    </body>
 </html>

不能直接包含字符串"</script>",因为这会导致该 字符串被解释为脚本块的结束,它后面的代码将无法执行。需加入转义字符\即可
(2) 如果在文档加载结束后再调用 document.write(),那么输出的内容将会重写整个页面。

<html>
    <head>
        <title>document.write() Example 4</title>
    </head>
    <body>
        <p>This is some content that you won't get to see 
                because it will be overwritten.</p>
        <script type="text/javascript">
        window.onload = function(){
            document.write("Hello world!");
        }; 
       </script>
    </body>
</html>

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

(3) Element类型

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

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

  1. 要访问元素的标签名,可以使用 nodeName 属性,也可以使用 tagName 属性;
  2. 在 HTML 中,标签名始终都以全部大写表示,div.tagName 实际上输出的是 "DIV"而非"div"。
*HTML元素
  1. 所有 HTML 元素都由 HTMLElement 类型表示,不是直接通过这个类型,也是通过它的子类型来表示。
  2. HTMLElement 类型直接继承自 Element 并添加了一些属性。添加的这些属性分别对应于每个 HTML 元素中都存在的下列标准特性。

(1) id,元素在文档中的唯一标识符。
(2) title,有关元素的附加说明信息,一般通过工具提示条显示出来。
(3) lang,元素内容的语言代码,很少使用。
(4) dir,语言的方向,值为"ltr"(left-to-right,从左至右)或"rtl"(right-to-left,从右至左),
也很少使用。
(5) 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"
* 取得特性

getAttribute()方法:

  1. 通过 getAttribute()方法也可以取得自定义特性(即标准 HTML 语言中没有的特性)的值。

2.特性的名称是不区分大小写的,即"ID"和"id"代表的都是同一个特性。

任何元素的所有特性,也都可以通过 DOM 元素本身的属性来访问。只有公认的(非自定义的)特性才会以属性的形式添加到 DOM 对象中。

两类特殊的特性属性的值与通过 getAttribute()返回的值不相同:

(1) 第一类特性就是 style,用于通过 CSS 为元素指定样式。在通过 getAttribute()访问时,返 回的 style 特性值中包含的是 CSS 文本,而通过属性来访问它则会返回一个对象。
(2) 第二类特性是onclick 这样的事件处理程序。当在元素上使用时,onclick 特性中包 含的是 JavaScript 代码,如果通过 getAttribute()访问,则会返回相应代码的字符串。而在访问 onclick 属性时,则会返回一个 JavaScript 函数(如果未在元素中指定相应特性,则返回 null)。

* 设置特性

setAttribute()方法:

  1. 这个方法 接受两个参数:要设置的特性名和值。如果特性已经存在,setAttribute()会以指定的值替换现有的值;如果特性不存在,setAttribute() 则创建该属性并设置相应的值。
  2. 通过这个方法设置的 特性名会被统一转换为小写形式,即"ID"最终会变成"id"。

(1) 因为所有特性都是属性,所以直接给属性赋值可以设置特性的值。
(2) 为 DOM 元素添加一个自定义的属性,该属性不会自动成为元素的特性。

removeAttribute()方法:

这个方法用于彻底删除元素的特性。调用这个方法不仅会清除特性的值,而且也会从元素中完全删除特性。

*attributes 属性

1.Element 类型是使用 attributes 属性的唯一一个 DOM 节点类型。

2.attributes 属性中包含一个NamedNodeMap,与 NodeList 类似,也是一个“动态”的集合。元素的每一个特性都由一个 Attr 节 点表示,每个节点都保存在 NamedNodeMap 对象中。

NamedNodeMap 对象拥有下列方法:

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

  1. attributes 属性中包含一系列节点,每个节点的nodeName 就是特性的名称,而节点的 nodeValue 就是特性的值
var id = element.attributes.getNamedItem("id").nodeValue;
//简写方式
var id = element.attributes["id"].nodeValue;
//设置新值
element.attributes["id"].nodeValue = "someOtherId";
  1. 调用 removeNamedItem()方法与在元素上调用 removeAttribute()方法的效果相同——直接删 除具有给定名称的特性。两个方法间唯一的区别,即 removeNamedItem()返回表示 被删除特性的 Attr 节点。

  2. 针对 attributes 对象中的特性,不同浏览器返回的顺序不同。这些特性在 XML 或 HTML 代 码中出现的先后顺序,不一定与它们出现在 attributes 对象中的顺序一致。

  3. IE7 及更早的版本会返回 HTML 元素中所有可能的特性,包括没有指定的特性。换句话说,返回 100 多个特性的情况会很常见。

每个特 性节点都有一个名为 specified 的属性,这个属性的值如果为 true,则意味着要么是在 HTML 中指定了相应特性,要么是通过 setAttribute()方法设置了该特性。在 IE 中,所有未设置过的特性的该 属性值都为 false,而在其他浏览器中根本不会为这类特性生成对应的特性节点(因此,在这些浏览器 中,任何特性节点的 specified 值始终为 true)。

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;
if (element.attributes[i].specified) {
            pairs.push(attrName + "=\"" + attrValue + "\"");
        }
}
    return pairs.join(" ");
}
* 创建元素

document.createElement()方法可以创建新元素。

  1. 这个方法只接受一个参数,即要创建元素的标签名。

  2. 这个标签名在 HTML 文档中不区分大小写,而在 XML(包括 XHTML)文档中,则是区 分大小写的。

  3. IE 中可以以另一种方式使用 createElement(),即为这个方法传入完整的元素标签,也可以包含属性。


var div = document.createElement("<div id=\"myNewDiv\" 
class=\"box\"></div >");
*元素的子节点
  1. 元素的 childNodes 属性中包含了它的所有子节点,这些子节点有可能是元素、文本节点、注释或处理指令。

  2. 不同浏览器在看待这些节点方面存在显著的不同,返回的子节点不相同。

  3. 如果需要通过 childNodes 属性遍历子节点,要先检查 一下 nodeTpye 属性。

for (var i=0, len=element.childNodes.length; i < len; i++){
if (element.childNodes[i].nodeType == 1){ 12
//执行某些操作 }
}
  1. 元素也支持 getElementsByTagName()方法。在通过元素调用这个方法时,除了搜索起点是当前元素之外,其他 方面都跟通过 document 调用这个方法相同,因此结果只会返回当前元素的后代。
var ul = document.getElementById("myList");
var items = ul.getElementsByTagName("li");
(4) Text 类型
  1. 文本节点由 Text 类型表示,包含的是可以照字面解释的纯文本内容。
  2. 纯文本中可以包含转义后的 HTML 字符,但不能包含 HTML 代码。

Text 节点具有以下特征:

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

  1. 通过 nodeValue 属性data 属性访问 Text 节点中包含的文本,这两个属性中包含的值相同。对 nodeValue 的修改也会通过 data 反映出来,反之亦然。

操作节点中文本的方法

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

  1. 文本节点还有一个 length 属性,保存着节点中字符的数目。而且,nodeValue.length 和 data.length 中也保存着同样的值。

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

访问文本子节点:

var textNode = div.firstChild; //或者div.childNodes[0]
//取得了文本节点的引用后修改它。
div.firstChild.nodeValue = "Some other message";
  1. 在修改文本节点时还要注意,此时的字符串会经过 HTML(或 XML,取决于文档类型)编码。换句话说, 小于号、大于号或引号都会像下面的例子一样被转义。
//输出结果是"Some &lt;strong&gt;other&lt;/strong&gt; message" 
div.firstChild.nodeValue = "Some <strong>other</strong> message";
* 创建文本节点

document.createTextNode()创建新文本节点。

  1. 这个方法接受一个参数——要插入节点 中的文本。
  2. 与设置已有文本节点的值一样,作为参数的文本也将按照 HTML 或 XML 的格式进行编码。
  3. 一般情况下,每个元素只有一个文本子节点。不过,在某些情况下也可能包含多个文本子节点。如果两个文本节点是相邻的同胞节点,那么这两个节点中的文本就会连起来显示,中间不会有空格。
    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);
*规范化文本节点

normalize()方法:

如果 在一个包含两个或多个文本节点的父元素上调用 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!"
* 分割文本节点

splitText()方法:

这个方法会将一个文本节点分成两个文本节点,即按照指定的位置分割 nodeValue 值。原来的文本节点将包含从开始到指定位 置之前的内容,新文本节点将包含剩下的文本。这个方法会返回一个新文本节点,该节点与原节点的 parentNode 相同。

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类型

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

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

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

  2. 与 Text 类型相似,也可以通过nodeValuedata 属性来取得注释的内容。

3.document.createComment()并为其传递注释文本也可以创建注释节点。

(6) CDATASection类型
  1. CDATASection 类型只针对基于 XML 的文档,表示的是 CDATA 区域。
  2. 与 Comment 类似, CDATASection 类型继承自 Text 类型,因此拥有除 splitText()之外的所有字符串操作方法。

CDATASection 节点具有下列特征:

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

  1. CDATA 区域只会出现在 XML 文档中,因此多数浏览器都会把 CDATA 区域错误地解析为 Comment 或 Element

  2. 在真正的 XML 文档中,可以使用document.createCDataSection()来创建 CDATA 区域,只需 为其传入节点的内容即可。

(7) DocumentType类型

DocumentType 包含着与文档的 doctype 有关的所有信息。
DocumentType具有下列特征:

(1) nodeType 的值为 10;
(2) nodeName 的值为 doctype 的名称;
(3) nodeValue 的值为 null;
(4) parentNode 是 Document;
(5) 不支持(没有)子节点。

  1. 在 DOM1 级中,DocumentType 对象不能动态创建,而只能通过解析文档代码的方式来创建。
  2. 支持它的浏览器会把 DocumentType 对象保存在 document.doctype 中。
  3. DOM1 级描述了 DocumentType 对象的 3 个属性:name、entities 和 notations。

(1) name表示文档类型的名称。
(2) entities 是由文档类型描述的实体的 NamedNodeMap 对象
(3) notations 是由文档类型描述的符号的 NamedNodeMap 对象。

* DocumentFragment类型
  1. 在所有节点类型中,只有 DocumentFragment 在文档中没有对应的标记
  2. DOM 规定文档片段 (document fragment)是一种“轻量级”的文档,可以包含和控制节点,但不会像完整的文档那样占用
    额外的资源。
    DocumentFragment 节点具有下列特征:

(1) nodeType 的值为 11;
(2) nodeName 的值为"#document-fragment";
(3) nodeValue 的值为 null;
(4) parentNode 的值为 null;
(5) 子节点可以是 Element、ProcessingInstruction 、Comment、Text、CDATASection 或EntityReference。

  1. 虽然不能把文档片段直接添加到文档中,但可以将它作为一个“仓库”来使用,即可以在里面保存将来可能会添加到文档中的节点。

document.createDocumentFragment()方法:创建文档片段。

var fragment = document.createDocumentFragment();
  1. 如果将文档中的节点添加到文档片段中,就会从文档树中移除该节点,也不会从浏览器中再看到该节点。添加到文档片段 中的新节点同样也不属于文档树。
  2. 可以通过 appendChild()或 insertBefore()将文档片段中内容添 加到文档中。在将文档片段作为参数传递给这两个方法时,实际上只会将文档片段的所有子节点添加到相应位置上;文档片段本身永远不会成为文档树的一部分。
(5) Attr类型

元素的特性在 DOM 中以 Attr 类型来表示。

  1. 从技术角度讲,特性就是存在于元素的 attributes 属性中的节点。

特性节点具有 下列特征:

(1) nodeType 的值为 2;
(2) nodeName 的值是特性的名称;
(3) nodeValue 的值是特性的值;
(4) parentNode 的值为 null;

(5) 在 HTML 中不支持(没有)子节点;
(6) 在 XML 中子节点可以是 Text 或 EntityReference。

  1. 尽管它们也是节点,但特性却不被认为是 DOM 文档树的一部分。

  2. Attr 对象有 3 个属性:name、value 和 specified。

(1) name 是特性名称(与 nodeName 的 值相同)。
(2) value 是特性的值(与 nodeValue 的值相同)。
(3) specified 是一个布尔值,用以区别特性是在代码中指定的,还是默认的。

document.createAttribute()并传入特性的名称可以创建新的特性节点。
setAttributeNode()方法:将新创建的特性添加到元素中。

访问特性:attributes 属性、getAttributeNode()方法以及 getAttribute()方法。其中,attributes和 getAttributeNode()都会返回对应特性的 Attr 节点,而 getAttribute()则只返回特性的值。

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"

2. DOM 操作技术

(1) 动态脚本

创建动态脚本有两种方式:插入外部文件直接插入 JavaScript 代码

* 加载外部的 JavaScript 文件
function loadScript(url){
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = url;
        document.body.appendChild(script);
}
loadScript("client.js");
* 指定 JavaScript 代码
function loadScriptString(code){
    var script = document.createElement("script");
    script.type = "text/javascript";
    try {
        script.appendChild(document.createTextNode(code));
    } catch (ex){
        script.text = code;
    }
    document.body.appendChild(script);
}
loadScriptString("function sayHi(){alert('hi');}");

IE 将<script>视为一个特殊的元素,不允许 DOM 访问其子节点。不过,可以使用<script>元素的 text 属性来指定 JavaScript 代码。

(2) 动态样式

与动态脚本类似,所谓动态样式是指在页面刚加载时不存在的样式;动态样式是在页面加载完成后动态添加到页面中的。

  1. 能够把 CSS 样式包含到 HTML 页面中的元素有两个。其中,<link>元素用于包含来自外部的文件, 而<style>元素用于指定嵌入的样式。
*<link>元素
<link rel="stylesheet" type="text/css" href="styles.css">

function loadStyles(url){
    var link = document.createElement("link");
    link.rel = "stylesheet";
    link.type = "text/css";
    link.href = url;
    var head = document.getElementsByTagName("head")[0];
    head.appendChild(link);
}
loadStyles("styles.css");
* <style>元素
<style type="text/css">
    body {
        background-color: red;
    }
</style>

function loadStyleString(css){
        var style = document.createElement("style");
        style.type = "text/css";
        try{
            style.appendChild(document.createTextNode(css));
         } catch (ex){
            style.styleSheet.cssText = css;
         }
        var head = document.getElementsByTagName("head")[0];
        head.appendChild(style);
}
loadStyleString("body{background-color:red}");

IE 将<style>视为 一个特殊的、与<script>类似的节点,不允许访问其子节点。解决 IE 中这个问题的办法,就是访问元素的 styleSheet 属性, 该属性又有一个 cssText 属性,可以接受 CSS 代码。

(3) 操作表格

*<table>元素添加的属性和方法

(1) caption:保存着对<caption>元素(如果有)的指针。
(2) tBodies:是一个<tbody>元素的 HTMLCollection。
(3) tFoot:保存着对<tfoot>元素(如果有)的指针。
(4) tHead:保存着对<thead>元素(如果有)的指针。
(5) rows:是一个表格中所有行的 HTMLCollection。
(6) createTHead():创建<thead>元素,将其放到表格中,返回引用。
(7) createTFoot():创建<tfoot>元素,将其放到表格中,返回引用。
(8) createCaption():创建<caption>元素,将其放到表格中,返回引用。  deleteTHead():删除<thead>元素。
(9) deleteTFoot():删除<tfoot>元素。
(10) deleteCaption():删除<caption>元素。
(11) deleteRow(pos):删除指定位置的行。
(12) insertRow(pos):向 rows 集合中的指定位置插入一行。

*为<tbody>元素添加的属性和方法

(1) rows:保存着<tbody>元素中行的 HTMLCollection。
(2) deleteRow(pos):删除指定位置的行。
(3) insertRow(pos):向 rows 集合中的指定位置插入一行,返回对新插入行的引用。

*<tr>元素添加的属性和方法

(1) cells:保存着<tr>元素中单元格的 HTMLCollection。
(2) deleteCell(pos):删除指定位置的单元格。
(3) insertCell(pos):向 cells 集合中的指定位置插入一个单元格,返回对新插入单元格的引用。

<table border="1" width="100%">
        <tbody>
            <tr>
                <td>Cell 1,1</td>
                <td>Cell 2,1</td>
            </tr>
            <tr>
                <td>Cell 1,2</td>
                <td>Cell 2,2</td>
            </tr>
        </tbody>
</table>

//创建 table
var table = document.createElement("table");
table.border = 1;
table.width = "100%";

//创建 tbody
var tbody = document.createElement("tbody");
table.appendChild(tbody); 

//创建第一行
tbody.insertRow(0);
tbody.rows[0].insertCell(0);
tbody.rows[0].cells[0].appendChild(document.createTextNode("Cell 1,1"));
tbody.rows[0].insertCell(1);
tbody.rows[0].cells[1].appendChild(document.createTextNode("Cell 2,1"));

//创建第二行
tbody.insertRow(1);
tbody.rows[1].insertCell(0);
tbody.rows[1].cells[0].appendChild(document.createTextNode("Cell 1,2"));
 tbody.rows[1].insertCell(1);
tbody.rows[1].cells[1].appendChild(document.createTextNode("Cell 2,2"));
//将表格添加到文档主体中
document.body.appendChild(table);

(4) 使用NodeList

NodeList 及其“近亲”NamedNodeMap 和 HTMLCollection,这三个集合都是“动态的”;换句话说,每当文档结构发生变化时,它们都会得到更新。因 此,它们始终都会保存着最新、最准确的信息。

如果想要迭代一个 NodeList,最好是使用 length 属性初始化第二个变量,然后将迭代器与该变量进行比较。

var divs = document.getElementsByTagName("div"),i,len, div;
for (i=0, len=divs.length; i < len; i++){
        div = document.createElement("div");
        document.body.appendChild(div);
 }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容