第十章:DOM(节点层次剩余节点类型介绍)

DOM

节点层次

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中,标签名始终都是大写表示。而在XML(有时也包括XHTML)中,标签名则始终会与源代码中的保持一致。所以一般都会先转成同样的格式再去比较:

    ifelement.tagName.toLowerCase() == "div") {
        //code
    }
HTML元素
  • 所有HTML元素都由HTMLElement类型表示,不是直接通过这个类型,也是通过它的子类型来表示。HTMLElement类型直接继承自ELement并添加了一些属性。添加的这些属性分别对应于每个HTML元素中都存在的下列标准特性:
    1. id,元素在文档中的唯一标识符。
    2. title,有关元素的附加说明信息,一般通过工具提示条显示出来。
    3. lang,元素内容的语言代码,一般很少使用。
    4. dir,语言的方向,值为”ltr”(left-to-right)或者”rtl”,一般很少使用。
    5. className,与元素的class特性对应,即为元素指定的CSS类。没有将这个属性命名为class,是因为class是保留字。
<!DOCTYPE html>
<html>
<head>
    <title>HTML Elements Example</title>
</head>
<body>
    <div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr">Some text</div>
    <input type="button" value="Get Values" onclick="getValues()">
    <input type="button" value="Set Values" onclick="setValues()">
    <script type="text/javascript">
        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";        
        }
    </script>
</body>
</html>
  • 并不是对所有属性的修改都会在页面中直观的表现出来。对id和lang的修改对用于而言是不可见的。而title只会在鼠标移动到节点上才会显示。对dir的修改会在属性被重写的那一刻,立即影响页面中文本的左、右对齐方式。修改className,如果新类关联了新的CSS样式,也会马上体现出来。
  • 所有HTML元素都是由HTMLElement或者其更具体的子类来表示的。在书上了263页,有具体的元素对应的类型表。
取得特性
  • 每个元素都有一或多个特性,操作特性的DOM方法有三个,分别是getAttribute()、setAttribute()、removeAttribute()。这三者看看名字就知道怎么用了,下面先讲一下getAttribute()。
  • 传给getAttribute()的特性名必须和实际的特性名相同(不区分大小写)。不存在就返回null。
  • 任何元素的所有特性,也都可以通过DOM元素本身的属性来访问。不过只有公认的(非自定义的)特性才会以属性的形式添加到DOM对象中。
<!DOCTYPE html>
<html>
<head>
    <title>Element Attributes Example 2</title>
</head>
<body>
    <div id="myDiv" my_special_attribute="hello!" align="left">Some text</div>
    <input type="button" value="Get Values" onclick="getValues()">
    <script type="text/javascript">
        var div = null;
        function getValues(){
            if (div == null) {
                div = document.getElementById("myDiv");
            }
            alert(div.id);                     //"myDiv"
            alert(div.my_special_attribute);   //undefined
            alert(div.align);                  //"left"
            //align是div的公认属性,而my_special_attribute不是
        }    
    </script>
</body>
</html>
  • 有两种特殊的特性虽然有对应的属性名,但属性的值与通过getAttribute()返回的值并不相同。一个是style,一个是事件处理程序。style通过getAttribute()只会返回一个字符串,而通过属性名访问则会返回一个对象。事件处理程序的getAttribute()只会返回一个字符串,而通过属性名访问则会返回一个function。
<!DOCTYPE html>
<html>
<head>
    <title>Element Attributes Example 2</title>
</head>
<body>
    <div id="myDiv" onclick="alert('hello');" style="color: #0F0;">Some text</div>
    <input type="button" value="Get Values" onclick="getValues()">
    <script type="text/javascript">
        var div = document.getElementById("myDiv");
        function getValues(){
            alert(div.onclick);//function onclick(event){alert('hello');}
            alert(typeof div.onclick);//function
            alert(div.getAttribute("onclick"));//alert('hello');
            alert(typeof div.getAttribute("onclick"));//string
            alert(div.style);//[object CSSStyleDeclaration]
            alert(typeof div.style);//object
            alert(div.getAttribute("style"));//color: #0F0;
            alert(typeof div.getAttribute("style"));//string
        }
    </script>
</body>
</html>
设置特性
  • 设置元素的特性一般有两种写法,对于公认的(非自定义的)特性,可以直接通过属性名去修改。也可以通过setAttribute()传入两个参数去修改(这种方式设置的特性名会被自动转换成小写形式)。后者可以自定义特性。如果用前者自定义属性,该属性不会自动成为元素的特性。另外通过setAttibuteNode()方法传入一个Attr对象(后面介绍)也可以设置新的特性。
    div.id = "someId";
    div.align = "left";
    div.mycolor = "red";//这种写法不会成为元素的特性。
    alert(div.getAttribute("mycolor"));//null(IE8及低版本会正常显示)
  • 总结一下,但凡是自定义属性或者特性都不会自动设置对方。
  • removeAttribute()就厉害了,不仅会清除特性的值,而且也会从元素中完全删除特性。
attributes属性
  • Element类型是使用attributes属性的唯一一个DOM节点类型。attributes属性中包含一个NamedNodeMap,与NodeList类型,也是一个”动态”集合。元素的每一个特性都由一个Attr节点表示,每个节点都保存在NamedNodeMap对象中。NamedNodeMap对象拥有下列方法。
    1. getNamedItem(name): 返回nodeName属性等于name(不区分大小写)的节点
    2. removeNamedItem(name): 从列表中移除nodeName属性等于name的节点
    3. setNamedItem(node): 向列表中添加节点,以节点的nodeName属性为索引。
    4. item(pos): 位于数字pos位置的节点。
  • attributes属性中包含一系列节点,每个节点的nodeName就是特性的名称,而节点的nodeValue就是特性的值。除了使用getNamedItem(name)、 item(pos)获取特性节点,还可以直接使用方括号语法获取。
  • 由于上面的方法写起来不太方便,所以一般开发就会使用上面介绍的方法,但是要遍历元素节点的特性,就得用到attributes了。
     for (i=0, len=element.attributes.length; i < len; i++){
         attrName = element.attributes[i].nodeName;
         attrValue = element.attributes[i].nodeValue;
         pairs.push(attrName + "=\"" + attrValue + "\"");
     }
  • 不同浏览器返回的特性顺序可能不一致,而IE7及更早的版本会返回HTML元素中所有可能的特性。针对IE7的问题,可以对上面的函数加以改进。每个特性节点都有一个名为specified的属性,这个属性的值如果是true,则意味着要么是在HTML中指定了该特性,要么是通过setAttribute设置了该特性。而未设置过的特性的该值都为false。在其他浏览器中,根本不会生成该特性节点,所以所有存在的特性节点的specified都为true。
     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 + "\"");
         }
     }
创建元素
  • 使用document.createElement()方法可以创建新元素。这个方法只接收一个参数,即要创建的元素的标签名。这个标签名在HTML中不区分大小写,而在XML(包括XHTML)中则是区分大小写的。在使用该方法创新新元素的同时,也为新元素设置了ownDocument属性。
  • 在IE中可以使用另外一种方式使用createElement(),即为这个方法传入完整的元素标签,如下:
    var div = document.createElement("<div id=\"mynewdivid\"></div>");
  • 这种方式的缺陷很多,不推荐使用。
元素的子节点
  • 看下面的代码:
    <ul id="myList">
        <li>item 1</li>
        <li>item 2</li>
        <li>item 3</li>
    </ul>
  • 如果是IE来解析这些代码,那么这个元素会有3个子节点,分别是3个li元素。如果在其他浏览器中,ul元素会有7个元素,另外包含了4个文本节点。所以在用childNodes去遍历所有子节点时,千万不要忘记有这个小小的差别。我们一般用检测子节点的nodeType(为1)来判断是不是我们需要的元素节点。
  • 另外我们还可以用下面的代码获得所有的li元素:
    var ul = document.getElementById("myList");
    var items = ul.getElementsByTagName("li");
    //不过该方法会返回ul元素下所有层次的所有li元素。

Text类型

  • 文本节点由Text类型表示,包含的是可以按照字面解释的纯文本内容。纯文本可以包含转义后的HTML字符,但不能包含HTML代码。Text节点具有以下特征:
    1. nodeType的类型为3
    2. nodeName的值为#text
    3. nodeValue的值为文本内容
    4. parentNode是一个Element
    5. 没有子节点
  • 可以通过nodeValue或data属性访问文本内容,他们包含的值相同。使用下列的方法可以操作节点中的文本。
    1. appendData(text),添加text到末尾
    2. deleteData(offset, count),从offset位置开始删除count个字符
    3. insertData(offset, text),从offset位置插入text
    4. replaceData(offset, count, text),删除加插入
    5. splitText(offset),从offset处将文本节点分成2个文本节点
    6. substringData(offset, count),截取字符串
  • 除了这些方法,还有一个length属性,保存着文本节点中字符的数目。
  • 在修改文本节点时,字符串会经过HTML(XML)编码。大于号等符号会被转义。但是目前比较新的浏览器(例如我的chrome)则会显示原来的内容:
    function changeText(){
        var div = document.getElementById("myDiv");
        div.firstChild.nodeValue = "Some <strong>other</strong> message";
    }
创建文本节点
  • 可以使用document.createTextNode()创建新文本节点,该方法接收一个参数,即要插入的文本节点内容。下面是例子:
    function addNode(){
        var element = document.createElement("div");
        element.className = "message";
        var textNode = document.createTextNode("Hello world!");
        element.appendChild(textNode);
        document.body.appendChild(element);
    }
规范化文本节点
  • 如上所示,可以通过splitText()或者createTextNode(),然后appendChild()方式造成相邻的同胞文本节点。这种行为很容易造成混乱,会分不清哪个文本节点表示哪个字符串。因此就催生了一个Node类型的方法(前面提到过)normalize()。如果文本节点不包含文本,或者接连出现两个文本节点。当在某个节点上调用这个方法时,就会在该节点的后代节点中查找上述两种情况。如果找到了空文本节点,则删除。如果找到接连出现两个文本节点,就合并。且nodeValue的值也会合并。
    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!"
    }

Comment类型

  • 注释在DOM中是通过Comment类型来表示的。Comment节点具有以下特征:
    1. nodeType的值为8
    2. nodeName的值为#comment
    3. nodeValue的值是注释的内容
    4. parentNode可能是Document或Element
    5. 没有子节点
  • Comment类型与Text类型继承自相同的基类,因此他拥有除splitText()之外的所有字符串操作方法。与Text类型相似,也可以通过nodeValue或data属性来取得注释的内容。另外还有createComment()方法创建注释节点,但是由于这种类型鲜有人用,所以这里不再讨论。开发的时候不要忽略注释也是一个节点就可以了。

CDATASection类型

  • 该类型只针对XML文档,表示的是CDATA区域。与Comment类似,CDATASection类型继承自Text类型,因此拥有除splitText()之外的所有字符串操作方法。特征如下:
    1. nodeType的值为4
    2. nodeName的值为#cdata-section
    3. nodeValue的值是CDATA区域中的内容
    4. parentNode可能是Document或Element
    5. 没有子节点
  • CDATA区域只会出现在XML文档中,因此多数浏览器都会把CDATA区域错误的解析为Comment或Element(Chrome中会当成Comment)。
  • 相应的,在XML文档中,可以使用document.createCDataSection()来创建CDATA区域。

DocumentType类型

  • 该类型在Web浏览器中并不常用,仅有Firefox、Safari和Opera支持他(也许目前的最新浏览器也可以使用,因为我的Chrome也可以用)。DocumentType包含着与文档的doctype有关的所有信息,它具有以下特征:

    1. nodeType的值为10
    2. nodeName的值为doctype的名称
    3. nodeValue的值为null
    4. parentNode为Document
    5. 没有子节点
  • 在DOM1级中,DocumentType对象不能动态创建,而只能通过解析文档代码的方式来创建。支持他的浏览器会吧DocumentType对象保存在document.doctype中。DOM1级描述了3个属性:name、entities和notations。其中name表示文档类型的名称。entities 是由文档类型描述的实体的NamedNodeMap对象。notations是由文档类型描述的符号的NamedNodeMap对象。后两个属性一般没有什么用。第一个属性则是用来保存

DocumentFragment类型

  • 该类型只是一个节点”仓库”,在文档中没有对应的标记。DOM规定文档片段是一种轻量级的文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源。特征如下:
    1. nodeType的值为11
    2. nodeName的值为#document-fragment
    3. nodeValue的值为null
    4. parentNode的值为null
    5. 子节点可以是Element、ProcessingInstruction、Comment、Text、CDATASection或EntityReference
  • 可以使用document.createDocumentFragment()来创建文档片段。如果将文档中的节点添加到文档片段中,就会从文档树中移除该节点,也不会从浏览器中再看到该节点。添加到文档片段中的新结点同样也不属于文档树。可以通过appendChild()或insertBefore()将文档片段中内容添加到文档中。在将文档片段作为参数传递给这2个方法时,实际上只会将文档片段的子节点添加到相应位置上(这也说明了该类型为什么没有parentNode!)。
<!DOCTYPE html>
<html>
<head>
    <title>Document Fragment Example</title>
</head>
<body>
    <ul id="myList"></ul>
    <input type="button" value="Add Items" onclick="addItems()">
    <input type="button" value="remove Items" onclick="removeItems()">
    <input type="button" value="restore Items" onclick="restoreItems()">
    <script type="text/javascript">
        var fragment = document.createDocumentFragment();
        var ul = document.getElementById("myList");
        function addItems(){
            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);
            alert("fragment length:" + fragment.childNodes.length);
        }
        function removeItems(){
            var length = ul.childNodes.length;
            for (var i=0; i < length; i++){//注意不能写成i < ul.childNodes.length,因为ul是动态的
                fragment.appendChild(ul.firstChild);
            }
            alert("fragment length:" + fragment.childNodes.length);
        }
        function restoreItems(){
            ul.appendChild(fragment);
            alert("fragment length:" + fragment.childNodes.length);
        }
    </script>
</body>
</html>
  • 通过上面的代码,我们可以将DocumentFragment类型理解成文档的回收站,嘿嘿。

Attr类型

  • 元素的特性在DOM中以Attr类型来表示。在所有浏览器中(包括IE8),都可以访问Attr类型的构造函数和原型。从技术角度讲,特性就是存在于元素的attributes属性中的节点。特性节点具有下列特征:

    1. nodeType的值为11
    2. nodeName的值是特性的名称
    3. nodeValue的值是特性的值
    4. parentNode的值为null(这里我觉得其实可以为Element)
    5. 在HTML中没有子节点,在XML中子节点可以是Text或EntityReference
  • 尽管特性节点也是节点,但却不被认为是DOM文档树的一部分(这也是其parentNode为null的原因)。我们只要使用getAttribute()、setAttribute()、removeAttribute()去操作他们就行了。

  • 前面已经提到过,Attr对象有3个属性,name、value和specified。其中name是特性名称(与nodeName相同),value是特性值(与nodeValue相同),而specified是一个布尔值,用以区别特性是在代码中指定的还是默认的。
  • 使用document.createAttribute()并传入特性的名称可以创建新的特性节点。例如要为元素添加align特性,可以使用下面的代码:
    function assignAttribute(){
        var element = document.getElementById("myDiv");
        var attr = document.createAttribute("align");
        attr.value = "left";
        //使用setAttributeNode()方法添加特性节点
        element.setAttributeNode(attr);
        alert(element.attributes["align"] === element.getAttributeNode("align"));//true
        alert(element.attributes["align"].value);       //"left"
        //使用getAttributeNode()方法获取特性节点
        alert(element.getAttributeNode("align").value); //"left"
        alert(element.getAttribute("align"));           //"left"
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值