高程 第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()会在字符串的末尾添加一个换行符(\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操作。
时间: 2024-10-09 20:51:23

高程 第10章 DOM的相关文章

Javascript高级程序设计读书笔记(第10章 DOM)

第10章 DOM 10.1  节点层次 每个节点都有一个nodeType属性,用于表明节点的类型.任何节点类型必是下面中的一个: 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); Nod

第10章 DOM (2 DOM操作技术)

10.2 DOM操作技术 10.2.1 动态脚本 使用<script>元素可以向页面中插入JavaScript 代码,一种方式是通过其src 特性包含外部文件,另一种方式就是用这个元素本身来包含代码.而这一节要讨论的动态脚本,指的是在页面加载时不存在,但将来的某一时刻通过修改DOM 动态添加的脚本.跟操作HTML 元素一样,创建动态脚本也有两种方式:插入外部文件和直接插入JavaScript 代码. 动态加载的外部JavaScript 文件能够立即运行,比如下面的<script>元

第10章DOM笔记

第十章 DOM 一 Node类型 共有12种节点类型,每个节点都有nodeType属性,用于表明节点类型,nodename 表示标签名称 nodeValue始终为null 1.操作节点 a)  appendChild()方法 用于向childNodes的列表最后添加节点,添加后相应的节点都会得到更新.如果出入到appendChild()中的节点已经是文档的一部分了,那结果就是将该节点从原来的位置移到新位子. b) 如果要把节点放到childNodes列表中某个特定的位置,而不是末尾.可以使用in

第10章 DOM (1 节点层次)

DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口).DOM描绘了一个层次化的节点树,允许开发人员添加.移除和修改页面的某一部分. 10.1 节点层次 DOM 可以将任何HTML 或XML 文档描绘成一个由多层节点构成的结构.节点分为几种不同的类型,每种类型分别表示文档中不同的信息及(或)标记.每个节点都拥有各自的特点.数据和方法,另外也与其他节点存在某种关系.节点之间的关系构成了层次,而所有页面标记则表现为一个以特定节点为根节点的树形结构.以下面的HTML 为例:

js高程笔记8-10章

第8章 BOM 1.window对象:既是BOM的核心对象,也是ES的Global对象. 2.如果页面包含框架(frame),每个框架都有自己的window对象,保存在frames集合中. 3.top对象始终指向最外层框架,即浏览器窗口,使用它可以在一个框架中访问另一个框架. parent对象始终指向当前框架的上层框架. self对象始终指向window. 4.window对象关于窗口位置的属性: (1)screenLeft和screenTop(火狐不支持)/screenX和screenY(IE

js高程笔记10-12章

第10章 DOM 1.文档节点是每个文档的根节点.<html>为文档元素,为文档最外层元素.HTML元素——元素节点,特性——特性节点,文档类型——文档类型节点,注释——注释节点 2.Node类型:所有节点类型都继承自Node类型,共享基本的属性和方法. 基本属性:nodeType,nodeName,nodeValue 节点关系:childNodes,parentNode,previousSibling,nextSibling,firstChild,lastChild,hasChildNode

JavaScript高级程序设计(第三版)学习笔记8、9、10章

第8章,BOM BOM的核心对象是window,具有双重角色,既是js访问浏览器的一个接口,又是ECMAScript规定的Global对象.因此,在全局作用域中声明的函数.变量都会变成window对象的属性和方法. 例: var age = 20; function sayAge(){ alert(this.age); } alert(window.age); //20 window.sayAge(); //20 定义全局变量与在window对象上直接定义属性区别:全局变量不能通过delete操

javascript高级程序设计 第十一章--DOM扩展

javascript高级程序设计 第十一章--DOM扩展DOM最主要的扩展就是选择符API.HTML5和Element Traversal Selectors API:定义了两个方法 querySelector() 和 querySelectorAll(),能够基于CSS选择符从DOM中取得元素.querySelector()方法接收一个CSS选择符,返回该模式匹配的第一个元素,querySelectorAll()接收的参数一样,但是返回NodeList实例: matchesSelector()

[摘录]第10章 培养胜过对手的力量

第五部分 谈判高手 优势秘籍力量.控制和影响,是每个人与别人交往时都会追求这些东西.不是吗?在进行谈判时,那些最有影响力火灾是最有力量的一方往往会在谈判时迫使对手做出更多的让步.如果你甘心让对手来操纵或影响你的话,显然你就很可能得不到自己想要的结果.另一方面,如果你直到哪些因素,能影响你的对手,并知道如何使用一些具体的方法来形成这种影响力,你就可以将形势控制在自己手中.权力本身也可以成为一种非常富有建设性的力量,当我们谈论权力时,我并不是指独裁者们用来祸害平民们的那种权力,我所说的权力实际上是一