Javascript学习8 - 脚本化文档(Document对象)

    每个Web浏览器窗口(或帧)显示一个HTML文档,表示这个窗口的Window对象有一个document属性,它引用了一个Document对象。
    一个文档对象模型或者说DOM就是一个API,它定义了如何访问组成一个文档的对象。W3C定义了一个标准的DOM,使用Document API,可以作用于HTML和XML文档的通用功能,添加特定于HTML的属性和方法。
    Document对象的详细属性可以见:http://www.w3school.com.cn/htmldom/dom_obj_document.asp

    8.1 Document属性
        cookie      : 允许Javascript程序读写HTTP cookie.
        lastModfied : 一个字符串,包含文档修改日期
        location    : 等价于URL,已经废弃。
        referrer    : 文档URL,包含把浏览器带到当前文档的链接。
        title       : 文档标记<title>之间的文本。
        URL         : 一个字符串,声明装载文档的URL。
    8.2 文档对象集合 【遗留DOM】
        anchors[]   : 文档中所有的锚
        applets[]   : 代表文档中的Java applet
        forms[]     : 代表文档中的form元素。
        images[]    : 所有<img>元素的集合
        links[]     : 所有超链接Link对象
        以上这些称之为遗留DOM集合,它们可以脚本化,但是,它们不能改变文档的结构。可以查看并修改链接的目标地址,从表单元素读取和写入值,但是,无法改变文档相互的结构。
    8.3 命名document对象
        一般来说,可以使用基于数字来索引文档对象集合元素,但是,基于位置索引不稳定,小的文档改变顺序可以破坏代码。
        所以,可以为文档元素分配名字,通过名字来引用这些元素。
        例如,以下form元素的访问:
            <form name="f1">....</form>
        可以这样访问:
            document.forms[0]  
        也可以这样:
            document.forms.f1 或者 document.forms["f1"]
       有以下表单
            <form name="shipping">  <input type="text" name="zipcode"> </form>
        可以做以访问:
1document.forms[0].elements[0]
2document.shipping.zipcode
    8.4 Document对象上的事件句柄
        在HTML中,把函数赋予一个事件句柄属性来定义它们,以下的HTML代码加下事件句柄:
            <form name="myform" onsubmit="return validateform();">...</form>
        除了在onsubmit中加入javascript函数外,也可以在JS中直接把函数赋予事件句柄属性
          
1document.myform.onsubmit = validateform;   //注意,不是调用函数,不需要()

    8.5 W3C DOM 节点
        W3C DOM 取代了遗留DOM,强大而标准化,在介绍DOM之前,有一些预备知识:
        ①需要把文档表示为树
            HTML文档在DOM中表示为对象的一棵树,树中有各种各样的节点,节点之上的节点是父节点(parent),直接位于一个节点下层的节点是子节点(children).位于同一层次的节点是兄弟节点(sibling).一个节点的下一个层次节点的集合是那个节点的扣代(descentdant).一个节点的父节点、祖父节点及其它所有位于其它的节点集合是那个节点的祖先(ancestor)
        ②节点Node
            一个节点表示为一个Node接口,Node接口定义了遍历和操作树的属性和方法。
            Node.childNodes 返回节点的孩子集合
            Node.firstChild,lastChild,nextSibling,previousSibling,parentNode 属性提供了遍历节点的树的一种方法
            Node.appendChild(), removeChild(),replaceChild(),insertBefore() 这些方法能够向一个文档树中添加节点或者移动节点。
        ③节点的类型
            每个Node对象都有一个nodeType属性,它指定了节点是什么类型。
            常见节点类型:
            Element             Node.ELEMENT_NODE               1
            Text                Node.TEXT_NODE                  3
            Document            Node.DOCUMENT_NODE              9
            Comment             Node.COMMENT_NODE               8
            DocumentFragment    Node.DOCUMENT_FRAGMENT_NODE     11
            Attr                Node.ATTRIBUTE_NODE             2
           DOM树部的Node是一个Document对象,这个对象的documentElemtn属性引用一个Element对象,它代表了文档的根元素。对于HTML文档,这是<html>标记。
            在一个DOM树中只有一个Document对象,DOM树的大部分节点是表示标记的Element对象和表示文本串的Text对象。
            DOM API的部门类分层图见15-2
        ④属性
            用Element接口的getAttribute()方法、SetAttribute()方法和RemoveAttribute()方法可以获得、增加、删除一个元素的属性(如img的src属性和width属性)

      8.6 DOM HTML API
            HTMLDocument是HTML专有的Document接口的子接子。HTMLElement是HTML专有的Element接口的子接口。另外,DOM为许多HTML元素定义了标记专有的接口,如HTMLBodyElement、HTMLTitleElement、HTMLInputElement...这些标记专有的接口通常定义了HTML标记属性的属性集合。
            ● HTMLDocument接口定义了支持各种文档的属性和方法,包括location、forms[]数组、write()方法
            ● HTMLElement接口定义了id,style,title,lang,dir和className属性。
            ● 其它的专有的HTML..相关接口也定义了专有的属性和方法,如HTMLInputElement定义了focus(),blur()...
            一个访问DOM接口的例子:
           
1var n = document.documentElement;  // This is a Node object.
2var children = n.childNodes;       // This is a NodeList object.
3var head = children.item(0);       // Here is one way to use a NodeList.
4var body = children[1];            // But this way is easier!
            另一个需要了解的是:DOM标准定义了接口,而不是类,所以它没有定义任何构造函数方法。如果想创建一个Text对象,把它插入文档,不能用如下代码:
            var t = new Text("this is a new text node");  // No such constructor
            取而代之的是,DOM在Document接口中定义了大量有用的工厂方法(factory method).因此,要为文档创建一个Text节点,可以使用以下代码:
            var t = document.createTextNode("this is a new text node");

    8.7 遍历文档
        DOM把一个HTML文档表示为Node对象的树,对于任何一个树形结构来说,最常用的事就是遍历树。
        →依次检查树的每个节点。如以下代码所示:
 1function countTags(n) {                         // n is a Node
 2    var numtags = 0;                            // Initialize the tag counter
 3    if (n.nodeType == 1 /*Node.ELEMENT_NODE*/)  // Check if n is an Element
 4         numtags++;                              // Increment the counter if so
 5    var children = n.childNodes;                // Now get all children of n
 6    for(var i=0; i < children.length; i++{    // Loop through the children
 7         numtags += countTags(children[i]);      // Recurse on each one
 8    }

 9    return numtags;                             // Return the total
10}


        除了childNodes属性,Node接口还定义了其它几个有用的属性,包括firstChild,lastChild,nextSibling,previousSibling.
        →获得DOM节点下所有的文本:
 
 1       function getText(n) {
 2            // Repeated string concatenation can be inefficient, so we collect
 3            // the value of all text nodes into an array, and then concatenate
 4            // the elements of that array all at once.
 5            var strings = [];
 6            getStrings(n, strings);
 7            return strings.join("");
 8
 9            // This recursive function finds all text nodes and appends
10            // their text to an array.
11            function getStrings(n, strings) {
12                if (n.nodeType == 3 /* Node.TEXT_NODE */)
13                    strings.push(n.data);
14                else if (n.nodeType == 1 /* Node.ELEMENT_NODE */{
15                    // Note iteration with firstChild/nextSibling
16                    for(var m = n.firstChild; m != null; m = m.nextSibling) {
17                        getStrings(m, strings);
18                    }

19                }

20            }

21        }
    
    8.8 在文档中查找元素
        ● getElementsByTagName()方法
            调用getElementsByTagName(param)方法,返回一个数组,该数组元素是文档中所有param元素。
            例如:
            var tables = document.getElementsByTagName("table");
            alert("This document contains " + tables.length + " tables");  // 文档中定义了多少个Table
            如果把特殊字符"*"传递给getElementsByTagName,它将返回文档中所有元素的列表。

            有时不想操作元素列表,而想操作文档中一个特定元素,如果对文档中结构有充分的了解,仍可以使用getElementsByTagName方法:
            var myParagraph = document.getElementsByTagName("p")[3];
            但这并不是最好的方法。最好的办法是使用getElementsById()方法、
        ● getElementById()方法
            getElementById方法不像getElementsByTagName返回一个数组列表,因为每个id属性值唯一,所以getElementById方法只返回一个元素。
            getElementById是一个很重要的方法,非常常见。
            以下通过getElementById方法获得表格中某个Cell的值。
           
1var tableOfContents = document.getElementById("TOC");
2var rows = tableOfContents.getElementsByTagName("tr");
3var numrows = rows.length;
        ● getElementsByName()方法
            与getElementById方法相似,它查询元素的name属性,而不是id属性。另外,一个文档中的name属性可能不唯一,所以getElementsByName方法返回的是元素的数组,而不是一个元素。
           
1var link = document.getElementsByName("top")[0];
2// Find all <input type="radio" name="shippingMethod"> elements
3var choices = document.getElementsByName("shippingMethod");

    8.9 修改文档内容
        DOM API的真正威力在于用Javascript动态修改文档的特性。
        →对元素的一个列表按字母排序
    
 1<script>
 2function sortkids(e) {
 3     // This is the element whose children we are going to sort
 4     if (typeof e == "string") e = document.getElementById(e);
 5
 6     // Transfer the element (but not text node) children of e to a real array
 7     var kids = [];
 8     for(var x = e.firstChild; x != null; x = x.nextSibling)
 9         if (x.nodeType == 1 /* Node.ELEMENT_NODE */) kids.push(x);
10
11     // Now sort the array based on the text content of each kid.
12     // Assume that each kid has only a single child and it is a Text node
13     kids.sort(function(n, m) // This is the comparator function for sorting
14                   var s = n.firstChild.data; // text of node n
15                   var t = m.firstChild.data; // text of node m
16                   if (s < t) return -1;      // n comes before m
17                   else if (s > t) return 1;  // n comes after m
18                   else return 0;             // n and m are equal
19               }
);
20     for(var i = 0; i < kids.length; i++) e.appendChild(kids[i]);
21}

22</script>
23<ul id="list"> <!-- This is the list we'll sort -->
24<li>one<li>two<li>three<li>four <!-- items are not in alphabetical order -->
25</ul>
26<!-- this is the button that sorts the list -->
27<button onclick="sortkids('list')">Sort list</button>

        →把文档内容转换为大小写
 1function upcase(n) {
 2    if (n.nodeType == 3 /*Node.TEXT_NODE*/{
 3        // If the node is a Text node, change its text to uppercase.
 4        n.data = n.data.toUpperCase();
 5    }

 6    else {
 7        // If the node is not a Text node, loop through its children
 8        // and recursively call this function on each child.
 9        var kids = n.childNodes;
10        for(var i = 0; i < kids.length; i++) upcase(kids[i]);
11    }

12}

13


        →把一个节点的父节点重定为<b>元素
 1<script>
 2function embolden(n) {
 3    if (typeof n == "string") n = document.getElementById(n); // Lookup node
 4    var b = document.createElement("b"); // Create a new <b> element
 5    var parent = n.parentNode;           // Get the parent of the node
 6    parent.replaceChild(b, n);           // Replace the node with the <b> tag
 7    b.appendChild(n);                    // Make the node a child of the <b> element
 8}

 9</script>
10
11<!-- A couple of sample paragraphs -->
12<p id="p1">This <i>is</i> paragraph #1.</p>
13<p id="p2">This <i>is</i> paragraph #2.</p>
14<!-- A button that invokes the embolden() function on the element named p1 -->
15<button onclick="embolden('p1');">Embolden</button>
16
17



    8.10 修改节点属性
        可以调用element.setAttribute()方法来设置一个节点的属性,如:
       
1var headline = document.getElementById("headline");  // Find named element
2headline.setAttribute("align""center");            // Set align='center'
3//或者:headline.align = "center";  // Set alignment attribute.

    8.11 Document段
        DocumentFragment是一种特殊类型的节点,它自身不出现在文档中,只作为连续节点集合的临时容器,并允许将这些节点作为一个对象来操作。
        把一个DocumentFragment插入文档时,插入的不是DocumentFragment本身,而是它所持有的子节点。
       
1function reverse(n) {
2     // Create an empty DocumentFragment as a temporary container
3     var f = document.createDocumentFragment();
4     while(n.lastChild) f.appendChild(n.lastChild);
5     // Finally, move the children of f all at once back to n, all at once.
6     n.appendChild(f);
7}

    8.12 给文档添加内容
        Document.createElement()方法和Document.createTextNode()方法创建新的Element节点和Text节点。
        而方法Node.appendChild()、Node.insertBefore()和Node.replaceChild()可以用来将它们添加到一个文档。

    8.13 innerHTML属性
        该属性可以用来获得和设置结点中HTML文本。例如:
       
1var table = document.createElement("table");  // Create the <table> element
2table.border = 1;                             // Set an attribute
3// Add a Name|Type|Value header to the table
4table.innerHTML = "<tr><th>Name</th><th>Type</th><th>Value</th></tr>";
posted @ 2009-10-01 23:38  shipfi  阅读(667)  评论(0编辑  收藏  举报