Javascript--10DOM

 DOM(文档对象模型)

  @针对HTML和XML文档的一个API,为基本的文档结构及查询提供接口。
  @IE中的DOM都是以COM对象的形式实现的,故IE中的DOM对象于原生JavaScript对象的行为或活动特点有差异。

  10.1节点层次

    @DOM能够将任何HTML或XML文档庙会成一个由多层节点构成的结构。
    @每个文档只能有一个文档元素,在HTML页面中,文档元素为<html>元素。【根节点为Document,最外层元素为文档元素html】
    @HTML元素通过元素节点表示,特性(attribute)通过特性节点表示,文档类型通过文档类型节点表示,注释通过注释节点表示。

    10.1.1 Node类型

      @DOM1级定义了Node接口,由DOM中的所有节点类型实现。除了IE外,JavaScript中的节点都是继承自Node类型。
      @节点类型由Node类型定义的12个数值常量表示:
        Node.ELEMENT_NODE(1);
        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)
      @通过上面的常量能判断节点的类型,但由于IE没有公开Node类型的构造函数,故应该用数字值进行比较:


if (someNode.nodeType == Node.ELEMENT_NODE){  //在IE中无效
    alert("元素节点");
}

if (someNode.nodeType == 1){  //所有浏览器适应
    alert("元素节点");
}

      ① nodeName 和 nodeValue

        @对于元素节点,nodeName保存元素的标签名,nodeValue值为null。

      ② 节点关系

        每个节点都有一个childNodes属性,保存着一个NodeList对象(一种类数组对象,保存一组有序的节点)。
          @可通过方括号语法和item()方法访问NodeList的值,有length属性,但不是Array的实例,而是基于DOM结构动态查询的结果。
          @在IE8-浏览器中,会为空白符创建节点,length属性值会包含空白符节点。

var firstChild = someNode.childNodes[0];
var secondChild = someNode.childNodes.item(1);
var count = someNode.childNodes.length;
           @length属性表示的是访问NodeList那一刻节点的数量。

          @将NodeList对象转换为数组:使用Array.prototype.slice()【IE8及以下无效,需要手动枚举所有成员】


function toArray(){
  var array = null;
  try {
    array = Array.prototype.slice.call(nodes, 0); //针对IE9+等浏览器
  } catch(ex){
    array = new Array();
    for (var i = 0; i < nodes.length; i++) {  //针对IE8-
      array.push(nodes[i]);
    };
  }
  return array;
}

         每个节点都有一个parentNode属性。包含在NodeList列表中的所有节点具有相同的父节点,他们的parentNode指向同个父节点。

        每个节点通过previousSibling和nextSibling属性访问相邻节点。首个节点的previousSibling和末尾节点的nextSibling都是null。
          @只有一个子节点时,firstChild和lastChild指向同个子节点。没有节点时都为null。
          @hasChildNodes()方法在节点包含子节点时返回true。

      ③ 操作节点

        appendChild():1个子节点参数。向NodeList列表末尾添加一个新节点。
          @当传入的节点已经是文档的一部分时,该节点讲过从原点的位置转移到新位置。
        insertBefore():2个参数。在指定节点前插入一个新节点。
          @当指定的节点即第一个参数为null时,insertBefore()和appendChild()执行相同的操作。


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

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

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

        replaceChild():2个参数。以上述2种不同的是,这个方法会代替原来的节点。
          @插入一个节点时,原节点的所有关系指针都会被代替节点复制过去,但原节点仍在文档中,只是没有了自己的位置。

//替换第一个子节点
var returnedNode = someNode.replaceChild(newNode,someNode.firstChild);
//替换最后一个子节点
returnedNode = someNode.replaceChild(newNode,someNode.lastChild);
        removeChild():1个参数。移除节点。移除的节点成为方法的返回值。
          @同样,移除的节点仍为文档所有,只是没有了自己的位置。

        前面4中操作方法,都需要先取得父节点。使用该4种方法操作不支持子节点的节点时,会导致错误发生。

      ④ 其他方法

        2个所有类型节点都有的方法:cloneNode() 和 normalize()

        cloneNode():1个布尔值参数(表是否执行深复制)。用于创建调用这个方法的节点的一个完全相同的副本。
          参数为true时,执行深复制,即复制节点及其整个子节点树。
          参数为false时,执行浅复制,即只复制节点本身。
          @cloneNode():不会复制DOM节点的JavaScript属性(如事件处理程序),只复制特性。IE则会复制JavaScript属性。

        normalize():用于处理文档树中的文本节点:删除空文本节点 和 合并相邻文本节点。

 

    10.1.2 Document 类型

      @JavaScript通过Document类型表示文档(HTML或XML)。浏览器中,document是HTMLDocument(继承自Document类型)的一个实例。
      @document对象表示整个HTML页面,是window对象的属性,故可作为全局对象来访问。
        nodeType=9
        nodeName="#document"
        nodeValue、parentNode、ownerDocument = null
        子节点 可能是:DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction 或 Comment。

      ① 文档的子节点

        @访问document子节点的2个快捷方式:documentElement属性 和 通过childNodes列表访问文档元素。

var html = document.documentElement; //取得对<html>的引用

//html的值 与 document.childNodes[0] 和 document.firstChild相同。
        @document对象还有一个body属性,指向<body>元素。
        @Document有一个可能的子节点DocumentType。
          通常将<!DOCTYPE>标签看成一个与文档其他部分不同的实体,可通过doctype属性访问,但该属性兼容性差。

       ② 文档信息

        @作为HTMLDocument的实例,document对象有一些标准Document对象没有的属性。
        @title属性:将<title>元素中的文本,显示在浏览器窗口的标题栏的标签页上。
        @存在请求的HTTP头部的属性:
          URL属性,包含网页完整的URL。 var url = document.URL;
          domain属性,包含页面的域名。
          referrer属性,保存着链接到当前页面的那个页面的URL。没有来源页面时,为空字符串。
          @3个中只有domain可设置,但受安全限制:
            如:URL为aa.bbb.com时,domain只能设为bbb.com;
              URL为www.bbb.com时,domain只能设为bbb.com。
            不能将domain设置为URL不包含的域。
          @跨域:当包含来自其他子域的框架或内嵌框架时,由于安全限制,默认不能与不同子域的页面进行JavaScript通信。
              但通过将彼此的document.domain设置相同值,就能互访对方的JavaScript对象。
            如:主页www.bbb.com,框架内的页面aa.bbb.com,设置彼此的document.domain = "bbb.com";,就能互访。
          @对domain的另一个限制:不能将"松散的"(loose)domain属性 再设置为"紧绷的"(tight)
            如:不能将松散的"bbb.com"设置为紧绷的"aa.bbb.com"。

      ③ 查找元素

        Document类型提供2种方法:getElementById() 和 getElementByTagName()
          getElementById():通过元素的ID引用元素。
            @当页面有多个元素相同ID时,返回文档中第一次出现的元素。
            @在IE7及以下版本中,name值以ID相同的表单元素也会被返回。当name与ID值相同的表单元素位于前面时,后面的“ID元素”不会被返回。
              应该避免表单元素中name属性与其他元素的ID值相同。
          getElementByTagName():接收标签名,返回包含零或多个元素的NodeList。在HTML中,返回一个HTMLCollection对象,一个"动态"集合。
            @通过方括号语法 、item()方法 和 name值 访问HTMLCollection对象中的项,元素数量通过其length属性取得。
            @HTMLCollection对象的namedItem()方法可通过元素name特性取得集合中的项。
            @对HTMLCollection而言,可向方括号中传入数值或字符串形式的牵引值,
              在后台,对数值牵引就会调用item()方法,对于字符串就会调用namedItem()。
          getElementByName():返回给定name特性的所有元素。常用于取得单选按钮。

       ④ 特殊集合

        document.anchors:包含所有带name特性的<a>元素。
        document.links:包含所有带href特性的<a>元素。
        document.forms:包含所有<form>元素。结果同document.getElementByTagName(“form”);
        document.images:包含所有<img>元素。

      ⑤ 文档写入

        将输出流写入页面的4个方法:write()、writeln()、opne() 和 close()
          @write()原样写入。writeln()在字符串较为添加一个换行符(\n)。
          @输入"</script>"时,应该添加转义序列,不然会被解释为与外部<script>标签匹配,' "); '会出现在页面中。

document.write("<script type=\"text\javascript\" src=\"file.js\">" + "<\/script>");
          @加载结束后,再调用document.write()输出的内容会重写整个页面。



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

          @open()和close()分别打开和关闭输出流。

    10.1.3 Element类型

      @Element节点的子节点可能是:Element、Text、Comment、ProcessingInstruction、CDATASection 或 EntityReference。
      @通过nodeName和tagName能访问元素的标签名。
      @在HTML中,标签名始终全部大写。在XML中,始终与源代码一致。最好使用toLowerCase()统一转换为小写。

        ① HTML元素

          @所有HTML元素 都由HTMLElement类型或其子类型表示。HTMLElement继承自Element。
          @每个HTML元素的标准特性:
            id元素在文档的唯一标识符、className对应元素的name特性、title附加说明信息、lang元素内容的语言代码、dir语言方向"ltr"/"rtl"。



        var div = null;
        function getValues(){
            if (div == null) {
                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"
        }   
       
        function setValues(){
            if (div == null) {
                div = document.getElementById("myDiv");
            }
       
            div.id = "someOtherId";
            div.className = "ft";
            div.title = "Some other text";
            div.lang = "fr";
            div.dir ="rtl";       
        }

        ② 取得特性

          操作DOM的3个方法:getAttribute()、setAttibute()、removeAttribute()

            getAttribute()【应该尽量不用它访问HTML特性】
              @传入的为实际的特性名,故应该用class而不是className。不存在时,返回null。
              @可获取自定义特性(标准HTML语言没有的特性),特性名称不区分大小写。在HTML5规范中,自定义特性应该以“data-”前缀。
                @只有公认特性才会以属性的形式添加到DOM对象中。自定义特性只有在IE中才被创建为属性。

//<div id="myDiv" my_attribute="hello!">Some text</div>

var div = document.getElementById("myDiv");
alert(div.id);                                 //"myDiv"
alert(div.my_special_attribute);   // undefined (IE 返回"hello!") 
              @两类特殊的特性:style属性 和 事件处理程序
                @通过getAttribute()返回CSS文本,通过访问style属性返回一个对象。
                @事件句柄中的JS代码通过getAttribute()访问时,返回相应代码的字符串。而在直接访问类似onclick属性时,返回一个函数。
                @在IE7-中两个特性分别返回一个对象和一个函数。

        ③ 设置特性

          setAttitude()
            @通过此方法设置的特性名会被统一转换为小写形式。
            @所有特性都是属性,故可以直接赋值和调用:div.id = "balabala";
              但自定义特性在IE以外的浏览器,为DOM元素添加一个自定义的属性时,该属性不会自动成为元素的特性。

div.myColor = "red";
alert(div.getAttibute("myColor"));  //null (IE除外)
               在IE7-中使用上述方法设置class、style属性 和 事件句柄,没有效果。故推荐使用属性来设置特性。

          removeAttitude()【IE6-不支持】

        ④ attitude属性【没getAttribute()等方法方便】

          @Element类型是使用attributes属性的唯一一个DOM节点类型。
          @attributes属性包含一个NamedNodeMap集合(类似NodeList)。
            元素的每一个特性都由一个Attr节点表示,Attr节点保存早NameNodeMap对象中。
          @NameNodeMap对象的方法:
            getNamedItem(name):返回nodeName属性等于name的节点。
            removeNamedItem(name):从列表中移除nodeName属性等于name的节点。
            setNamedItem(node):向列表中添加节点,以节点的nodeName属性为索引。
            item(num):返回位于数字num位置处的节点。
          @attributes属性中包含一系列节点,每个节点nodeName为特性名,nodeValue为特性值。

var id = element.attribute.getNamedItem("id").nodeValue;
var id = element.attribute["id"].nodeValue;
          @removeNamedItem()效果同removeAttribute(),但removeNamedItem()返回被删除特性的Attr节点。

          @迭代元素的每个特性:



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(" ");
}

            以上代码并不完善,IE7-会返回HTML元素中的所有可能特性,包括没指定的特性。
            解决方案:每个特性节点都有一个specified属性。
              该属性值为true时,表示要么在HTML中指定了相应特性,要么通过setAttribute()方法设置了该特性。
              在IE中没设置的特性的specified属性值为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(),一个参数(标签名)。
            @使用createElement()创建新元素时,也为元素设置了ownerDocument属性。
            @传入完整的元素标签,能解决IE7-中创建元素的一些问题:
              不能设置动态创建<iframe>元素的name特性;
              不能通过标签元素的reset()方法重设动态创建的<input>元素;
              动态创建的type属性值为reset的<button>元素重设不了表单;
              动态创建的一批name值相同的单选按钮彼此毫无关系。
            @上述IE7-中的问题都能通过给createElement()穿日完整的标签解决:



if(client.browser.ie && client.browser.ie <= 7){
  var iframe = document.createElement("<iframe name=\"maiframe\"></iframe>");
  var input = document.createElement("<input type=\"checkbox\"/>");
  var button = document.createElement("<buttom type=\"reset\"></button>");
  var radio1 = document.createElement("<input type=\"radio\" name=\"choice\" value=\"1\"/>");
  var radio2 = document.createElement("<input type=\"radio\" name=\"choice\" value=\"2\"/>");
}

     10.1.4 Text类型

      文本节点由Text类型表示,不支持子节点。
      @可通过nodeValue属性或data属性访问Text节点中包含的文本。
      @操作节点中的文本:
        appendData(text):将text添加到节点的末尾。
        deleteData(offset,count):从offset位置开始删除count个字符。
        insertData(offset,text):从offset位置插入text。
        replaceData(offset,count,text):用text代替从offset位置开始的count个字符。
        splitText(offset):从offset位置将文本分成两部分。
        substringData(offset,count):提取从offset位置到offset+count位置的文本。
        length属性:节点中的字符个数。
      @在修改文本节点时,字符串会经过编码,即不会字符串中的标签会与文本的形式显示:

div.firstChild.nodeValue = "Some <strong>other</strong> message";
//输出Some <strong>other</strong> message
      ① 创建文本节点

        document.createTextNode(),同上,传入的文本参数也会进行编码。
          @连续添加多个文本节点时,各相邻节点会连起来显示,中间无空格。



        function addNode(){
       
            var element = document.createElement("div");
            element.className = "message";
           
            var textNode = document.createTextNode("11111");
            element.appendChild(textNode);
           
            var anotherTextNode = document.createTextNode("22222");
            element.appendChild(anotherTextNode);
           
            document.body.appendChild(element);
        }

//输出1111122222

      ② 规范化 文本节点

        normalize():能将包含的多个文本节点合并成一个。此方法由Node类型定义,故存在于所有节点类型中。



function addNode(){

    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():此方法会将文本节点分成两个文本节点,原来的文本节点剩下没指定的,新文本节点包含指定的文本,并被此方法返回。

    10.1.5 Comment类型

      @注释类型Comment与Text类型继承自相同的基类。
      @浏览器不会识别位于</html>标签后的注释,故应该保证它们是<html>的后代。

    10.1.6 CDATASection类型

      此类型只针对XML文档,表示CDATA区域。

    10.1.7 DocumentType类型

      包含文档的dictype有关的所有信息,仅有Firefox、Safari、Chrome4 和 Opera支持。

    10.1.8 DocumentFragment类型

      @所有节点类型中,只有DocumentFragment类型没有对应的标记。
      @DOM规文档片段是一种“轻量级”文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源。
      ①document.createDocumentFragment()方法,创建文档片段。
        @继承了Node的所有方法。
        @将文档中的节点添加到文档片段中,就会从文档树中移除节点。添加在文档片段的新节点同样不属于文档树。
        @文档片段本身永远不会成为文档树的一部分。
      ②当需要给一个<ul>元素添加三个列表项时,逐个添加列表项节点会导致浏览器反复渲染和呈现新信息,使用文档片段能避免:



<body>
    <ul id="myList"></ul>
    <input type="button" value="Add Items" onclick="addItems()">

    <script type="text/javascript">
        function addItems(){
       
            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);   

           
        }

    </script>
</body>

 

        @添加后,文档片段中的子节点会被删除。

    10.1.9 Attr类型

      元素的特性在DOM中与Attr类型表示。
      @特性是存在于元素的attribute属性中的节点,但特性不被认为是DOM文档的一部分。
      @Attr类型有三个属性:name(特性名,同nodeName)、value(特性值,同nodeValue) 和 specified(布尔值,区分特性是指定还是默认)。



        function assignAttribute(){
            var element = document.getElementById("myDiv");
            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"
        }

      @实际上,使用getAttribute()等3个方法比操作特性节点更方便。

  10.2 DOM操作技术

    10.2.1 动态脚本

      ① 通过<script>元素,有 src属性指定外部文件 和 本身包围代码 2种方法向页面添加JavaScript代码。
      ② 动态脚本,指在加载页面时不存在,但在某时通过修改DOM动态添加的脚本。
        @创建动态脚本也有两种方法:插入外部文件 和 直接插入JavaScript代码。
      ③ IE中,<script>为一个特殊元素,不允许DOM访问其子节点:
        script.appendChild(document.createTextNode("function sayHi(){alert("Hello!");}")); (在IE会报错)
        @IE中可以使用script的text属性 指定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);
        }
   
        function addScript(){
            loadScriptString("function sayHi(){alert('hi');}");
            sayHi();
        }

      这样加载的代码会在全局作用域中执行,与在全局作用域中 把相同的字符串传递给你eval()一样。

    10.2.2 动态样式

      ①有2个元素 能将CSS样式包含到HTML页面中,<link>元素包含外部文件,<style>元素指定嵌入的样式。
        @加载外部样式文件是异步的,即与执行JavaScript代码的过程没有固定程序。
      ②同样的,IE中<style>为一个特殊的元素,不允许访问其子节点:
        style.appendChild(document.createTextNode("body{color:red;}")); (在IE会报错)
        @IE中可以使用访问元素的styleSheet属性的cssText属性 指定CSS样式:



        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);
        }
   
        function addStyle(){
            loadStyleString("body{background-color:red}");
        }

        @在针对IE编码时,应注意使用styleSheet.cssText属性:
          在重用同个<style>元素并再次设置这个属性时,可能会导致浏览器崩溃。将cssText属性设为空字符串也可能使浏览器崩溃。

    10.2.3 操作表格

      为了方便构建表格,HTML DOM还为<table>、<tbody> 和 <tr>元素添加了一些属性:
        为<teble>元素添加的属性和方法:
          caption:(若有)保存着对<caption>元素的指针。
          tHead:(若有)同上。
          tFoot:(若有)同上。
          tBodies:一个所有<tbody>元素的HTMLCollection。
          rows:一个所有行的HTMLCollection。
          createCaption:创建该元素,放如表格,返回引用。
          createTHead():同上。
          createTFoot():同上。
          deleteCaption():删除<caption>元素。
          deleteTHead():同上。
          deleteTFoot():同上。
          insertRow(pos):向rows集合中的指定位置 插入一行。
          deleteRow(pos):删除指定位置的一行。
        <tbody>:
          rows:一个保存着<tbody>元素中行的HTMLCollection。
          insertRow(pos):向rows集合中指定位置插入一行,返回新行的引用。
          deleteRow(pos):删除指定位置的行。
        <tr>:
          cells():一个保存着<tr>元素中的单元格的HTMLCollection。
          insertCell(pos):向cells集合中的指定位置插入一个单元格,返回新单元格引用。
          deleteCell(pos):删除指定位置的单元格。



    //创建talbe
    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);

    10.2.4 使用NodeList

      NodeList、NameNodeMap 和 HTMLColletction 三个集合都是动态的。
      @浏览器不会将创建的所有集合保存在一个列表中,而是在下一次访问集合是更新集合。
      迭代一个NodeList时,应该在比较之前,先将其length保存在一个变量中:



var divs = document.getElementByTagName("div"),
i,
len,
div;
for(i=o, len=divs.length; i<len; i++){
     div = document.createElement("div");
     document.body.sppendChild(div);
}




从这篇笔记开始整理JavaScript的第三部分:文档对象模型DOM(Document Object Model)。DOM是针对HTML和XML文档的一个API,脱胎于DHTML,由W3C负责制定相关标准,现在已经成为表现和操作页面标记的真正的跨平台、语言中立的一种标准,除了JavaScript外,其它一些语言比如SVG、MathML等也不同程度的实现了各自的DOM。

1、DOM组成和级别

  DOM分为三个组成部分和三个级别:

组成部分 说明
核心DOM 用于任何结构化文档的标准模型
XML DOM 用于XML文档的标准模型,定义了所有XML元素的对象和属性,以及访问它们的方法(接口),换句话说,XML DOM是用于获取、更改、添加或删除XML元素的标准
HMTL DOM 用于HTML文档的标准模型,定义了所有HTML元素的对象和属性,以及访问它们的方法(接口)
DOM级别 浏览器支持情况 功能模块 说明
0级 IE4、Netscape4 在W3C标准中,是没有0级的,通常所谓DOM 0级指的就是在DOM 1级规范之前的在IE4和Netscape Navigator4中支持的DHTML
1级 几乎所有现代浏览器 DOM核心(DOM Core) 规定的是如何映射基于XML的文档结构,以便简化对文档中任意部分的访问和操作
DOM HTML 在DOM核心基础上加以扩展,添加了针对HTML的对象和方法
2级 IE 9+
Opera 7-9.9(部分支持),OPera 10+
Safari 2+(部分支持)
Chrome 1+(部分支持)
Firefox 1+(几乎全部) DOM视图(DOM Views) 定义了跟踪不同文档(例如,应用CSS前后的文档)视图的接口
DOM事件(DOM Events) 定义了事件和事件处理的接口
DOM样式(DOM Style) 定义了基于CSS为元素应用样式的接口
DOM遍历和范围(DOM Traversal and Range) 定义了遍历和操作文档树的接口
DOM核心和HTML扩展 开始支持XML命名空间等
3级 IE9+
Opera9+(部分支持)
Firefox1+(部分支持) DOM加载和保存(DOM Load and Save) 引入了以统一方式加载和保存文档的方法
DOM验证(DOM Validation) 验证文档的方法
DOM核心和HTML扩展 开始支持XML1.0规范,涉及XML Infoset、XPath和XMLBase等
2、文档映射

DOM将HTML和XML文档映射成一个由不同节点组成的树型机构,每种节点都对应于文档中的信息或标记,节点有自己的属性和方法,并和其他节点存在某种关系,节点之间的关系构成了节点层次,例如:


<html>
    <head>
        <title>标题</title>
    </head>
    <body>
        <p>测试</p>
    </body>
</html>

(1)文档节点Document是每个文档的根节点。
(2)文档元素:如右图,文档节点只有一个子节点,即<html>元素,称之为文档元素。文档元素是文档的最外层元素,其他所有元素都包含在文档元素中,每个文档只能有一个文档元素。在HTML中,文档元素永远是<html>元素,但是在XML中,没有预定义元素,因此任何元素都可能成为文档元素。
(3)文档中每一段标记都通过树中的一个节点来表示,比如HTML元素通过元素节点表示,特性(attribute)通过特性节点表示,文档类型通过文档类型节点表示,而注释则通过注释节点表示。在DOM1中,总共有12种节点类型,他们都继承自一个基类型。



 
3、Node接口

类别 属性/方法 值/类型/返回类型 说明
属性 nodeName String 节点名字,根据节点类型定义。对于元素节点,就是原始的标签名
nodeValue String 节点值,根据节点类型定义。对于元素节点为null
nodeType Number 节点类型,返回12种节点类型值之一
ownerDocument Document 指向这个节点所属的文档,可以利用它直接访问文档节点,而不用层层回溯
parentNode Node 文档树中的父节点
childNodes NodeList 所有直接子节点组成的列表,不同浏览器对空白字符和<html>外的注释有不同处理,会导致childNodes不一致
firstChild Node 第一个直接子节点,没有子节点返回null
lastChild Node 最后一个直接子节点,没有子节点返回null
previousSibiling Node 前一个兄弟节点,没有则返回null
nextSibiling Node 后一个兄弟节点,没有则返回null
方法 hasChildNodes() Boolean 有子节点时返回true,否则返回false
appendChild(node) Node 在末尾添加子节点,返回新添加的节点。如果传入参数已经是文档中一部分,结果将是将该节点从原来的位置移向新位置(任何DOM节点不能同时出现在多个位置上)
removeChild(node) Node 移除节点并返回这个节点。删除后,节点仍然属于原来的文档,只是没有了位置
replaceChild(node,node) Node 传入新添加的节点和被替换的节点,返回被替换的节点。被替换的节点仍然属于原来的文档,只是没有了位置
insertBefore(node,node) Node 传入新添加的节点和参照节点,新添加节点会成为参照节点的前一个兄弟节点,如果参照节点为null,则插入到最后,相当于appendChild()。返回新添加的节点
cloneNode(boolean) Node 复制节点,参数为true时,复制节点及其所有子节点树,为false时,只复制节点本身。返回的节点属于文档所有,但没有指定父节点
normalize()   处理文档树中的文本节点,删除空文档节点或合并两个相邻的文本节点等
说明:

(1)关于节点类型nodeType,在DOM1中定义了12种常量,是作为Node类型构造函数的属性定义的(静态属性),它们对应于各自的节点类型:

节点 节点类型(nodeType,Node的静态属性) 节点名称(nodeName) 节点值(nodeValue) 父节点(parentNode) 子节点(childNodes) 说明
Document Node.DOCUMENT_NODE(9) #document null null DocumentType(最多一个)|Element(最多一个)
|Comment|ProcessingInstruction
下有进一步叙述
Element Node.ELEMENT_NODE(1) 元素的标签名 null Document|Element Element|Text|Comment|
ProcessingInstruction|
CDATASection|EntityReference
Text Node.TEXT_NODE(3) #text 节点所包含的文本 Element (不支持)没有子节点
Comment Node.COMMENT_NODE(8) #comment 注释的内容 Document|Element (不支持)没有子节点 和Text继承自相同基类,拥有除splitText()外所有字符串方法,可通过nodeValue或data属性获取注释内容
CDATASection Node.CDATA_SECTION_NODE(4) #cdata-section CDATA区域的内容 Document|Element (不支持)没有子节点 继承自Text类型,拥有除splitText()外所有字符串方法
DocumentType Node.DOCUMENT_TYPE_NODE(10) doctype的名称 null Document (不支持)没有子节点 在DOM1中不能动态创建,DocumentType对象的3个属性:
name表示文档类型名称
entities表示描述文档类型实体的NamedNodeMap
notations表示文档类型描述的符号的NamedNodeMap
DocumentFragment Node.DOCUMENT_FRAGMENT_NODE(11) #document-fragment null null 同Element类型 下有进一步叙述
Attr Node.ATTRIBUTE_NODE(2) 特性名称 特性值 null HTML中不支持,XML中可以是Text或EntityReference 有3个自己的属性:
name等于nodeName
value等于nodeValue
specified表示是否为默认设置
EntityReference Node.ENTITY_REFERENCE_NODE(5) 引用的实体名称 null     实体引用节点
Entity Node.ENTITY_NODE(6) entity name null     实体节点
ProcessingInstruction  Node.PROCESSING_INSTRUCTION_NODE(7) 与 ProcessingInstruction.target 相同 与 ProcessingInstruction.data 相同     处理指令
Notation  Node.NOTATION_NODE(12) notation name null     DTD中定义的符号
这些节点类型都实现了Node接口,因此都可以访问Node类型的属性和方法(不支持子节点的节点类型上调用appendChild()、insertBefore()、replaceChild()、removeChild()等方法时会抛出异常)。经过测试在IE9中已经可以直接访问Node类型中定义的常量值,并且IE9中这些值不能改变,而在Firefox15的版本中仍然可以修改,这应该是Firefox实现的一个Bug(原书说IE中不可访问Node的论述似有不妥)。

Node.DOCUMENT_NODE = 2;
console.info(Node.DOCUMENT_NODE);//IE9输出9,而Firefox15输出的是2
(2)关于NodeList类型,它也是一个类数组类型,有length属性,也可以通过方括号语法访问,还可以通过item()方法访问,但并不是Array的实例,如果要对其使用数组方法,必须像转换arguments对象一样来转换NodeList对象:

var node = document;//任意一个节点,这里使用文档根节点测试
console.info(node.childNodes.length);//2,直接子节点
console.info(node.childNodes[0].nodeName);//通过方括号语法访问第1个元素,索引从0开始
console.info(node.childNodes.item(1).nodeName);//通过item()方法访问第2个元素,索引从0开始
var arr = Array.prototype.slice.call(node.childNodes,0);//转换为真正的数组
console.info(arr.join(','));//可以使用数组方法了
需要特别注意的是,NodeList对象类型是一个有生命、有呼吸的对象,它的属性和元素是跟随文档变化而变化的:

var node = document;
var nodeList = node.childNodes;
var src = nodeList.length;
node.removeChild(nodeList[0]);//修改文档,会同时修改NodeList对象的属性和元素,即便是已经将其保存为另外一个变量
console.info(nodeList.length == src - 1);//true
类似NodeList这种动态变化的对象对象还有HTMLCollection、NamedNodeMap等,其中HTMLCollection还有一个namedItem()方法,可以通过元素的name获取集合中的项。

4、Document类型

  在JavaScript中,通过Document类型表示文档,而我们通常使用的document对象则是HTMLDocument(继承自Document类型)的一个实例,表示整个HTML页面。同时,docuemnt对象也是window对象的一个属性,可以作为全局对象来访问。document对象的主要属性和方法有:

类别 属性/方法 说明 备注
属性 documentElement 指向HTML页面中的<html>元素 作为document的子节点,<html>元素还可以通过document.firstChild或document.childNodes[0]等方式访问
body 直接指向HTML页面中的<body>元素 document.body的使用频率非常高
doctype 表示<!DOCTYPE>相关信息,不同浏览器差异比较大,因此用处不大 有些浏览器会把<!DOCTYPE>作为注释处理
title 包含<title>元素中的文本,显示在浏览器窗口的标题和标签页上,可以通过它修改标题 修改title属性的值不会改变<title>元素
URL 页面完整的URL,即地址栏中显示的URL 这些信息都存在于请求的HTTP头部,这些属性是为了方便在JavaScript中访问,domain的设置需要注意:
1、不能将domain设置为URL不包含的域,如URL='p2p.wrox.com',domain可以设置为wrox.com,但不能设置为ncz.net
2、不能将domain由松散的设置为紧绷的,如原来domain='wrox.com',不能设置为domain='p2p.wrox.com' 
domain 页面的域名,可以设置
referrer 链接到当前页面的那个页面的URL,没有来源页面时,为空字符串
implementation 提供浏览器对DOM实现情况的描述对象,在DOM1只有一个hasFeature()方法 hasFeature()接受两个参数:DOM功能和版本号。由于浏览器实现问题,这个方法并非百分百准确
文档元素集合 anchors 包含文档中所有带name特性的<a>元素 这些集合都是HTMLCollection对象,集合中的项会随文档的变化而更新
applets 包含文档中所有<applet>元素,已经不推荐使用
forms 包含文档中所有<form>元素,相当于document.getElementsByTagName('form')
images 包含文档中所有<img>元素,相当于document.getElementsByTagName('img')
links 包含文档中所有带href特性的<a>元素
元素获取方法 getElementById() 接受一个参数:要获取元素的ID,匹配大小写,找不到时返回null,若有多个相同ID元素,返回第一个 在IE8-中不区分大小写,并且表单元素(如<input>)中的name也被作为ID去查询
getElementsByTagName() 接受一个参数:要获取元素的标签名,返回包含0或多个元素的NodeList,在HTML中,返回HTMLCollection 传入*号时,则返回文档中所有元素,可以通过索引(调用item())、字符串(调用namedItem())、以及直接使用item()方法访问结果集
getElementsByName() HTMLDocument特有方法,返回name特性为传入参数值的元素集合,返回HTMLCollection对象 使用namedItem()时,只返回第一项,因为是按name获取的集合,集合中的name全部相同
文档写入方法 write() 输出文本,接受一个参数:写入到输出流的文本 write()和writeln()被用来向页面动态地输入内容,需要注意的是:
1、如果输出内容中含'</script>',为了防止做为标签解析而发生错误,需要特殊处理,可以写成'<\/script>'或拆分
2、如果是页面加载完成之后调用,会重写整个页面
writeln() 输出文本,并添加换行符(\n),接受一个参数:写入到输出流的文本
open() 打开网页输出流
close() 关闭网页输出流
创建方法 createElement() 创建新元素,并设置ownerDocument属性,接受一个参数:要创建元素的标签名(在HTML中不分大小写,在XML中区分) 在IE中还可以传入包含属性的完整的元素标签来创建新元素
createTextNode() 创建文本节点,接受一个参数:要插入节点中的文本(会按HTML/XML格式编码),会同时设置ownerDocument 除非把新节点添加到文档中,否则不会显示新节点
createComment() 创建新注释,接受注释文本 浏览器不会识别<html>后代注释,如要访问注释节点,需要保证是<html>元素的后代 
createCDATASection() 在XML文件中创建CDATA区域,传入节点内容 CDATA区域只会出现XML文档中,因此多数浏览器会报CDATA区域错误地解析为Comment或Element
createDocumentFragment() 创建文档片段  
createAttribute() 创建新特性节点  
说明:

(1)一般情况下,不用在document对象上调用appendChild()、insertBefore()、removeChild()、replaceChild()等方法,因为文档类型(如果存在的话)是只读的,而且它只能有一个元素子节点。

(2)document对象的创建方法,是实现动态加载脚本或样式的基础,从而可以进一步对代码模块化,实现按需加载,提升性能,这在Ext4库中已经很好地应用了。动态加载的一般方法:


function loadScript(url){//动态加载外部js文件,也可以类似的加载js代码
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = url;
    document.body.appendChild(script);
}

function loadStyle(url){//动态加载外部css文件,也可以类似的通过style元素加载css代码
    var link = document.createElement("link");
    link.rel = "stylesheet";
    link.type = "text/css";
    link.href = url;
    var head = document.getElementsByTagName("head")[0];
    head.appendChild(link);
}

5、Element类型

  Element类型用于表现XML或HTML元素,提供了对元素标签名、子节点以及特性的访问。在HTML中,元素由HTMLElement类型(或其子类型)表示,HTMLElement继承了Element类型,并添加了对应每个HTML元素都存在的标准特性的属性。HTMLElement类型常用属性和方法总结如下:

类别 属性/特性 说明
Element类型属性 tagName 这个属性是所有Element都有的,值和nodeName相同,表示元素标签名,在HTML中,返回的标签名始终大写,在XML中,和源代码一致
HTML元素标准特性 id id 元素在文档中的唯一标识符
title title 有关元素的附件说明信息,一般通过工具条显示出来
lang lang 元素内容的语言代码,很少使用
dir dir 语言的方向,ltr:从左至右,rtl:从右至左,也很少使用
className class 元素的CSS类,因为class是保留字,所以属性命名为className
特性属性 attributes 这个是属性只有Element类型使用,是一个NamedNodeMap值,属于一个“动态”集合
特性方法 getAttribute() 参数:特性名。参数必须与实际的特性名相同,因此是class而不是className,给定特性不存在时,返回null,这个方法也可以获取自定义特性,特性名不区分大小写
setAttribute() 参数:特性名和特性值。如果已存在该特性,替换现有的值,如果不存在,就创建并赋值。通过这个方法设置特性时,会把特性名转换为小写形式
removeAttribute() 参数:特性名。彻底删除元素的特性,不仅会清除特性的值,也会从元素对象中删除特性
特性节点方法 getAttributeNode() 返回对应特性的Attr节点,element.getAttributeNode('align')相当于element.attributes['align']
setAttributeNode() 设置元素的Attr节点
其它方法 getElementsByTagName() 在当前元素的后代节点中搜索,其它用法和Document类型的同名方法一样
说明:

(1)特殊特性:

  A、class特性,其对应DOM对象的属性为className,在特性方法操作中参数需要传入class,而对象属性操作需要设置className属性。

  B、style特性,在通过getAttribute()访问时,返回的是style特性值中包含的CSS文本,而通过属性来访问它则会返回一个对象。

  C、事件处理特性,比如onclick,当在元素上使用时,onclick特性中包含的是JavaScript代码,如果通过getAttribute()访问,返回相应代码的字符串,而在访问onclick属性时,会返回一个JavaScript函数(没有相应特性时返回null)。

(2)关于自定义特性和属性,在HTML5规范中,需加上“data-”前缀。

  A、给节点设置特性值时,会同步修改相应DOM对象的属性值,但是设置自定义特性的值时,一般浏览器是不会为相应的DOM对象添加属性的,然而IE也会为自定义特性创建属性。

  B、直接给DOM对象设置属性值时,会同步修改相应节点元素的特性值,但是一般浏览器中自定义属性不会成为元素的特性,使用getArrtibute()时会返回null,然而IE会为自定义属性创建特性。

(3)HTMLElement类型是HTML中元素的基类型,对应不同的标签,还有很多更加具体的子类型,这些子类型也有与之相关的特性和方法,比如对应<body>标签有HTMLBodyElement类型、对应<table>标签有HTMLTableElement类型等。

(4)元素的子节点,可以有任意数目的子节点和后代节点,childNodes属性则包括了所有直接子节点,但是由于不同浏览器在处理注释、文本等节点的不同,会使得childNodes也不同,因此,如果需要遍历元素子节点的话,需要添加节点类型判断:

for(var i=0,l=element.childNodes.length; i < l; i++){
    if(element.childNodes[i].nodeType === 1)//过滤元素子节点
    {
    //对元素子节点做操作
    }
}
(5)元素的每一个特性都由一个Attr节点表示,每个节点都保存在一个NamedNodeMap对象中,这个对象和NodeList与HTMLCollection类似,是一个“动态”的,随文档变化而变化,它有下面的一些方法:

方法 说明
getNamesItem(name) 返回nodeName等于name的节点
removeNamedItem(name) 从列表中移除nodeName等于那么的节点,调用removeNamedItem()与在元素上调用removeAttribute()效果相同,只是前者返回被移除的Attr节点
setNamedItem(node) 向列表中添加节点,以节点的nodeName属性为索引
item(pos) 返回位于数字pos位置处的节点
元素的attributes属性返回的就是一个NamedNodeMap对象,其中包含一系列Attr节点,每个节点的nodeName就是特性名称,nodeValue就是特性值,可以使用attributes属性来遍历元素的特性(原书第268页):


function outputAttributes(element){
    var pairs = new Array(),
        attr;
    for(var i=0, len=element.attributes.length; i < len; i++){
        attr = element.attributes[i];
        if(attr.specified){//specified属性表示特性值是设置还是默认的,为true表示设置的
            pairs.push(attr.nodeName + "=\"" +attr.nodeValue + "\"");
        }   
    }
    return pairs.join(" ");//以空格连接各个特性并返回
}

6、Text类型

  文本节点由Text类型表示,包含的是可以按字面解释的纯文本内容,可以包含转义后的HTML字符,但不能包含HTML代码,Text类型的主要属性和方法有:

类别 属性/方法 说明
属性 length 文本字符数
data 文本字符,和nodeValue值相同
方法 appendData(text) 将text添加到文本节点末尾
deleteData(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为止处的字符串
说明:

(1)在Node类型中定义了一个normalize()方法,用于将相邻的两个或多个文本子节点合并,需要注意的是这个方法需要在文本节点的父节点上调用;与之相反的是,Text类型提供了splitText()方法,它会将原文本节点分成两个文本节点,原文本节点将包含从开始到指定位置之前的内容,新文本节点包含剩下的内容,最终返回新文本节点。

(2)默认情况下,每个可以包含内容的元素最多只能有一个文本子节点,而且文本不能为空。通过DOM脚本操作时,可能存在有多个文件子节点的情况。

(3)设置文本节点时需要注意,字符串会经过HTML或XML编码。

7、DocumentFragment类型

  在所有节点类型中,只有DocumentFragment是没有对应的标记的,DOM规定DocumentFragment是一种“轻量级”的文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源。DocumentFragment类型可以作为一个容器来使用,可以把后面要对文档进行的添加、修改、移除等操作先对DocumentFragment进行,然后再将DocumentFragment添加至文档中,从而避免DOM视图的多次渲染。例如:


function addItems(){       
    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); //将容器中的节点添加到文档中(但容器本身不会添加至文档树),这样只需要渲染一次页面   
}

需要注意的是,在DocumentFragment中的节点不属于文档,如果将文本中的节点添加至DocumentFragment中,该节点将会从文档树中移除。

8、操作表格

  <table>元素是HTML中最复杂的结构之一,在HTML DOM中还为<table>、<tbody>、<tr>等元素添加了一些属性和方法(请注意table、tbody、tr及td之间的关系):

元素 类别 属性/方法 说明
<table> 属性 caption 保存着对<caption>元素(如果有)的指针
tBodies 是一个<tbody>元素的HTMLCollection
tHead 保存着对<thead>元素(如果有)的指针
tFoot 保存着对<tfoot>元素(如果有)的指针
rows 表格中所有行的HTMLCollection
方法 createTHead() 创建<thead>元素,将其放到表格中,返回引用
createTFoot() 创建<tfoot>元素,将其放到表格中,返回引用
createCaption() 创建<caption>元素,将其放到表格中,返回引用
deleteTHead() 删除<thead>元素
deleteTFoot() 删除<tfoot>元素
deleteCaption() 删除<caption>元素
deleteRow(pos) 删除指定位置的行
insertRow(pos) 向rows集合中的指定位置插入一行
<tbody> 属性 rows 保存着<tbody>元素中行的HTMLCollection
方法 deleteRow(pos) 删除指定位置的行
insertRow(pos) 向rows集合中的指定位置插入一行,返回新插入行的引用
<tr> 属性 cells 保存着<tr>元素中单元格的HTMLCollection
方法 deleteCell(pos) 删除指定位置的单元格
insertCell(pos) 想cells集合中的指定位置插入一个单元格,返回新插入单元格的引用
注意,上表中列出的是原书中提及元素的属性和方法,并不全面,比如对应<td>元素还有HTMLTableCellElement对象,而<tr>对应对象还有rowIndex属性等,实际使用时可以查阅相关的DOM参考手册。这里旨在通过主要的一些属性和方法明确概念,而非参考大全。

DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序接口)。

Document类型

文档的子节点

虽然DOM标准规定Document节点的子节点可以是DocumentType,Element,ProcessingInstruction或Comment,但还有两个内置的访问其子节点的快捷方式。第一个就是
documnetElement属性,该属性始终指向HTML页面中的<html>元素。另一个就是通过childNodes列表访问文档元素,但通过documentElement属性则能更快捷、更直接地访问该元素。

documnetElement、firstChild和childNodes[0]的值相同,都指向<html>元素
var html=documnet.documnetElement; //取得对<html>的访问
alert(html===documnet.childNodes[0]); //true
alert(html===documnet.firstChild); //true
文档信息

修改tilte属性的值不会改变<title>元素。

想要取得文档中的所有元素,可以向getElementsByTagName()中传入"*",在JavaScript及CSS中,星号(*)通常表示“全部”,下面看一个例子:
var allElements=documnet.getElementsByTagName("*");

可以使用write()和writeIn()方法动态地包含外部资源,例如JavaScrip文件等。在包含JavaScript文件时,必须注意不能直接包含字符串"</script>",因为这会导致该字符串
被解释为脚本块的结束,它后面的代码将无法执行。为避免这个问题,只需加入转义符\即可,如下:

<body>
<script type="text/javascript">
documnet.write("<script type=\"text/javascript\" scr=\"file.js\">"+
"<\/script>");
</script>
</body>

在HTML中,标签名始终都以全部大写表示;而在XML(有时候也包括XHTML)中,标签名则始终会与源代码中保持一致。
动态脚本

动态加载外部脚本

var script=documnet.createElement("script");
script.type="text/javascript";
script.scr="client.js";
documnet.body.appendChild(script);
动态嵌入脚本


function loadScriptString(code){
var script=documnet.createElement("script");
script.type="text/javascript";
try{
script.appendChild(documnet.createTextNode(code));
}catch(ex){
script.text=code;
}
documnet.body.appendChild(code);
}

下面是调用这个函数的示例:

loadScriptString("function sayHi(){alert('Hi');}");
以这种方式加载的代码会在全局作用域中执行,而且当脚本执行后将立即可用。实际上,这样执行代码与在全局作用域中把相同的字符串传递给eval()是一样的。
动态样式

动态加载外部样式

var link=documnet.createElement("link");
link.rel="stylesheet";
link.type="text/css";
link.href="style.css";
var head=documnet.getElementsByTagName("head")[0];
head.appendChild(link);
必须将<link>元素添加到<head>而不是<body>元素,才能保证在所有浏览器中的行为一致。
动态嵌入样式


function loadStypeString(css){
var style=documnet.createElement("style");
style.type="text/css";
try{
style.appendChild(documnet.createTextNode(css));
}catch(ex){
style.stylesheet.cssText=css;
}
var head=documnet.getElementsByTagName("head")[0];
head.appendChild(link);
}

调用这个函数的示例如下:
loadStypeString("body{background-color:red}");
DOM可以将任何HTML或XML文档描绘成一个由多层节点构成的结构.
1. Node类型
DOM1级定义了一个Node接口,该接口将由DOM中的所有节点类型实现.javascript中的所有节点类型都继承自Node类型,因此所有节点类型都共享着相同的基本属性和方法.
每个节点都有一个nodeType属性,用于表明节点的类型:
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);
而我们可以这样比较:
print(document.nodeType);  //9
1. nodeName和nodeValue属性
nodeName保存元素的标签名,而nodeValue始终为null.由于这两个属性完全取决于节点的类型,所以使用之前最好进行一次比较:
if (someNode.nodeType == 1) { /*do something*/}
因为nodeType==1说明它为一个元素节点(Node.ELEMENT_NODE),所以可以进行对nodeName和nodeValue的操作.
<html>
<script type="text/javascript" src="./print.js"></script>
<script type="text/javascript" src="./EventUtil.js"></script>
<Form method="post" id="myForm">
    <ul>
        <li><input type="radio" name="color" value="red">Red</li>
        <li><input type="radio" name="color" value="green">green</li>
        <li><input type="radio" name="color" value="blue">blue</li>
    </ul>
</form>
<body>
<script type="text/javascript">
var form = document.getElementById("myForm");
var red = document.getElementsByName("color");
</script>
</body>
</html>
firebug上显示如下:


2. 节点关系
每个节点都有一个childNodes属性,其中保存着一个NodeList对象.NodeList是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点.NodeList对象的独特之处在于:它实时反映DOM结构的变化.

我们可以通过方括号或者item来访问NodeList中的节点:
var firstChild = someNode.childNodes[0];
var secondChild = someNode.childNodes.item(1);
var count = someNode.childNodes.length;
而我们可以遍历childNodes来枚举所有的成员:
function convertToArray(nodes) {
    var array = null;
    try {
        array = Array.prototype.slice.call(nodes, 0);
    } catch (ex) {
        array = new Array();
        for (var i = 0, len = nodes.length; i < len; i++) {
            array.push(nodes[i]);
        }
    }

    return array;
}
而每个节点都有一个parentNode属性,该属性指向文档树中的父节点.我们可以通过列表中的每个节点的previousSibling和nextSibling属性,访问同一列表中的其他节点.列表中第一个节点的previousSibling属性值为null,而最后一个节点的nextSibling也为null:
对于上面的代码,我们也可以firebug如下:

而父节点也有firstChild和lastChild属性,指向第一个节点和最后一个节点:

3. 操作节点
appendChild: 向childNodes列表的末尾添加一个节点.如果新插入的节点已经存在childNodes中,则进行转移操作(DOM节点不能同时出现在文档中的多个位置).
//someNode有多个子节点
var returnedNode = someNode.appendChild(someNode.firstChild);
print(returnedNode == someNode.firstChild);//false
print(returnedNode == someNode.lastChild);//true
insertBefore:接收两个参数,要插入的节点和作为参照的节点
//插入后成为最后一个子节点
returnedNode = someNode.insertBefore(newNode, null);
print(newNode == someNode.lastChild);   //true

//插入后成为第一个字节点
var returnedNode = someNode.insertBefore(newNode, someNode.firstChild);
print(newNode == someNode.firstChild);  //true

//插入到最后一个字节点前面
returnedNode = someNode.insertBefore(newNode, someNode.lastChild);
print(newNode == someNode.childNodes[someNode.childNodes.length - 2]);  //true
replaceChild:接收两个参数,要插入的节点和替换的节点
//替换第一个字节点
var returnedNode = someNode.replaceChild(newNode, someNode.firstChild);

//替换最后一个字节点
returnedNode = someNode.replaceChild(newNode, someNode.lastChild);
removeChild:接收一个参数,移除节点.
//移除第一个字节点
var returnedNode = someNode.removeChild(someNode.firstChild);

//移除最后一个字节点
returnedNode = someNode.removeChild(someNode.lastChild);
实际的例子如下:
<html>
<script type="text/javascript" src="./print.js"></script>
<script type="text/javascript" src="./EventUtil.js"></script>
<body id="myBody">
<div id="myDiv1" value="hello1">hello1</div>
<div id="myDiv2" value="hello2">hello2</div>
<div id="myDiv3" value="hello3">hello3</div>
<script type="text/javascript">
var body = document.getElementById("myBody");
var myDiv1 = document.getElementById("myDiv1");
//插入后,界面显示hello2 hello3  hello1
var newDiv1 = body.appendChild(myDiv1);
print(newDiv1 == myDiv1);   //true

//插入后,界面显示hello1 hello2 hello3
myDiv1 = document.getElementById("myDiv1");
var myDiv2 = document.getElementById("myDiv2");
body.insertBefore(myDiv1, myDiv2);

//myDiv2被myDiv1代替,界面上显示hello1 hello3
myDiv1 = document.getElementById("myDiv1");
myDiv2 = document.getElementById("myDiv2");
body.replaceChild(myDiv1, myDiv2);

//移除myDiv1,界面上显示hello3
myDiv1 = document.getElementById("myDiv1");
body.removeChild(myDiv1);

</script>
</body>
</html>
cloneNode:用于创建调用这个方法的节点的一个完全相同的副本.接收一个参数:如果为true则表示进行深复制,即复制节点及其整个子节点树,为false则单单复制节点本身.
<Form method="post" id="myForm">
    <ul>
        <li><input type="radio" name="color" value="red">Red</li>
        <li><input type="radio" name="color" value="green">green</li>
        <li><input type="radio" name="color" value="blue">blue</li>
    </ul>
</form>
<body>
<script type="text/javascript">
var form = document.getElementById("myForm");
var deepList = form.cloneNode(true);
print(deepList.childNodes.length);  //3
var shallowList = form.cloneNode(false);
print(shallowList.childNodes.length);   //0
</script>
normalize():处理文档树中的文本节点.

在处理DOM操作中,可能会出现文本节点不包含文本,或者接连出现两个文本节点的情况.当在某个节点上调用这个方法时,就会在该节点的后代节点中查找上述情况.如果找到了空文本节点,则删除它;如果找到相邻的文本节点,则将它们合并为一个文本节点.
2. Document类型
javascript通过Document类型表示文档.在浏览器中,document对象是HTMLDocument(继承自Document类型)的一个实例,表示整个HTML页面.而且,document对象是window对象的一个属性,因此可以将其作为全局对象来访问(Document并不表示具体的节点,而是表示整个HTML页面).Document节点具有下列特征:
1. nodeType的值为9
2. nodeName的值为#document
3. nodeValue的值为null
4. parentNode的值为null
5. ownerDocument的值为null
6. 其子节点可能是一个DocumentType(最多一个),Element(最多一个),ProcessingInstruction或Comment.
1. 文档的子节点
快速访问节点:documentElement和ChildNodes:
<html id="hello">
<body id="world">
<script type="text/javascript">
function print(str) {
    document.write(str + "<br />");
}

var html = document.documentElement;
print(html === document.childNodes[0]); //true
print(html === document.firstChild);    //true

</script>
</body>
</html>
而我们在firebug里面输入:


这实际上并不正确,因为document.childNodes表示页面中第一个层次的节点,一般来说是<html>,但是存在两个第一层次的节点:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
这时候document.childNodes[0]并不等于document.documentElement了.所以我们一般使用document.documentElement来调用<html>,用document.doctype来调用<!DOCTYPE>标签:


多数情况下,我们都用不着在document对象上调用appendChild(),removeChild()和replaceChild()方法,因为文档类型是只读的,而且它只能有一个元素子节点(html).
2. 文档信息
document通常有以下属性:title(包含<title>的内容),URL(地址栏显示的URL),domain(页面的域名)和referrer(链接到当前页面的那个页面的URL):
<html id="hello">
<title>this is a title</title>
<body id="world">
<script type="text/javascript">
function print(str) {
    document.write(str + "<br />");
}

setTimeout(function(){
    location.replace("http://www.wrox.com/");
}, 1000);

</script>
</body>
</html>
在还没有跳转的情况下,在页面输入输出为:


但是,跳转之后为:

3. 查找元素
getElementById():接收一个参数为要取得元素的ID.(但是如果多个元素的ID相同,则只返回第一次出现的元素,但是在DOM情况下,一般ID都是唯一的)
getElementsByTagName():接收一个参数为要取得元素的标签名.而返回的是包含零个或多个元素的NodeList.
namedItem():通过元素的name来取得集合中的项(多个name相同情况下,只会取第一个name的值)
getElementsByName():根据元素的name来取得集合中的所有项.
输入代码如下:
<html id="hello">
<title>this is a title</title>
<body id="world">
<script type="text/javascript">
function print(str) {
    document.write(str + "<br />");
}

</script>

<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>
</body>
</html>
浏览器显示如下:


而我们在firebug里面的调试信息如下:

4. 文档写入
write:要写入的输出流的文本
writeln:要写入的输出流的文本,但是字符串末尾会加换行符\n
<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>
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.
要访问元素的标签名,可以使用nodeName属性,也可以使用tagName属性;这两个属性会返回相同的值.
<html>
<body>
    <div id="myDiv"></div>
</body>
</html>
而firebug里面显示如下:


由于显示的DIV为大写,但可能存在情况是nodeName为小写.所以我们进行比较的时候,最好要用toLowerCase函数,把它转换为小写.
1. HTML元素
所有HTML元素都由HTMLElement类型表示,不是直接通过这个类型,也是通过它的子类型来表示.下列是HTML元素中都存在的标准特性:
1. id,元素在文档中的唯一标识符.
2. title,有关元素的附加说明,一般通过工具提示条显示出来.
3. lang,元素内容的语言代码,很少使用
4. dir,语言方向.ltr(left-to-right)或者rtl(right-to-left)
5. className,元素指定的CSS类
<html>
<body>
    <div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr">hello world</div>
</body>
</html>
firebug调试信息如下:


这里特别有用的一点是title属性,当我们把鼠标放在内容上时候,就会显示出来.
2. 取得特性
每个元素都有一个或多个特性.这些特性的内容是给出相应元素或其他内容的附加信息.getAttribute()用于取得特性,它区别于直接使用对象的方法是:它可以调用自定义的属性:
<html>
<meta charset="utf-8" />
<head>
</head>
<body>
<div id="myDiv1" title="this is a div" myValue="value">hello world</div>
</body>
<script type="text/javascript" >
var div = document.getElementById("myDiv1");
</script>

</html>
firebug调试信息如下:


有两类特殊的特性,它们虽然有对应的属性名,但是属性的值与通过getAttribute()返回的值并不相同.第一类特性就是style,用于通过CSS为元素指定样式.在通过getAttribute访问时,返回的style特性值中包含的是CSS文本,而通过属性来访问它则会返回一个对象.第二类是onclick这样的事件处理程序.当在元素上使用时,onclick特性中包含的是javascript代码,如果通过getAttribute访问时,则会返回相应代码的字符串.而在访问onclick属性时,则会返回一个javascript函数.
由于存在这些差别,在通过javascript以编程方式操作DOM时,开发人员经常不使用getAttribute,而只是使用对象的属性,除非取得自定义特性才使用getAttribute方法.
3. 设置特性
我们可以通过setAttribute来设置特性,当然也是可以直接通过设定属性值来达到目标.但是setAttribute的方法可以设定自定义的特性:
<html>
<body>
    <div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr" data-my_special_attribute="my attribute">hello world</div>
    <script type="text/javascript">
        var div = document.getElementById("myDiv");
        div.setAttribute("data-my_special_attribute", "new my attribute");
        document.write(div.getAttribute("data-my_special_attribute"));  //new my attribute
    </script>
</body>
</html>
但是我们不能使用div.data-my_special_attribute="new my attribute"来进行自定义属性的设置,这是无效的.
我们也可以直接通过removeAttribute来删除属性.
4. attributes属性
Element类型是使用attributes属性的唯一一个DOM节点类型.它包含了一个NamedNodeMap的动态集合,具有下列方法:
1. getNamedItem(name):返回nodeName属性等于name的节点;
2. removeNamedItem(name):从列表中移除nodeName属性等于name的节点.
3. setNamedItem(node):向列表中添加节点,以节点的nodeName属性为索引.
4. item(pos):返回位于数字pos位置处的节点.
而nodeValue就是特性的值,nodeName就是属性的名称.
<html>
<body>
    <div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr" data-my_special_attribute="my attribute">hello world</div>
    <script type="text/javascript">
        var div = document.getElementById("myDiv");
        var id = div.attributes.getNamedItem("id").nodeValue;
        document.write(id + "<br />");    //myDiv
        div.attributes["id"].nodeValue = "new Div";
        id = div.attributes.getNamedItem("id").nodeValue;
        document.write(id); //new Div
    </script>
</body>
</html>
但是,这attributes的方法不够好用,最好使用getAttribute的方法.而attributes的方法可以用于遍历元素的所有特性:
       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(" ");
        }
但是IE7及更早的版本可能包含所有的特性,所以我们需要一次判断:每个特性节点都有一个名为specified的属性,这个属性的值如果为true,则意味着要么是在HTML中指定了相应特性,要么是通过setAttribute()方法设置了该特性.所以算法修改为:
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(" ");
}
5. 创建元素
通过document.createElement()方法来创建新元素.但是新元素的创建还需要appendChild(),insertBefore()或replaceChild()方法添加到文档树中:
<script type="text/javascript">
var div = document.createElement("div");
div.id = "myDiv2";
var body = document.body;
body.appendChild(div);
var myDiv2 = document.getElementById("myDiv2");
var textNode = document.createTextNode("haha");
myDiv2.appendChild(textNode);
</script>
4. Text类型
文本节点由Text类型表示,包含纯文本内容.纯文本中可以包含转义后的HTML字符,但不能包含HTML代码.Text具有以下的特征:
1. nodeType的值为3;
2. nodeName的值为"#text";
3. nodeValue的值为节点所包含的文本;
4. parentNode是一个Element;
5. 不支持(没有)子节点.
可以通过nodeValue属性或data属性访问Text节点中包含的文本,这两个属性中包含的值相同.以下方法可操作节点中的文本:
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为止处的字符串.
<html>
<body>
    <div id="myDiv1" title="Body text">hello world1</div>
    <div id="myDiv2" title="Body text">hello world2</div>
    <div id="myDiv3" title="Body text">hello world3</div>
    <script type="text/javascript">
    var div = document.getElementById("myDiv1");
    div.firstChild.nodeValue = "new hello world1";  //new hello world1
    div.firstChild.appendData(" ???");      //new hello world1 ???
    div.firstChild.deleteData(0, 5);        //ello world1 ???
    </script>
</body>
</html>
1. 创建文本节点
可以使用document.createTextNode()创建新文本节点,接受一个参数--要插入节点中的文本.但是我们要把新节点添加到文档树中已经存在的节点.
<html>
<body>
    <div id="myDiv1" title="Body text">hello world1</div>
    <script type="text/javascript">
    var div = document.getElementById("myDiv1");

    var textNode = document.createTextNode("____Hello world!");
    //两个节点连接起来
    div.appendChild(textNode);      //hello world1____Hello world!
    </script>
</body>
</html>
这里必须注意,虽然输出:hello world1____Hello world!,但是这里是两个文本相邻显示而已!
而我们需要函数normalize()来将所有的文本合并起来:

当然,我们也可以使用splitText来分割字符串:
<html>
<body>
    <div id="myDiv1" title="Body text">hello world1</div>
    <script type="text/javascript">
    var div = document.getElementById("myDiv1");

    var textNode = document.createTextNode("____Hello world!");
    //两个节点连接起来
    div.appendChild(textNode);      //hello world1____Hello world!

    div.normalize();

    div.firstChild.splitText("hello world1".length);
    </script>
</body>
</html>
firebug调试如下:


5. Comment类型
注释在DOM中是通过Comment类型来表示的.Comment节点具有下列特征:
1. nodeType的值为8;
2. nodeName的值为"#comment";
3. nodeValue的值为注释的内容.
4. parentNode可能是document或Element;
5. 不支持(没有)子节点.
Comment类型与Text类型继承自相同的基类,拥有除了splitText之外的所有操作方法.注释节点可以通过父节点来访问.
<html>
<body>
    <!--the comment 1-->
    <div id="myDiv1" title="Body text"><!--the comment 2--></div>
    <script type="text/javascript">
    </script>
</body>
</html>
而firebug调试如下:


6. CDATASection类型
CDATASection类型只争对基于XML的文档,表示的是CDATA区域.
1. nodeType的值为4;
2. nodeName的值为"#cdata-section";
3. nodeValue的值是CDATA区域中的内容;
4. parentNode可能是Document或Element;
5. 不支持(没有)子节点.
2. DOM操作技术
1. 动态脚本
使用<script>元素可以向页面中插入javascript代码,一种方式是通过其src特性包含外部文件,另一种方式就是用这个元素本身来包含代码.
当我们加载如下脚本的时候:
<script type="text/javascript" src="client.js"></script>
我们可以通过封装一个函数来达到相同的目的:
   function loadScript(url) {
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = url;
        document.body.appendChild(script);
    }
    loadScript("client.js");
当我们面对另一种加载js代码的方式时候:
   <script type="text/javascript">
    function sayHi() {
        alert("Hi");
    }
    </script>
我们可以这样编写:
       var script = document.createElement("script");
        script.type = "text/javascript";
        script.appendChild(document.createTextNode("function sayHi() {alert('Hi');}"));
        document.body.appendChild(script);
为了应付可恶的IE,则代码最终修改如下:
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');}");
2. 动态样式
<link>元素用于包含来自外部的文件,而<style>元素用于指定嵌入的样式.所谓动态样式是指页面刚加载时不存在的样式;动态样式是在页面加载完成后动态添加到页面中的.
<link rel="stylesheet" type="text/css" href="styles.css">
我们可以动态编写如下:
   var link = document.createElement("link");
    link.rel = "stylesheet";
    link.type = "text/css";
    link.href = "style.css";
    var head = document.getElementsByTagName("head")[0];
    head.appendChild(link);
而对于<style>格式:

    <style type="text/css">
    body {
        background-color : red;
    }
    </style>
我们可以修改如下:
   var style = document.createElement("style");
    style.type = "text/css";
    style.appendChild(document.createTextNode("body{background-color : red}"));
    var head = document.getElementsByTagName("head")[0];
    head.appendChild(style);
封装的函数如下:
function loadStyle(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);
}

loadStyle("styles.css");
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}");
2. DOM扩展
1. 选择符API
querySelector()方法:接收一个CSS选择符,返回与该模式匹配的第一个元素,没有找到匹配则返回null.
querySelectorAll()方法:和querySelector方法类似,只是返回所匹配的所有元素,是一个NodeList的实例.
<body>
<div id="myDiv" title="this is a div">hello world</div>
<div class="selected" title="this is a class">class</div>
<img class="button" id="button1" />
<img class="button" id="button2" />

<script type="text/javascript">
//取得body元素
var body = document.querySelector("body");
//取得ID为"myDiv"的元素
var myDiv = document.querySelector("#myDiv");
//取得类为"selected"的第一个元素
var selected = document.querySelector(".selected");
//取得类为"button"的第一个图像元素
var img = document.body.querySelector("img.button");
</script>
浏览器显示如下:


而querySelectorAll的方法使用如下:
   //取得某<div>中的所有<em>元素(类似于getElementsByTagName("em"))
    var ems = document.getElementById("myDiv").querySelectorAll("em");

    //取得类为"selected"的所有元素
    var selected = document.querySelectorAll(".selected");

    //取得所有<p>元素中的所有<strong>元素
    var strongs = document.querySelectorAll("p strong");
得到NodeList后我们可以通过[]或者item来获取其值.
但是如果传入了浏览器不支持的选择符或者选择符有语法错误,则querySelector()和querySelectorAll()会抛出错误.
2. 元素遍历
新定义了DOM元素的5个属性:
1. childElementCount:返回子元素(不包括文本节点和注释)的个数
2. firstElementChild:指向第一个子元素;firstChild的元素版
3. lastElementChild:指向最后一个子元素;lastChild的元素版
4. previousElementSibling:指向前一个同辈元素;previousSibling的元素版
5. nextElementSibling:指向后一个同辈元素;nextSibling的元素版
备注:元素版的意思是:此节点必定为元素,因为递归childNodes的情况下,存在文本节点或者注释或者换行等等.
例子如下:我们遍历某元素的所有子元素,通常需要编写以下代码:
var i,
    len,
    child = element.firstChild;
while (child != element.lastChild) {
    if (child.nodeType == 1) {  //检查是不是元素
        processChild(child);
    }
    child = child.nextSibling;
}
而如今我们可以这样编写
var i,
    len,
    child = element.firstElementChild;
while (child != element.lastElementChild) {
    processChild(child);
    child = child.nextElementSibling;
}
3. HTML5
1. 与类相关的补充
class属性被使用过多,所以需要添加一些API来优化其操作:
1. getElementsByClassName()方法
此方法接收一个参数,即一个包含一或多个类名的字符串,返回带有指定类的所有元素的NodeList.传入多个类名时,类名的先后顺序不重要.
调用这个方法时,只有位于调用元素子树中的元素才会返回.在document对象上调用getElementsByClassName()始终会返回与类名匹配的所有元素,在元素上调用该方法就只会返回后代元素中匹配的元素:
<body>
    <div class="username" id="myDiv1">hello world</div>
    <div class="current" id="myDiv2">hello world</div>
    <div class="username current" id="myDiv3">hello world</div>
<script type="text/javascript">
var myDiv1 = document.getElementById("myDiv1");
var errorUserName = myDiv1.getElementsByClassName("username");
var userName = document.getElementsByClassName("username");
var allCurrentUserNames = document.getElementsByClassName("username current");
</script>
</body>
firebug调试如下:


2. classList属性
在操作类名时,需要通过className属性添加,删除和替换类名.但是HTML5之前必须读取出整个类名,然后进行操作.HTML5定义了新集合类型DOMTokenList,此类型定义了如下的方法:
1.add(value):将给定的字符串值添加到列表中.如果值已经存在,就不添加了.
2. contains(value):表示列表中是否存在给定的值,如果存在则返回true,否则返回false.
3. remove(value):从列表中删除给定的字符串.
4. toggle(value):如果列表中已经存在给定的值,删除它;如果列表中没有给定的值,添加它.
这样有了classList属性,除非需要全部删除所有类名,或者完全重写元素的class属性,否则也就用不到className属性了.
<body>
    <div class="username" id="myDiv1">hello world</div>
    <div class="current" id="myDiv2">hello world</div>
    <div class="bd user disabled" id="myDiv3">hello world</div>
<script type="text/javascript">
var myDiv3 = document.getElementById("myDiv3");
</script>
firebug调试如下:


2. 焦点管理
1. document.activeElement属性
这个属性始终会引用DOM中当前获得了焦点的元素.元素获得焦点的方法有页面加载,用户输入(通常是通过按Tab键)和在代码中调用focus()方法:
var button = document.getElementById("myButton");
button.focus();
alert(document.activeElement === button);   //true
2. document.hasFocus()方法
此方法用于确定文档是否获得了焦点:
var button = document.getElementById("myButton");
button.focus();
alert(document.hasFocus()); //true
通过检查文档是否获得了焦点,可以知道用户是不是正在与页面交互.
3. HTMLDocument的变化
1. readyState属性
存在两个值:loading,正在加载文档. complete,已经加载完文档.
使用document.readyState的最恰当方式,就是通过它来实现一个指示文档已经加载完成的指示器:
if (document.readyState == "complete") {
    //执行操作
}
2. 兼容模式
compatMode属性:在标准模式下,document.compatMode的值等于"CSS1Compat",而在混杂模式下,document.compatMode的值等于"BackCompat":
if (document.compatMode === "CSS1Compat") {
    alert("Standards mode");
} else {
    alert("Quirks mode");
}
3. head属性
var head = document.head || document.getElementsByTagName("head")[0];
4. 字符集属性
charset属性表示文档中实际使用的字符集,defaultCharset表示默认浏览器及操作系统的设置,当前文档默认的字符集应该是什么:
5. 自定义数据属性
HTML5规定可以为元素添加非标准的属性,但要添加前缀data-,目的是为元素提供与渲染无关的信息,或者提供语义信息.这些属性可以任意添加,随意命名,只要以data-开头即可(但是一定要以小写字母来命名):
<body>
    <div class="username" id="myDiv1" data-appId="12345" data-myname="Nicholas">hello world</div>
<script type="text/javascript">
var div = document.getElementById("myDiv1");

var appId = div.dataset.appId;  //undefined--只是因为data-appId中包含大写字母
var myName = div.dataset.myname;    //Nicholas
</script>
而实例如下
<body>
    <div class="username" id="myDiv1" data-appid="12345" data-myname="Nicholas">hello world</div>
<script type="text/javascript">
var div = document.getElementById("myDiv1");

//取得自定义属性的值
var appId = div.dataset.appid;
var myName = div.dataset.myname;   

//设置值
div.dataset.appId = 23456;
div.dataset.myname = "Michael";

if (div.dataset.myname) {
    print("Hello, " + div.dataset.myname);  //Hello, Michael
}
</script>
6. 插入标记
DOM在操作大量新的HTML时候会很麻烦,因为需要一一创建DOM节点然后一一的插入.而HTML5提供了一些属性用于处理这种情况.
1. innerHTML属性
在读模式下,innerHTML属性返回与调用元素的所有子节点(包括元素,注释和文本节点)对应的HTML标记.在写模式下,innerHTML会根据指定的值创建新的DOM树,然后用这个DOM树完全替换调用元素原先的所有子节点.
替换调用元素原先的所有子节点.
<body>
    <div id="content">
        <p>This is <strong>paragraph</strong> wit a list following it.</p>
        <ul>
            <li>Item 1</li>
            <li>Item 2</li>
            <li>Item 3</li>
        </ul>
    </div>
<script type="text/javascript">
var div = document.getElementById("content");

//读模式下显示HTML
var innerHtml = div.innerHTML;
print(innerHtml);

//写模式下更改HTML的内容
div.innerHTML = "hello world";
</script>
</body>
浏览器显示如下:


使用innerHTML也有一些限制:通过innerHTML插入<script>元素并不会执行其中的脚本(因为<script>是无作用域的元素,不可显示,跟注释一样).所以想插入<script>,我们需要在前面添加一个"有作用域的元素",可以是一个文本节点,也可以是一个没有结束标签的元素如<input>:
div.innerHTML = "_<script defer>alert('hi');</script>";
div.innerHTML = "<div>&nbsp;</div><script defer>alert('hi');</script>";
div.innerHTML = "<input type=\"hidden\"><script defer>alert('hi');</script>";
第一行代码插入一个文本节点,但是为了界面的显示,我们需要移除这个节点.第二行代码类似,我们也需要移除<div>节点;最后一行代码由于隐藏的<input>不影响页面布局,所以通常情况是首选.
我们也可以直观的通过innerHTML插入<style>元素:
div.innerHTML = "<style type=\"text/css\">body{background-color: red;}</style>";
不支持innerHTML的元素有:<col>,<colgroup>,<frameset>,<head>,<html>,<style>,<table>,<tbody>,<thead>,<tfoot>和<tr>.
2. outerHTML属性
在读模式下,outerHTML返回调用它的元素及所有子节点的HTML标签.在写模式下,outerHTML会根据指定的HTML字符串创建新的DOM子树,然后用这个DOM子树完全替换调用元素.
<body>
    <div id="content">
        <p>This is <strong>paragraph</strong> wit a list following it.</p>
        <p>this is a test.</p>
        <ul>
            <li>Item 1</li>
            <li>Item 2</li>
            <li>Item 3</li>
        </ul>
    </div>
<script type="text/javascript">
var div = document.getElementById("content");

//读模式下显示HTML
var outerHtml = div.outerHTML;
print(outerHtml);

//写模式下更改HTML的内容---这里会替换所有的<p>标签
div.outerHTML = "<p>This is a paragraph.</p>";
</script>
</body>
浏览器显示如下:


3. insertAdjacentHTML()方法
insertAdjacentHTML()方法接收两个参数:插入位置和要插入的HTNML文本.第一个参数必须是下列值之一:
beforebegin:在当前元素之前插入一个紧邻的同辈元素.
afterbegin:在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素.
beforeend:在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素.
afterend:在当前元素之后插入一个紧邻的同辈元素.
<body>
    <div id="content">
        <p>This is <strong>paragraph</strong> wit a list following it.</p>
        <p>this is a test.</p>
        <ul>
            <li>Item 1</li>
            <li>Item 2</li>
            <li>Item 3</li>
        </ul>
    </div>
<script type="text/javascript">
var div = document.getElementById("content");

div.insertAdjacentHTML("beforebegin", "<p>beforebegin paragraph</p>");
div.insertAdjacentHTML("afterend", "<p>afterend paragraph</p>");
div.insertAdjacentHTML("afterbegin", "<p>afterbegin paragraph</p>");
div.insertAdjacentHTML("beforeend", "<p>beforeend paragraph</p>");
</script>
</body>
浏览器显示如下:

一、节点
1.节点层次
(1)节点是浏览器中的基础类型,所有DOM对象都是特殊的节点,继承自node,可以使用节点自带的方法。
(2)可以通过somenode.childNodes[0];somenode.childNodes.item(0);somenode.firstChild;somenode.lastChild迭代当前节点的子节点。
(3)可以通过somenode.parentNode获取当前节点的父节点。
(4)可以通过somenode.appendChild(anothernode);somenode.insertBefore(anothernode,somenode.firstChild);somenode.replaceChild(another,somenode.firstChild)添加和替换子节点。
(5)可以通过somenode.removeChild(somenode.firstChild)删除节点。
2.document类型
(1)document是一个特殊的node,是window的一个属性,可以在全局直接访问。
(2)可以通过document.documentElement;document.childNodes[0];document.firstChild获取html元素的引用,第一种效率最高。
(3)可以通过document.body获取body元素引用,这个最常用。
(4)可以通过document.title获取和设置页面的标题,这个设置不影响<title>标签。
(5)可以通过document.domain设置当前页面所在的域。当页面中存在多个frame/iframe,并且这些框架中的页面在不同域时,通过js是无法直接完成跨域页面通信的。如果把每个页面的document.domain设置成相同的值,这些页面就能相互访问对方包含的javascript对象了。
(6)可以通过document.getElementById;documment.getElementsByTagName;document.getElementsByName获取到html元素的引用。非常常用。
(7)可以通过document.anchors;document.applets;document.forms;document.images;document.links等特殊集合直接访问html元素。
(8)可以通过document.write;document.writeln动态写入文档流。
3.element类型
(1)直接把element理解为html元素也没有问题。因为element广泛的应用,就是提供了一组操作html标签的API。
(2)可以通过element.arrtName获取或设置html元素的某个属性值。如div.id=1;img.src="1.jpg";table.className="class1"。
(3)可以通过element.getAttribute("attrName");element.setAttribute("attrName",value);element.removeAttribute("attrName")设置、修改或删除html元素的属性。getAttribute返回的是某个属性的值,如果用这个方法去访问style或者onclick之类的属性,得到的都是字符串,而不是对象或函数。
(4)可以通过document.createElement("div"/"<div id='mydiv'>");的形式创建element。
二、DOM操作
1.动态脚本
(1)动态脚本指的是不在head写script标签载入js文件,而是通过创建element并添加的方法把外部js引入。
(2)引入动态脚本的难点在于,怎样确定脚本已经加载完毕可以使用了。我们将在以后的内容详细展开,这里只给出一个简单的例子。
//小实验
var script=document.createElement("script");
script.type="text/javascript";
script.src="demo.js";
document.body.appendChild(script);
2.动态样式
(1)动态脚本是引入js文件,那css文件能动态加载么?答案是肯定的。
(2)样式的载入本来就是异步的,因此动态载入样式有个好处就是不用太关心啥时候完成。
//小实验
var link=document.createElement("link");
link.rel="stylesheet";
link.type="text/css";
link.href="style.css";
document.getElementsByTagName("head")[0].appendChild(link);
三、DOM扩展
1.选择器
  用原生的getElementById和getElementsByTagName选取往往比较麻烦,扩展性也不好。因此有很多js库写了自己的选择器。W3C制定了一个选择器标准,要求所有实现此类功能的js库,都完成一个或使用已经存在的选择器,选择器使用CSS筛选器语法,开发人员都会尽可能提高自己的选择器的性能,从而提高js库的执行效率。目前实现最好的是jQuery的sizzle引擎。
2.HTML5
(1)HTML5定义DOM的同时,为js提出了很多新的API。
(2)document.getElementsByClassName(),根据class内容筛选出html元素;
(3)element.classlist,定义了一套操作class的api,如element.classlist.add/remove/toggle/contains。
(4)document.activeElement,保存当前具有焦点的element。element.hasFocus(),返回当前元素时候含有焦点。
(5)document.readyStated,表示页面是loading还是complete,目前所有浏览器都支持。
(6)document.charset,获取或设置页面渲染的字符集。
(7)自定义数据属性集data-。自定义字符集的好处是不必利用getAttribute去获取某个自定义属性,而是直接通过element.dataset.myAttr操作。当然,这要求html标签中,属性的前缀是data-。
(8)scrollIntoView(),允许控制滚动条滚动,以显示某个元素。element.scrollIntoView()。传入true或NULL,让元素顶部与窗口顶部对齐;传入false,让元素尽可能多的显示在页面中,类似与垂直居中。
四、专业扩展
  浏览器厂商都根据自己的喜好在标准之外添加着一些扩展功能。基本上这些功能是不通用的,但以后说不定会成为标准。比如element.children,是IE为了去除页面空白字符弄出来的,如果没有空白字符,这个和childNodes是完全一样的。还有contains,判断一个节点是不是另一个节点的祖先(注意不止是父亲),if (parentNode.contains(childNode))。另外还有几个控制滚动条的方法,这里不再赘述。
五、DOM2和DOM3
1.以上都是DOM1,而DOM2和DOM3的目的在于扩展DOM API,以满足操作XML的所有需求,同时提供更好的错误处理及特性检测能力。DOM2没有在DOM1基础上引入新类型,只是增加了新方法和新属性;DOM3同样增强了已有类型,但也引入了一些新类型。
2.js修改样式style的功能是DOM2才加入的。同时DOM2又增加了操作styleSheet的API。
3.DOM2级定义了createRange()方法,定义一个选中的范围。

,常用Node类型:Node.ELEMENT_NODE(1)

         Node.ATTRIBUTE_NODE(2)

         Node.TEXT_NODE(3)

         Node.DOCUMENT_NODE(9)

  对于元素节点,nodeName中保存的始终都是元素的标签名,而nodeValue的值始终是null

2.节点关系,如下图:



  hasChildNodes()这个方法在节点包含一个或多个子节点的情况下返回true;ownerDocument属性指向整个文档的文档节点

3,操作节点

  appendChild()方法用于向childNodes列表的末尾添加一个节点,并返回新增的节点;如果新增的节点已经是文档的一部分,那结果就是将该节点从原来的位置转移到新位置。

  insertBefore()方法接受两个参数:要插入的节点和作为参考的节点;被插入的节点会变成参照节点的前一个同胞节点(previousSibling),同时被方法返回。

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

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

  注:replaceChild()和removeChild()方法一样,被移除的节点仍然为文档所有,只不过在文档中已经没有了自己的位置

  前面四个方法必需先取得父节点(使用parentNode属性)

4,其它方法

  cloneNode()方法用于创建调用这个方法的节点的一个完全相同的副本,该方法接受一个布尔值参数;true为深复制,也就是复制节点及其整个子节点树,false只复制该节点。

  normalize()方法用来处理文本节点,文本节点不包含文本或者连接出现两个文本节点的情况。

5.Document类型

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

  文档的子节点:

  document.documentElement,document.childNode[0],document.firstChild都指向<html>元素

  document.body指向<body>元素,document.title可以取得<title>元素中的文本

  document.URL取得的是地址栏中显示的URL,domain属性中只包含页面的域名,documnet.referrer取得来源页面的URL,三个属性中只有domain可以设置。

  查找元素:

  documnet.getElementById(),接受一个ID参数,如果不存在返回null;如果页面中多个元素ID相同只返回第一次出现的元素;

  document.getElementsByTagName(),接受一个标签名的参数,返回的是包含零个或多个元素的NodeList,在HTML中返回一个HTMLCollection对象;与NodeList相似,可以使用方括号语法或item()方法来访问HTMLCollection对象中的项,该对象还有一个nameItem()方法可以通过元素的name特性取得集合中的项。

  document.getElementsByName()方法,只有HTMLDocument类型才有这个方法,用法顾名思义,而返回的也是一个HTMLCollection对象。

  特殊集合:

  document.anchors:包含文档中所有带有name特性的<a>元素;

  document.forms:包含文档中所有的<form>元素;

  document.images:包含文档中所有的<img>元素;

  document.links:包含文档中所有带href特性的<a>元素。

  文档写入:

  这个能力体现在四个方法:write(),writeln(),open(),close();

  write(),writeln()可以用来动态地包含外部资源,如下列:

  document.write("<script type=\"text/javascript\" src=\"file.js\">"+"</scr"+"ipt>" );

6,Element类型

  取得属性:

  操作特性的DOM方法主要有三个:getAttribute(),setAttribute(),removeAttribute()

  有两类特殊的特性需要注意:第一类是style,在通过getAttribute()访问时,返回的是包含的CSS文本,而通过属性来访问它则返回一个对象;第二类是onclick这样的时间处理程序,当通过getAttribute()访问会返回响应的代码字符串,而通过onclick属性访问时会返回一个javascript函数。

  attributes属性:

  Element类型是使用attributes属性的唯一一个DOM节点类型。attributes属性中包含一个NamedNodeMap,元素的每一个特性都由一个attr节点表示,每个节点都保存在NamedNodeMap对象中。NamedNodeMap拥有一下方法:

  getNamedItem(name):返回nodeName属性等于name的节点;

  removeNamedItem(name):从列表中已出nodeName属性等于name的节点;

  setNamedItem(node):向列表中添加节点,以节点的nodeName属性为索引;

  item(pos):返回位于数字pos位置处的节点。

  attributes属性中包含一系列节点,每个节点的nodeName就是特性的名称,而节点的nodeValue就是特性的值。每个特性节点都有一个名为specified的属性,这个属性的值如果为true,则意味这要么是在HTML中指定了相应的特性,要么是同时setAttribute()方法设置了该特性。

  创建元素:

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

7,Text类型

  文本节点由Text类型表示,包含的是可以照字面解析的纯文本内容。纯文本中可以包含转义后的HTML字符,但不能包含HTML代码。可以通过nodeValue和data属性访问Text节点中包含的文本。

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

  appendData(text):

  deleteData(offset,count):

  insertData(offset,text):

  replaceData(offset,count,text):

  splitText(offset):从offset指定的位置将当前文本节点分成两个文本节点

  substringData(offset,count):

  除了这些方法外,文本节点还有一个length属性,保存着节点中字符的数目。

  创建文本节点:documnet.cteateTextNode(),该方法接受一个参数——要插入节点中的文本。




DOM是针对XML和HTML文档的一个API:即规定了实现文本节点操控的属性、方法,具体实现由各自浏览器实现。
1. 节点层次
1) 文档节点:document,每个文档的根节点。
2) 文档元素:即<html>元素,文档最外层元素,文档节点第一个子节点。
3) Node类型:
①Node是DOM中各种节点类型的基类型,共享相同的基本属性和方法。
□ 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);
每种节点的nodeType属性返回上述类型之一,为一常量。
通过节点nodeType属性与数字值比较,可得节点类型。
②nodeName和nodeVlue属性。
③每个节点的子节点信息保存在childNodes属性中,childNodes属性中保存一个NodeList对象。
□ NodeList对象,类数组对象,有length属性,但非Array的实例。
□ 访问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;
}
④parentName属性:指向文档树中父节点。
⑤previousSibling属性和nextSibling属性:前一个/下一个同胞节点。
⑥firstChild属性和lastChild属性:前一个/后一个子节点。
⑦hasChildNodes()方法:含子节点返回true,反之返回false。
⑧appendChild()方法:向childNodes列表末尾添加一个子节点,返回新增节点。
⑨insertBefore()方法:两个参数:要插入的节点和作为参照的节点。返回新增节点。
⑩replaceChild()方法:两个参数:要插入的节点和要替换节点。返回新增节点。
⑾removeChild()方法:移除节点。
⑿cloneNode()方法:接受一个布尔值。true为深复制,复制节点及子节点。false为浅复制,仅复制本身节点。
⒀nomalize()方法:处理文档树中文本节点。
4) Document类型(针对document对象)
①Document类型表示文档,是HTMLDocument类型的一个实例,表示整个HTML页面。document对象是window对象的一个属性,可作全局对象访问。
②documentElement属性;该属性始终指向HTML页面中的<html>元素。
③body属性;直接指向<body>元素。
④doctype属性:访问<!DOCTYPE>,各浏览器支持不一致。用处有限。
⑤title属性:可获得和设置title的文本。
⑥URL属性:地址栏中的URL。
⑦domain属性:页面的域名(可设置,有限制)
⑧referrer属性:保存链接到当前页面的那个页面的URL
⑨getElementById()方法:传入元素的ID,返回元素节点。
⑩getElementsByTagName()方法:传入元素名,返回NodeList。
□ 在HTML中返回一个HTMLCollection对象,与NodeList类似。
□ 访问HTMLCollection对象:方括号语法,item()方法,namedItem()方法,HTMLCollection对象还可通过元素的name特性取得集合中的项。
⑾getElementsByName()方法:返回带有给定name特性的所有元素。
⑿特殊集合,这些集合都是HTMLCollection对象。
□ document.anchors:包含文档中所有带name特性的<a>元素。
□ document.applets:包含文档中所有的<applet>元素。
□ document.forms:包含文档中所有的<form>元素。
□ document.images:包含文档中所有的<img>元素。
□ document.links:包含文档中所有带href属性的<a>元素。
⒀DOM一致性检测:document.implementation属性就为此提供相应信息和功能的对象。
□ 此对象有一个方法:hasFeature():两个参数:要检测的DOM功能的名称及版本号。
□ 功能:Core、XML、HTML、Views、StyleSheets、CSS、CSS2、Events、UIEvents、MouseEvents、MutationEvents、HTMLEvents、Range、Traversal、LS、LS-Async、Validation
⒁将输出流写入网页:write()、writeln()、open()和close()。
5) Element类型
①用于表现XML或HTML元素,提供了对元素标签名、子节点及特性的访问。
②可用nodeName属性或tagName属性访问元素标签名。tagName会在HTML中返回大写标签名,在XML中会原样返回。
(1)HTML元素
■所有HTML元素都由Element类型子类HTMLElement类型表示,其属性如下:
□id:元素在文档中的唯一标识符。
□title:有关元素的附加说明信息,一般通过工具提示条显示出来。
□lang:元素内容的语言代码,很少使用。
□dir:语言的方向,值为“ltr”或“rtl”,很少使用。
□className:与元素的class特性对应,即为元素指定的css类。
上述这些属性都可以用来取得或修改相应的特性值。
(2)取得特性
①getAttribute()方法:可以取得公认特性和自定义特性的值。
□任何元素的所有特性,也可以通过DOM元素本身的属性来访问。alert(div.id);alert(div.align);
□只有公认的(非自定义的)特性才会以属性的形式添加到DOM对象中。
□style特性通过getAttribute()访问得特性值CSS文本。通过属性访问得一个对象。
□onclick特性:getAttribute(),返回JS代码字符串。通过属性访问返回一个函数。
□一般通过属性取得特性,只有在取自定义特性值时,才用getAttribute()。
(3)设置特性
①setAttribute():两个参数,要设置的特性名和值。如果特性已经存在,setAttribute()会以指定的值替换现有的值;如果特性不存在,setAttribute()则创建该属性并设置相应的值。
□此方法既可以操作HTML特性也可以操作自定义特性。
□所有公认特性都是属性,因此直接给属性赋值可以设置特性的值。
□IE6、IE7中,setAttribute()设置class、style,事件处理程序会每没有任何效果。但不建议通过属性设置特性。
②removeAttribute():彻底删除元素的特性(IE6不支持)。
(4)attributes属性
①此属性包含一个NameNodeMap对象(类似NodeList的“动态”集合)。元素的每一个特性有一个Attr节点表示,每个节点保存在NameNodeMap对象中。
□getNameItem(name):返回返回nodeName属性等于name的节点
□removeNameItem(name):从列表中移除nodeName属性等于name的节点。
□setNameItem(node):向列表中添加节点,以节点的nodeName属性为索引。
□item(pos):返回位于数字pos位置的节点。
(5)创建元素
①使用document.createElement()方法可以创建新元素。参数:标签名。
②IE中createElement()可传入完整的元素标签,防止IE7以及IE6问题:
□不能设置动态创建的<iframe>元素的name特性
□不能通过表单的reset()方法重设动态创建的<input>元素。
□动态创建的type特性值为“reset”的<button>元素重设不了表单。
□动态创建的一批name相同的单选按钮彼此毫无关系。
if(client.browser.ie&&client.brower.ie<=7){
var iframe = document.createElement("<iframe name = \"myframe\"></iframe>");
}
(6)元素的子节点
①元素的childNode属性中包含了它的所有子节点:元素、文本节点、注释或处理指令。
□一般浏览器解析childNodes时会把元素节点空间的空白符解析为文本节点,而IE不会。因此遍历执行操作需要检查nodeType属性。
For(var i= 0, len = element.childNode.length; i> len; i++){
If(element.childNodes[i].nodeType == 1){
//执行某些操作
}
}
□元素节点支持getElementByTagName()方法。
6) Text类型
①文本节点由Text类型表示,包含纯文本内容,不含HTML代码。
□不支持(没有)子节点
□nodeValue属性、data属性可访问Text节点中包含的文本。
②操作文本节点
□appendData(text):将text添加到节点的末尾。
□deleteData(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中也保存着同样的值。
○修改文本节点值时字符串经HTML编码,特殊符号转义:
div.firstChild.nodeValue = "Some<strong>other</strong>"; //输出Some<Strong>other</strong>
③创建文本节点
□使用document.createTextNode()创建新文本节点。参数:要插入的文本(自动按HTML或XML格式编码)
④规范化文本节点
□DOM操作中可向同一父元素插入多个文本节点,但会造成混乱。
□通过node类型继承的normalize()方法可合并同一父元素上的所有文本节点。
⑤分割文本节点
□Text类型方法splitText():与node方法normalize()相反传入一个位置参数,从该位置拆分成两个文本节点,返回后面的文本节点。
□分割文本节点是从文本节点中提取数据的一种常用DOM解析技术。
7) Comment类型
□Comment类型与Text类型继承自相同的基类,因此它拥有除splitText()之外所有字符串操作方法。
□可使用document.createComment()创建注释节点。
8) CDATASection类型
□CDATASection类型只针对基于XML的文档表示CDATA区域。
□CDATASection类型继承自Text类型,拥有除splitText()之外所有方法。
□各大浏览器均无法正确解析这种类型。
9) DocumentType类型
□IE不支持
□在DOM1级中DocumentType对象不能动态创建。
□DocumentType对象保存在document.doctype中。
◇name属性:文档类型名称。
◇entities属性:文档类型描述的实体的NamedNodeMap对象。
◇notation属性:文档类型描述的符号的NamedNodeMap对象。
10) DocumentFragment类型
□DOM规定文档片段(document fragment)是一种“轻量级”的文档,可以包含和控制节点,但不会像完整的文档那样占用额外资源。
□文档片段不能添加到文档中,只会添加文档片段作为“仓库”保存的节点。
var fragment = document.createDomFragment();
var ul = document.getElementById("myList");
var li = null;
for(var i= 0; i<3; i++){
li = document.createElement("li");
li.appendChild(document.createTextNode("haha"));
fragment.appendChild(li);
}
ul.appendChild.appendChild(li);
□可以通过appendChild()或insertBefore()将文档片段中内容添加到文档中。
11) Attr类型
□是节点,但特性不被认为是DOM文档树的一部分。很少使用这类节点。
□Attr对象3个属性:
◇name属性:特性名称(如nodeName)
◇value属性:特性的值(如nodeValue)
◇specified属性:布尔值,用以区别特性是在代码中指定的还是默认的。
□不建议直接访问特性节点。建议用getAttribute()
setAttribute()、removeAttribute()方法。










猜你喜欢

转载自zhyp29.iteye.com/blog/2304298