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



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