Scripting Document 筆記(1)

Client-side Javascript的主要目的是腳本化web page內容, 把靜態的HTML轉換成交互式的web應用程序. Scripting Document的主要內容:

  • DOM的基本架構;

  • 怎樣從Document query和select元素(Element);

  • 怎樣遍歷(Traverse)Document, 怎麼查找任何一個document元素的祖先(ancestors),兄弟(siblings),子孫(descendant);

  • 怎樣query和set document元素的屬性;

  • 怎樣query,set和modify document的內容;

  • 怎樣通過creating,inserting和deleting節點(node)來改變document的結構;

  • HTML form怎樣工作;


  1. DOM概要

    DOM是表示和操作HTML和XML的基本API, HTML和XML文檔的嵌套元素用DOM表示成對像樹,HTML文檔(document)包含表示HTML標籤(tag)和元素(element)的節點(node)和表示文本字符串的節點(node), HTML document也包含表示聲明(comments)的節點.

    <html>
      <head>
        <title>Sample Document</title>
      </head>
      <body>
        <h1>An HTML Document</h1>
        <p>This is a <i>simple</i> document.
    </html>

    wKiom1MwOQfgkDJhAADj46DIr4Y092.jpg

從上圖樹的根是Document Node,表示整個文檔; 表示HTML元素的節點是HTML Node; 表示文本的是Text Node, Document, Element和Text是Node的子類.

wKioL1MwPOOCjClkAAE8nCRsmGM691.jpg



從上面的類層次圖,需要注意的是Document和Element,HTMLDocument和HTMLElement之間是有區別的, Document要麼表示HTML文檔, 要麼表示XML文檔, 而Element則表示Document的元素. HTMLDocument和HTMLElement都是Document和Element的子類.

2. 查找Document元素

Client-side Javascript程序從某種程度來說就是操作一個或多個元素, 當程序啓動後,使用全局變量document引用文檔對象. 爲了操作文檔元素, 需要查找要操作的元素, DOM定義如下方法來查找元素:

  • 使用指定的屬性id;

  • 使用指定的屬性name;

  • 使用指定的標籤name;

  • 使用指定的CSS class;

  • 匹配指定的CSS選擇器;

2.1 通過屬性ID查找元素

 任何HTML元素都有一個在整個文檔唯一的id屬性, 因此可以通過使用文檔對象的getElementById()來查找元素. getElementById()方法只能查找一個元素,如果需要查找多個元素,可以使用如下的方法:

function getElements(/*ids...*/) {
    var elements = {};
    for(var i = 0; i < arguments.length; i++) {
        var id = arguments[i];
        var elt = document.getElementById(id);
        if (elt == null)
            throw new Error("No element with id: " + id);
        elements[id] = elt;
    }
    return elements;
}

2.2 通過屬性Name查找元素

 HTML name屬性最初是爲了給form元素設定name, 而且name屬性只有在form數據在提交給server時才被使用, 需要注意的是name屬性值是不唯一的,比如在form中的radio按鈕和checkboxes. 還有name屬性只有在少部分元素上是合法的, 比如form,<iframe>,<img>. 若根據name屬性查找元素, 可以使用文檔對象的getElementsByName()方法, 如:

var radiobuttons = document.getElementsByName("favorite_color");

getElementsByName()通過HTMLDocument類定義,而不是Document類, 所以只能在HTML文檔上使用,不能在XML文檔上使用, 該方法返回一個read-only的元素對象數組.

2.3 通過屬性Type查找元素

通過文檔對象的getElementsByType()方法可以查找指定Type的所有HTML和XML元素, 該方法返回一個read-only的元素對象數組. 如:

var spans = document.getElementsByTagName("span");

getElememtsByTagName()返回的元素順序是元素在文檔中順序, 比如在文檔中查找第一個<p>元素可以用:

var firstpara = document.getElementsByTagName("p")[0];

HTML tag是大小寫不明感的, 當用getElememtsByTagName()時,會忽略大小進行name的比較. 也可以在getElememtsByTagName()中使用通配符*查找所有元素. 除了Document類定義了getElememtsByTagName(), Element類也定義了getElememtsByTagName(),其使用跟Document的一樣,只是getElememtsByTagName()只返回調用它的元素的子孫. 如:

var firstpara = document.getElementsByTagName("p")[0];
var firstParaSpans = firstpara.getElementsByTagName("span");

2.4 通過CSS class查找元素

 HTML的class屬性是以空格分開的一個或多個標識符, 同getElememtsByTagName()一樣,getElementsByClass()可以被HTML document和HTML element調用, 返回匹配的class的read-only的所有子孫. 需注意的是getElementsByClass()方法以空格分隔class標識符, 而不是逗號.如:

var warnings = document.getElementsByClassName("warning");
var log = document.getElementById("log");
var fatal = log.getElementsByClassName("fatal error");

2.5 通過CSS選擇器查找元素

CSS stylesheets使用Selector描述文檔中的元素和元素集.

  • 元素可以通過ID, tag name或者class來描述, 如: #nav, div, .warning

  • 元素可以通過屬性值查找, 如: p[lang="fr"]  *[name="x"]

  • 基本選擇器可以被合併, 如: span.fatal.error  span[lang="fr"].warning

  • 選擇器也可以指定文檔結構, 如: #log span  #log>span  body>h1:first-child

  • 可以合併選擇器來查找多個元素和元素集, 如: div, #log

W3C定義了標準的API querySelectorAll()來查找指定選擇器的元素, 該方法返回元素不像上述查找的元素,是not live的, 也就是返回的Nodelist保存該方法調用時匹配的元素, 當文檔結構發生變化時不會更新. 如果該方法沒有查到匹配的元素, 返回空的Nodelist, 如果發生錯誤, 拋出異常錯誤. 除了querySelectorAll(), document也定義了querySelector(), 使用方法同querySelectorAll(),但該方法只返回第一個匹配的元素, 如果沒有匹配的, 則返回null. 這兩個方法也定義在Element類上, 但只返回調用該方法元素的子孫.

3. 文檔結構和遍歷

3.1 作爲節點樹的文檔

  • parentNode:

    當前節點的父節點,Document節點的父節點是null, 因爲它沒有父節點.

  • childNodes:

    一個read-only的類數組對象.

  • firstChild, lastChild:

    一個節點的第一孩子節點和最後孩子節點, null表示沒有孩子.

  • nextSibling, previousSibling:

    一個節點的下一個和前一個兄弟節點, 兩個節點擁有共同的父節點.

  • nodeType:

    節點的類型, Document節點的值9, Element節點的值是1, 文本節點的值是3, 聲明節點的值是8, Document Faragment是11.

  • nodeValue:

    文本和聲明節點的文本內容.

  • nodeName:

    元素的tag名字,轉換成大寫.

3.2 作爲元素樹的文檔

  1. Element對象的屬性children只返回元素對象.

  2. Text和Comment節點沒有孩子, 這意味着Node.parentNode不會返回Text和Comment節點.

  3. 基於元素的文檔遍歷API是Element屬性, 其等價於Node對象的child和sibling屬性.

  • firstElementChild, lastElementChild

  • nextElementSibling, previousElementSibling

  • clildElementCount

function parent(e, n) {
    if (n === undefined) n = 1;
    while(n-- && e) e = e.parentNode;
    if (!e || e.nodeType !== 1) return null;
    return e;
}
function sibling(e,n) {
    while(e && n !== 0) {
        if (n > 0) {
            if (e.nextElementSibling)
                e = e.nextElementSibling;
            else {
                for(e=e.nextSibling; e && e.nodeType !== 1; e=e.nextSibling)
                /* empty loop */ ;
            }
            n--;
        }
        else {
            if (e.previousElementSibing)
                e = e.previousElementSibling;
            else {
                for(e=e.previousSibling; e&&e.nodeType!==1; e=e.previousSibling)
                /* empty loop */ ;
            }
            n++;
        }
    }
    return e;
}
function child(e, n) {
    if (e.children) {
        if (n < 0) n += e.children.length;
        if (n < 0) return null;
        return e.children[n];
    }
    if (n >= 0) {
        if (e.firstElementChild)
            e = e.firstElementChild;
        else {
            for(e = e.firstChild; e && e.nodeType !== 1; e = e.nextSibling)
            /* empty */;
        }
        return sibling(e, n);
    }
    else {
        if (e.lastElementChild)
            e = e.lastElementChild;
        else {
            for(e = e.lastChild; e && e.nodeType !== 1; e=e.previousSibling)
            /* empty */;
        }
        return sibling(e, n+1);
    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章