• 高程 第10章 DOM



    DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口).

    DOM描绘了一个层次化的节点树,允许添加,移除和修改页面的某一部分.

    注意:IE中的所有DOM对象都是以COM对象的形式实现的.这意味着DOM对象与原生JavaScript对象的行为或活动特点并不一致.


    10.1 节点层次

    DOM描绘出的由多层节点构成的结构,每个节点都拥有各自的特点,数据和方法,也与其他节点存在某种关系,这种关系构成了层次,所有页面标记则表现为一个以特定节点为根节点的树形结构.

    文档节点是每个文档的根节点,文档节点子节点,称为文档元素,它是文档的最外层元素,文档中其他所有元素都包含在文档元素中.每个文档只能有一个文档元素.

    在HTML页面中,文档元素始终都是<html>元素.在XML中,没有预定义的元素,因此任何元素都可能成为文档元素.

    每一段标识都可以通过树中一个节点表示:HTML元素--元素节点,特性(attribute)--特性节点,文档类型--文档类型节点,注释--注释节点.


    10.1.1 Node类型

    DOM1级定义了一个Node接口,该接口将由DOOM中的所有节点类型实现.这个Node接口在js中是作为Node类型实现的,除了IE之外,在其他所有浏览器中都可以访问这个类型.JS中所有节点类型都继承自Node类型,因此所有节点类型都共享着相同着基本属性和方法.

    每个节点都有一个nodeType属性,用于表明节点的类型.节点类型由在Node类型中定义的下列12个数值常量来表示,任何节点类型必居其一:

    Node.ELEMENT_NODE(1);

    Node.ATTRIBUTE_NODE(2);

    Node.TEXT_NODE(3);

    Node.CDATA_SECTION_NODE(4);

    Node.ENTITY_REFERENCE_NODE(5);

    Node.ENTITY_NODE(6);

    Node.PROCESSING_INSTRUCTION_NODE(7);

    Node.COMMENT_NODE(8);

    Node.DOCUMENT_NODE(9);

    Node.DOCUMENT_TYPE_NODE(10);

    Node.DOCUMENT_FRAGMENT_NODE(11);

    Node.NOTATION_NODE(12);

    如果我们想知道一个节点是不是元素节点,我们可以通过比较它的nodeType和Node.ELEMENT_NODE是否相等来知道,但这种方法在IE下会报错,因为最好的办法是用节点的nodeType与数字值1来比较,这在所有浏览器下都是支持的.

    对于元素节点,它的nodeName保存的始终是元素的(大写的)标签名,而nodeValue的值始终为null.

    每个节点都有一个childNodes属性,其中保存着一个NodeList对象.NodeList是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点.

    NodeList对象是基于DOM结构动态执行查询的结果,因此DOM结构的变化能够自动反映在NodeList对象中.

    对于类数组对象(例如arguments,NodeList),可以用Array.prototype.slice()方法将其转换为数组.

    //在IE8及之前版本中无效
            var arrayOfNodes=Array.prototype.slice.call(someNode.childNodes,0);

    如果想在所有IE中将NodeList转换为数组,必须手动枚举所有成员.下面代码在所有浏览器中都可以运行:

    function convertToArray(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++){
                        array.push(nodes[i]);
                    }
                }
                return array;
            }

    每个节点都有一个parentNode属性,该属性指向文档树中的父节点.

    包含在childNodes列表中的每个节点都可以通过使用previousSibling和nextSibling来访问同一列表的其他节点.

    childNodes列表中第一个节点的previousSibling为null,列表中最后一个的nextSibling为null.

    父节点的firstChild和lastChild分别指向列表中第一个和最后一个节点.

    hasChildNodes()方法在节点包含一个或多个子节点的情况下返回true.

    所有节点都有的最后一个属性是ownerDocument,该属性指向表示整个文档的文档节点.这种关系表示的是任何节点都属性它所有的文档,任何节点都不能同时存在于两个或更多个文档中.通过这个属性,我们可以不必在节点层次中通过层层回溯到达顶端,而是可以直接访问文档节点.

    appendChild()用于向childNodes列表的末尾添加一个节点.这里添加的节点会直接改变结构.

    任何DOM节点不能同时存在出现在文档中的多个位置上,所以如果调用appendChild()传入一个已经存在的节点,那么这个已经存在的位置就会改变.

    insertBefore(要插入的节点,作为参照的节点):

    把节点放在某个节点之前,如果作为参照的节点为null,则插到最后,此时和appendChild()相同.

    replaceChild(要插入的节点,要替换的节点):

    要替换的节点将由这个方法返回,并从文档树中被移除,插入的节点占据移除的节点位置.

    如果只想移除而非替换节点,可以作用removeChild()方法.它接收一个参数,即要移除的节点.被移除的节点将成为方法的返回值.

    并不是所有类型的节点都有子节点,如果不支持子节点的节点调用了上面方法会导致错误.

    有两个方法是所有类型节点都有的,一个是cloneNode(),一个是normalize().

    cloneNode(布尔值):创建一个完全相同的副本,布尔值为true时深复制,也就是复制节点及其整个子节点树,布尔值为false时浅复制,即只复制节点本身.

    复制后返回的节点副本属于文档所有,但并没有为它指定父节点,算是个没有位置的"孤儿".

    cloneNode()只复制结构,不复制事件.但IE在这里存在一个bug,它会复制事件,所以在复制之前最好先移除事件.

    normalize()唯一的作用就是处理文档树中的文本节点,当某个节点上调用这个方法时,就会在后代节点中查找,如果找到空文本节点,则删除它,如果找到相邻的文本节点,则将它们合并为一个文本节点.


    10.1.2 Document类型

    JavaScript通过Document类型表示文档.在浏览器中,document对象是HTMLDocument(继承自Document类型)的一个实例,表示整个HTML页面.

    document对象是window对象的一个属性,可以将其作为全局对象来访问.

    Document节点具有下列特征:

    nodeType值为9;

    nodeName的值为"#document";

    nodeValue的值为null;

    parentNode的值为null;

    ownerDocument的值为null;

    其子节点可能是一个DocumentType(最多一个),Element(最多一个),ProcessingInstruction或Comment.

    documentElement属性始终指向HTML页面中的<html>元素,childNodes列表可以访问文档元素.

    document对象还有一个body属性,直接指向<body>元素,用document.body来引用<body>.

    所有浏览器都支持document.documentElement和document.body属性.

    可以通过document.doctype来引用<!DOCTYPE>.

    不过浏览器对document.doctype的支持差别很大.

    document对象的title属性,包含着<title>元素的文本--显示在浏览器窗口的标题栏或标签页上.

    通过title属性可以读也可改当前页面的标题,并反映在浏览器的标题栏中.修改title属性的值不会改变<title>元素.

    URL属性中包含页面完整的URL,domain属性只包含页面的域名,referrer属性中则保存着链接到当前页面的那个页面的URL.

    getElementById(),接收一个参数:要取得元素的ID.这里的ID必须与元素的id严格匹配,包括大小写.

    如果页面中多个元素的ID值相同,getElementById()只返回第一次出现的元素.

    getElementByTagName(),接收一个参数:即要取得元素的标签名,而返回的是包含零或多个元素的NodeList.这个方法会返回一个HTMLCollection对象,它是一个"动态"的集合,类数组.

    HTMLCollection对象还有一个方法namedItem(),使用这个方法可以通过元素的name特性取得集合中的项.

    document.getElementsByTagName(“*")取得文档中所有元素.

    getElementsByName(),这个方法会返回带有给定name特性的所有元素.

    document.anchors,包含文档中所有带name特性的<a>元素;

    document.forms,包含文档中所有的<form>元素,与document.getElementsByTagName(“form”)得到的结果相同;

    document.images,包含文档中所有的<img>元素,与document.getElementsByTagName(“img”)得到的结果相同.

    document.links,包含文档中所有带href特性的<a>元素.

    DOM一致性检测:由于DOM分为多个级别,也包含多个部分,因此检测浏览器实现了DOM的哪个部分十分必要,document.implementtation属性就是为此提供相应信息和功能的对象,它规定了一个方法hasFeature(检测的DOM功能的名称,检测DOM功能版本号),如果浏览器支持给定名称和版本的功能,则该方法返回true.

    document对象将输出流写入到网页中的方法:write(),writeln(),open(),close().

    write()和writeln()方法接受一个字符串参数,即要写入到输出流中的文本.

    write()会原样写入,而writeln()会在字符串的末尾添加一个换行符( ).在页面被加载的过程中,可以使用这两个方法向页面中动态地加入内容.

    如果在文档加载结束后再调用document.write(),那么输出的内容将会重写整个页面.


    10.1.3 Element类型

    Element节点特征:

    nodeType值为1;

    nodeName的值为元素的标签名;

    nodeValue的值为null;

    parentNode的值可能为Document或Element;

    其子节点可能是Element,Text,Comment,ProcessingInstruction,CDATASection或EntityReference.

    要访问元素的标签名,可以使用nodeName属性,也可以使用tagName属性;这两个属性会返回相同的值.

    在HTML中,标签名始终都以全部大写表示;而在XML中,标签名则始终与源代码中的保持一致.

    每个元素都有一个或多个特性,这些特性的用途是给出相应元素或其内容的附加信息.操作特性的DOM方法主要有三个,分别是getAttribute(),setAttribute()和removeAttribute().这三个方法可以针对任何特性使用,包括那些以HTMLElement类型属性的形式定义的特性.

    getAttribute()也可访问自定义特性值,特性的名称是不区分大小写的.

    在开发中,经常不使用getAttribute(),而是只使用对象的属性.只有在取得自定义特性值的情况下,才会使用getAttribute()方法.

    setAttribute(要设置的特性名,要设置的特性值):如果特性存在,会替换现有的,如果不存在,会创建并设置.

    因为所有的特性都是属性,所以直接给属性赋值可以设置特性的值.

    removeAttribute(),这个方法用于彻底删除元素的特性.调用这个方法不仅会清除特性的值,而且也会从元素中完全删除特性.这个方法并不常用.

    attributes属性中包含一个NamedNodemap,也是一个"动态"的集合.元素的每一个特性都由一个Attr节点表示,每个节点都保存在NamedNodeMap对象中.

    NamedNodeMap对象拥有下列方法:

    getNamedItem(name):返回nodeName属性等于name的节点;

    removeNamedItem(name):从列表中移除nodeName属性等于name的节点;

    setNamedItem(node):向列表中添加节点,以节点的nodeName属性为索引;

    item(pos):返回位于数字pos位置处的节点.

    针对attributes对象中的特性,不同浏览器返回的顺序是不同的.

    以下代码展示了如何迭代元素的每一个特性,然后将它们构成name=”value” name=”value”这样的字符串格式.

    function outputAttributes(element){
                var pairs=new Array(),
                    attrName,
                    attrValue,
                    i,
                    len;
                for( var 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+""");
                    }
                    
                }
                return pairs.join(" ");
            }

    document.createElement()方法可以创建新元素,不过新元素未被添加到文档树中,想添加到文档树中可以用appendChild(),insertBefore(),replaceChild().


    10.1.4 Text类型

    文本节点由Text类型表示,包含的是可以照字面解释的纯文本内容.纯文本中可以包含转义后的HTML代码,但不能包含HTML代码.

    Text节点有以下特征:

    nodeType值为3;

    nodeName的值为"#text";

    nodeValue的值为节点所包含的文本;

    parentNode是一个Element;

    不支持(没有)子节点.

    可以通过nodeValue属性或data属性访问Text节点中包含的文本,这两个属性中包含的值相同.对nodeValue的修改也会通过data反映出来,反之亦然.

    使用下列方法可以操作节点中的文本.

    appendData(text):将text添加到节点的末尾.

    deleteData(offset,count):从offset指定的位置开始删除count个字符.

    insertData(offset,text):从offset指定的位置插入text.

    replaceData(offset,count,text):用text替换从offset指定的位置开始到offset+count为止处的文本.

    splitText(offset):从offset指定的位置将当前文本节点分成两个文本节点.

    substringData(offset,count):提取从offset指定的位置开始到offset+count为止处的文本.

    如果使用createElement创建元素,而没有添加到文档中,元素是不会显示的,要使用appendChild添加到文档元素中。

    一般情况下,每个元素只有一个文本子节点,不过如果两个文本节点是相邻的同胞节点,两个文本节点创建出来后相继添加到元素里,它们会连接起来,中间不会有空格。

    可以使用normalize()将多个文本子节点合成一个文本子节点,结果节点的nodeValue等于将合并前每个文本节点的nodeValue值拼接起来的值。

    splitText()是和normalize()完全相反的方法,它将一个文本节点分成两个文本节点,括号里传入一个分割位置的值,原来的是到这个分割点的文本,新文本节点是剩下的内容。这个方法返回一个新文本节点,这个节点与原节点的parentNode相同。


    10.1.5 Comment类型

    Comment节点有以下特征:

    nodeType值为8;

    nodeName的值为"#conmment";

    nodeValue的值为注释的内容;

    parentNode可能是Document或Element;

    不支持(没有)子节点。


    10.1.6 CDATASection类型

    CDATASection节点有以下特征:

    nodeType值为4;

    nodeName的值为"#cdata-section";

    nodeValue的值为CDATA中的内容;

    parentNode可能是Document或Element;

    不支持(没有)子节点。


    10.1.7 DocumentType类型

    nodeType值为10;

    nodeName的值为doctype的名称;

    nodeValue的值为null;

    parentNode是Document;

    不支持(没有)子节点。


    10.1.8 DocumentFragment类型

    nodeType值为11;

    nodeName的值为”#document-fragment”;

    nodeValue的值为null;

    parentNode是null;

    子节点可以是Element,ProcessingInstruction,Comment,Text,CDATASection或EntityReference.


    10.1.9 Attr类型

    nodeType值为2;

    nodeName的值为特性的名称;

    nodeValue的值为特性的值;

    parentNode的值为null;

    在HTML中不支持(没有)子节点;

    在XML中子节点可以是Text或EntityReference.


    10.2 DOM操作技术

    10.2.1动态脚本

    在页面加载时不存在,但在将来某个时刻通过修改DOM动态添加的脚本。

    <script type="text/javascript" src="client.js"></script>
    上面语句可以用下面语句来解释:
    var script=document.createElement('script');
    script.type='text/javascript';
    script.src='client.js';
    document.body.appendChild(script);
     
    IE将<script>视为一个特殊的元素,不允许DOM访问其子节点。
    可以写一个函数,先尝试用标准DOM文本节点方法,除了IE会拋出错误外其他浏览器都支持,可以用try-catch语句来捕获IE抛出的错误,然后针对IE的特殊方法来设置样式。
     
    function loadScriptString(code){
    var script=document.createElement('script');
    script.type='text/javascript';
    try{
    script.appendChild(document.createTextNode(code));
    }catch(ex){
    script.text=code;
    }
    document.body.appendChild(script);
    }

    //调用函数
    loadScriptString("function sayHi(){alert('hi');}");
     
    10.2.2 动态样式
    动态样式是指在页面刚加载时不存在的样式,但在页面加载完成后动态添加到页面中的。
    将<link>元素添加到<head>里而不是<body>,才能保证所有浏览器的行为一致。
     
    加载外部样式文本的过程是异步的,也就是加载样式与执行JavaScript代码的过程没有固定的次序。
     
    10.2.3 操作表格
    10.2.4 使用NodeList
    应该尽量减少访问NodeList的次数,因为每次访问NodeList,都会运行一次基于文档的查询。所以,可以考虑将从NodeList中取得的值缓存起来。
    10.3 小结
    DOM是语言中的API,用于访问和操作HTML和XML文档。DOM1级将HTML和XML文档形象地看作一个层次化的节点树,可以使用JavaScript来操作这个节点树,进而改变底层文档的外观和结构。
    DOM由各种节点构成,简要总结如下:
    最基本的节点类型是Node,用于抽象地表示文档中一个独立的部分; 所有其他类型都继承自Node。
    Document类型表示整个文档,是一组分层节点的根节点。在JavaScript中,document对象是Document的一个实例。使用document对象,有很多种方式可以查询和取得节点。
    Element节点表示文档中的所有HTML和XML元素,可以用来操作这些元素的内容和特性。
    DOM操作往往是JavaScript程序中开销最大的部分,而因访问NodeList导致的问题为最多。NodeList对象都是“动态的”,这就意味着每次访问NodeList对象,都会运行一次查询。有鉴于此,最好的办法就是减少DOM操作。
  • 相关阅读:
    2012 Multi-University #8
    2016"百度之星"
    Codeforces Round #352 (Div. 2)
    数位DP CF 55D Beautiful numbers
    数位DP GYM 100827 E Hill Number
    2012 Multi-University #9
    2012 Multi-University #10
    java生成指定范围的随机数
    MySql查询时间段的方法
    eclipse报错GC overhead limit exceed,卡顿
  • 原文地址:https://www.cnblogs.com/sunshinegirl-7/p/5100588.html
Copyright © 2020-2023  润新知