JavaScript高级程序设计读书笔记10

第10章 DOM

节点层次

  • DOM可以将任何HTML或XML文档描绘成一个由多层节点构成的结构
  • 文档节点是每个文档的根节点

Node类型

  • DOM1级定义了一个Node接口,所有节点类型都继承自Node类型,因此所有节点类型都共享着相同的基本属性和方法
  • nodeType属性:1 元素节点,2 特性节点,3文档类型节点
  • nodeName属性:指定节点的节点名称
  • nodeValue属性:设置或返回指定节点的节点值
  • previousSilbing属性:返回同一树层级中指定节点的前一个节点
  • nextSibling属性:返回指定节点之后紧跟的节点
  • parentNide属性:指向文档树中的父节点
  • childNodes属性:保存着一个NodeList对象。可以通过方括号来访问NodeList的值,且有length属性,但它并不是Array的实例。
  • arguments对象使用Array.prototype.slice()方法可以将其转换成数组
  • 同样,NodeList也可以转换为数组var arrayOfNodes=Array.prototype.slice.call(someNode.childNodes,0),但此代码在IE8以前的版本无效

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function convertArray(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++){//IE8及以前的版本
    array.push(nodes[i]);
    }
    }
    return array;
    }
  • ownerDocument:指向表示整个文档的文档节点

    操作节点

  • 任何DOM节点都不能同时出现在文档中国的多个位置上,如果调用appendChild()时传入了父节点的一个子节点那么该节点就会成为父节点的最后一个子节点
  • insertBefore():放在某个特定的节点之前
  • replaceChild():替换节点。被替换的节点仍在还在文档中,但它在文档中没有了自己的位置
  • removeChild():移除节点。被移除的节点仍在还在文档中,但它在文档中没有了自己的位置
  • cloneNode(true):深复制,复制节点机器整个子节点数
  • cloneNode(false):浅复制,只复制节点本身
  • normalize():如果找到空文本节点,就删除,找到相邻的文本节点,就合并

    Document类型

  • Document类型可以表示HTML页面或者其他基于XML的文档
  • 最常见的应用是作为HTMLDocument实例的document对象

    文档的子节点

  • documentElement属性:始终指向HTML页面中的元素
  • childNodes:访问文档元素
  • body属性:直接指向元素
  • doctype属性:取得在<!DOCTYPE>中的DocumentType节点
  • 文档类型是只读的,而且只能有一个元素节点

    文档信息

  • document.title:元素的文本,显示在浏览器窗口的标题栏或标签页上
  • document.URL:页面完整的url
  • document.domain:页面的域名
  • document.referrer:链接到当前页面的那个页面的url。在没有来源页面的情况下,可能包含空字符串。
  • 只有domain可以设置,但也并不是任何值。
  • 由于跨域安全限制,来自不同子域的页面无法通过JS通信,而将每个也没按的document.domain设置为相同的值,这些页面就可以互相访问对方包含的JS对象了。
  • 如果域名一开始是松散的,就不能再将其设置为紧绷的。

    查找元素

  • getElementById:严格匹配,包括大小写。只返回文档中第一次出现的元素
  • getElementsByTagName():返回一个NodeList.在HTML文档中,返回一个HTMLCollection对象.
  • HTMLCollection.namedItem():可以通过元素的name特性取得集合中的项,效果和方括号语法相同
  • getElementsByName():最常用的情况是取得单选按钮

    DOM一致性检测

  • document.implementation:检测浏览器实现了DOM的哪些部分
  • hasFeature():DOM1级只为document.implementation规定了一个方法

    文档写入

  • 如果在文档加载结束后再调用document.write(),输出的内容将会重写整个页面。
  • 以下代码页面上只有Tue Jan 23 2018 18:08:35 GMT+0800 (中国标准时间)。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    <p>The time is:</p>
    <script type="text/javascript">
    window.onload=function(){
    document.write("<strong>"+(new Date()).toString()+"</strong>");
    };
    </script>

    </body>
    </html>

Element类型

  • tagName属性:和nodeName一样
  • 在HTML中标签名始终都会以全部大写表示,在XML中标签名会始终与源代码中的保持一致if(element.tagName.toLowerCase()=="div"){}

    HTML元素

  • 所有HTML元素都由HTMLElement类型表示,不是直接通过这个类型,也是通过它的子类型来表示
  • id、title、lang、dir、className

    取得特性

  • getAttribute()
  • 通过属性的值和通过getAttribute都可以得到特性值,但是自定义的特性一定要用getAttribute
  • 注意,className的特殊性<div class="bd"></div> div.className div.getAttribute("class")
  • style和onclick这样的时间处理程序在通过属性的值和通过getAttribute两种方法返回的值不同

    设置特性

  • setAttribute():设置属性,也可以直接给属性赋值来设置
  • removeAttribute():清除特性的值,从元素中完全删除特性

    attributes属性

  • ELement类型是使用attributes属性的唯一一个DOM节点类型。
  • attributes属性中包含一个NamedNodeMap,与NodeList类似。

    创建元素

  • createElement()
  • 在HTML文档椎间盘美好你起个名大小写,在XML(或者XHTML)文档中区分大小写

    元素的子节点

  • 如果需要通过childNodes属性遍历子节点,通常都要先吉安查一个nodeType属性

Text类型

  • 可以通过nodeValue或者data属性访问Text节点包含的文本
  • createTextNode():创建文本节点
  • normalize():如果在包含两个或多个本文节点的父元素上调用该方法,则会将所有文本节点合并成一个节点
  • splitText():按照指定的位置分割nodeValue值

DOM操作技术

动态脚本

  • 在页面加载时不存在,但将来的某一时刻通过修改DOM动态添加的脚本
  • 创建动态脚本有两种方式:插入外部文件和直接插入JS代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    //插入外部文件
    function loadScript(url){
    var script=document.createElement("script");
    script.type="text/javascript";
    script.src=url;
    document.body.appendChild(script);
    }
    loadScript("client.js");
    //直接插入JS代码
    function loadScriptString(code){
    var script=document.createElement("script");
    script.type="text/javascript";
    try{
    script.appendChild(document.createTextNode(code);
    }catch(ex){
    script.text=code; //用于IE,IE将<script>视为一个特殊的元素,不允许DOM访问其子节点
    }
    document.body.appendChild(script);
    }

动态样式

  • 在页面加载完成后添加到页面中的。
  • 加载外部样式文件的过程是异步的,也就是加载样式与执行JS代码的过程没有固定的次序。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    //插入外部文件
    function loadStyles(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);
    }
    loadStyles("styles.css");
    //直接插入JS代码
    function loadStyleString(css){
    var style=document.createElement("style");
    style.type="text/css";
    try{
    style.appendChild(document.createTextNode(css));
    }catch(ex){
    style.styleSheet.cssText=css; //用于IE,IE将<style>视为一个特殊的元素,不允许DOM访问其子节点
    }
    var head=document.getElementsByTagName("head")[0];
    head.appendChild(style);
    }
    loadStyleString("body{background-color:red}");

操作表格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var table=document.createElement("table");
table.border=1;
table.width="100%";
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[0].appendChild(document.createTextNode("cell 2,1"));
//创建第二行
tbody.insertRow(1);
tbody.rows[0].insertCell(0);
tbody.rows[0].cells[0].appendChild(document.createTextNode("cell 1,2"));
tbody.rows[0].insertCell(1);
tbody.rows[0].cells[0].appendChild(document.createTextNode("cell 2,2"));

使用NodeList

  • NodeList、NamedNodeMap、HTMLCollection这三个集合是动态的,每当文档结构发生变化时,它们都会得到更新。
  • 因此,它们始终都会保存着最新、最准确地信息。
  • 从本质上说。所有NodeList对象都是在访问DOM文档时实时运行的查询。
  • 浏览器不会将创建的所有集合都保存在一个列表中,而是在下一次访问集合时再更新集合。

    1
    2
    3
    4
    5
    6
    7
    8
    var divs=document.getElementsByTagName("div"),
    i,
    len,
    div;
    for(i=0,len=divs.length;i<len;i++){
    div=document.createElement("div");
    document.body.appendChild(div);
    }
  • length属性初始化len变量,然后将迭代器与该变量进行比较,避免直接比较造成的无限循环问题。