码迷,mamicode.com
首页 > 其他好文 > 详细

高程 第10章 DOM

时间:2016-01-04 23:57:46      阅读:574      评论:0      收藏:0      [点我收藏+]

标签:


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()会在字符串的末尾添加一个换行符(\n).在页面被加载的过程中,可以使用这两个方法向页面中动态地加入内容.

如果在文档加载结束后再调用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操作。

高程 第10章 DOM

标签:

原文地址:http://www.cnblogs.com/sunshinegirl-7/p/5100588.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!