美文网首页JavaScript < ES5、ES6、ES7、… >
JavaScript 高级程序设计(第10章 DOM)

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

作者: yinxmm | 来源:发表于2018-08-11 13:57 被阅读23次

    第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);
     }
    

    相关文章

      网友评论

        本文标题:JavaScript 高级程序设计(第10章 DOM)

        本文链接:https://www.haomeiwen.com/subject/odldbftx.html