`

16、DOM&HTML DOM(二)

阅读更多
  • 创建和操作节点

点创建方法

DOM Document(文档)中有一些方法用于创建不同类型的节点,即便在所有的浏览器中的浏览器document对象并不需要全部支持所有的方法。下面的表格列出了包含在DOM Level 1中的方法,并列出不同的浏览器是否支持项。

   

   

IE

MOZ

OP

SAF

createAttribute(name)

用给定名称name创建特性节点

×

×

×

createCDATASection(text)

用包含文本text的文本子节点创建一个CDATA Section

×

createComment(text)

创建包含文本text的注释节点

×

×

×

×

createDocumentFragment()

创建文档碎片节点

×

×

×

×

createElement(tagname)

创建标签名为tagname的元素

×

×

×

×

createEntityReference(name)

创建给定名称的实体引用节点

×

createProcessingInstruction(target,data)

创建包含给定targetdataPI节点

×

createTextNode(text)

创建包含文本text的文本节点

×

×

×

×

最常用到的几个方法是:createDocumentFragment()createElement()createTextNode();其他的一些方法要么就是没什么用(createComment()),要么就是浏览器的支持不够,目前还不太能用。

createElement()、createTextNode()、appendChild()

假设有如下HTML页面:

<html> 
<head> <title>createElement </title> </head> 
<body> <body> 
</html> 

 现在想使用DOM来添加下列代码到上面这个页面中:

<p>Hello World! </p> 

 首先,创建 <p/>元素:

var oP = document.createElement("p"); 

 第二,创建文本节点:

var oText = document.createTextNode('Hello World!'); 

 第三,把文本节点加入到元素中:

oP.appendChild(oText); 

 每种节点类型都有appendChild()方法,它的用途是将给定的节点添加到某个节点的childNodes列表的尾部。
第四,把 <p/>元素添加到body元素中:

document.body.appendChild(oP); 

 注:DOM操作必须在页面完全载入之后才能进行。当页面正在载入时,要向DOM插入相关代码是不可能的,因为在页面完全下载到客户端机器之前,是无法完全构建DOM树的。因为这个原因,必须使用 <body/>元素的onload事件句柄来执行这些代码。

removeChild()、replaceChild()和insertBefore()

删除上面文档中所增加的 <p/>元素

var oP = document.body.getElementsByTagName('p')[0]; 
//document.body.removeChild(oP); 
oP.parentNode.removeChild(oP); 

 替换上面文档中所增加的 <p/>元素,将文本内容替换成小写

var oNewP = document.createElement('p'); 
var oText = document.createTextNode('hello world'); 
oNewP.appendChild(oText); 
var oOldP = document.body.getElementsByTagName('p')[0]; 
oOldP.parentNode.replaceChild(oNewP,oOldP); 

 如果想让新消息出现在旧消息之前,就使用insertBefore()方法。

//...与上面前四行相同 
oOldP.parentNode.insertBefore(oNewP,oOldP); 

createDocumentFragment()

当要向document添加大量数据时,如果逐个添加变动,这个过程有可能会十分缓慢。为解决这个问题,可以创建一个文档碎片,把所有的新节点附加其上,然后把文档碎片的内容一次性添加到document中,这样可以提升性能,只需刷新屏幕一次。假设你想创建十个新段落:

var arrText = ["first", "second", "third", "fourth", "fifth"];
var oFragment = document.createDocumentFragment();
for (var i = 0; i < arrText.length; i++) {
	var oP = document.createElement("p");
	var oText = document.crateTextNode(arrText[i]);
	oP.appendChild(oText);
	oFragment.appendChild(oP);
}
document.body.appendChild(oFragment);
  • HTML元素属性另一访问方式

 大部分情况下,HTML DOM元素中包含的所有特性都是可作为属性:

<img src="mypicture.jpg"border=0" class="xx"/> 

 如果要使用核心的DOM来获取和设置src和border特性,那么要用getAttribute()和setAttribute()方法:

oImg.getAttribute('src');
oImg.setAttribute('border','1'); 

 然而,使用HTML DOM,可以使用同样名称的属性来获取和设置这些值:

oImg.src='mypicture.jpg';
oImg.border = '1'; 

 
但有一个属性class不能直接这样使用,因为class在ECMAScript中是一个保留字,要用className代替访问

var className = oImg.className;
oImg.className = '1'; 

 注:IE在setAttribute()上有个很大的问题:修改时并不会总是正确地反应出来。如果你打算支持IE,最好尽可能使用属性。

  • 使用HTML DOM操作Table

假设想使用DOM来创建如下的HTML表格:

<table border='1' width='100%'>
	<tbody>
		<tr>
			<td>
				cell 1,1
			</td>
			<td>
				cell 2,1
			</td>
		</tr>
	</tbody>
</table>

 
如果想通过核心DOM方法来完成这个任务,你的代码可能会像这样:

//创建表格 
var oTable = document.createElement('table'); 
oTable.setAttribute('border','1'); 
oTable.setAttribute('width','100%'); 

//创建tbody 
var oTBody = document.createElement('tbody'); 
oTable.appendChild(oTBody); 

//创建行 
var oTR = document.createElement('tr'); 
oTBody.appendChild(oTR); 

//创建列 
var oTD1 = document.createElement('td'); 
oTD1.appendChild(document.createTextNode('cell 1,1')); 
oTR.appendChild(oTD1); 
var oTD2 = document.createElement('td'); 
oTD2.appendChild(document.createTextNode('cell 1,2')); 
oTR.appendChild(oTD2); 

//把表格添加到body 
document.body.appendChild(oTable); 

 上面代码十分的冗长而且有些难于理解。为了协助建立表格,HTML DOM给 <table/>、 <tbody/>和 <tr/>等元素添加了一些特性和方法。

<table/>元素添加了以下内容:
caption——指向 <caption/>元素(如果存在);
tBodies—— <tbody/>元素的集合;
tFoot——指向 <tfoot/>元素(如果存在);
tHead——指向 <thead/>元素(如果存在);
rows——表格中所有行的集合;
createTHead()——创建 <thead/>元素并将其放入表格;
createTFoot()——创建 <tfoot/>元素并将其放入表格;
createCaption()——创建 <caption/>元素并将其放入表格;
deleteTHead()——删除 <thead/>元素;
deleteTFoot()——删除 <tfoot/>元素;
deleteCaption()——删除 <caption />元素;
deleteRow(position)——删除指定位置上的行;
insertRow(position)——在rows集合中的指定位置上插入一个新行。

<tbody/>元素添加了以下内容:
rows—— <tbody/>中所有行的集合;
deleteRow(position)——删除指定位置上的行;
insertRow(position)——在rows集合中的指定位置上插入一个新行。

<tr/>元素中添加了以下内容:
cells—— <tr/>元素中所有的单元格的集合; 
deleteCell(position)——删除给定位置上的单元格;
insertCell(position)——在cells集合的给定位置上插入一个新的单元格。

使用HTML DOM重写上面代码:

//...创建表格与tbody与上面代码一样 
//创建行 
oTBody.insertRow(0); 
oTBody.rows[0].insertCell(0); 
oTBody.rows[0].cells[0].appendChild(document.createTextNode('cell 1,1')); 
oTBody.rows[0].insertCell(1); 
oTBody.rows[0].cells[1].appendChild(document.createTextNode('cell 1,2')); 
//把表格添加到body 
document.body.appendChild(oTable);
  • 遍历DOM

到目前为止,我们讨论的功能都仅仅是DOM Level 1的部分(Level 1只是定义DOM简单接口,规划文档的结构,如创建、删除、修改节点,以及对某节点的直接亲属节点简单的导航接口),从现开始介绍一些DOM Level 2 的功能,尤其是和遍历DOM文档相关的DOM Level 2 遍历(traversal)和范围(range)规范中的对象。这些功能只有在Mozilla和Konqueror/Safari中才有。再者,DOM Level 3作为W3C的一个推荐标准被提出。目前为止,还没有哪个浏览器已经完全实现该标准,只有Mozilla已实现了一部分。

NodeIterator

用它可以对DOM树进行深度优先的搜索,如果要查找页面中某个特定类型的信息(或者元素),这是相当有用的。
要创建NodeIterator对象,请使用document对象的createNodeIterator()方法。这个方法接受四个参数:

(1) root——从树中开始搜索的那个节点。
(2) whatToShow——一个数值代码,代表哪些节点需要访问。
(3) filter——NodeFilter对象,用来决定需要忽略哪些节点。
(4) entityReferenceExpansion——布尔值,表示是否需要扩展实体引用。

 
通过应用下列一个或多个常量,whatToShow参数可以决定哪些节点可以访问:
NodeFilter.SHOW_ALL——显示所有的节点类型;
NodeFilter.SHOW_ELEMENT——显示元素节点;
NodeFilter.SHOW_ATTRIBUTE——显示特性节点;
NodeFilter.SHOW_TEXT——显示文本节点;
NodeFilter.SHOW_CDATA_SECTION——显示CData section节点;
NodeFilter.SHOW_ENTITY_REFERENCE——显示实体引用节点;
NodeFilter.SHOW_ENTITY——显示实体节点;
NodeFilter.SHOW_PROCESSING_INSTRUCTION——显示PI节点;
NodeFilter.SHOW_COMMENT——显示注释节点;
NodeFilter.SHOW_DOCUMENT——显示文档节点;
NodeFilter.SHOW_DOCUMENT_TYPE——显示文档类型节点;
NodeFilter.SHOW_DOCUMENT_FRAGMENT——显示文档碎片节点;
NodeFilter.SHOW_NOTATION——显示记号节点。

可以通过使用二进制或操作符来组合多个值:

var iWhatToShow = NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT; 

 createNodeIterator()的filter(过滤器)参数可以指定一个自定义的NodeFilter对象,但是如果不想使用它的话,也可以留空(null)。
要创建最简单的访问所有节点类型的NodeIterator对象,可以使用下面的代码:

var iterator = document.createNodeIterator(document,NodeFilter.SHOW_ALL,null,false); 

 要在搜索过程中前进或者后退,可以使用nextNode()和previousNode()方法:

var node1 = iterator.nextNode(); 
var node2 = iterator.previousNode(); 

 
遍历结构体(注:再强调一次NodeIterator为深度遍历,这就意味着它的子节点及孙节点都会遍历出来):

var oNode = iterator.nextNode();
while (oNode) { 
	//... do something 
	oNode = iterator.nextNode();
}

如果在遍历时不想遍历出某节点,可以自已构建NodeFilter对象。
NodeFilter对象只有一个方法:acceptNode()。如果应该访问给定的节点,那么该方法返回NodeFilter.FILTER_ACCEPT;如果不应该访问给定节点,则返回NodeFilter.FILTER_REJECT。但NodeFilter是一个抽象类,不能直接使用。
现在,只要创建任意一个有acceptNode()方法的对象,就可以将它传给createNodeIterator()方法,现如果要过滤掉 <p/>元素,代码如下所示:

var oFilter = new Object;
oFilter.acceptNode = function (oNode) {
	return (oNode.tagName == "P") ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
};

注:如果个某个元素被过滤掉后,该元素的所有子元素也将会过滤掉。

NodeIterator对象展示了一种有序的自顶向下遍历整个DOM树(或者仅仅其中一部分)的方式。然而可能想遍历到树的特定区域时,再看看某个节点的兄弟节点或者子节点。如果是这种情况,可以使用TreeWalker。

  • TreeWalker

当不想直接翻遍整个DOM树时,TreeWalker十分有用。TreeWalker有点像NodeIterator的大哥:它有NodeIterator所有的功能(nextNode()和previousNode()),并且添加了一些遍历方法,可以由某节点直接导航到其他直接亲属节点
parentNode()——进入当前节点的父节点;
firstChild()——进入当前节点的第一个子节点;
lastChild()——进入当前节点的最后一个节点;
nextSibling()——进入当前节点的下一个兄弟节点;
previousSibling()——进入当前节点的前一个兄弟节点。
要开始使用TreeWalker,其实完全可以像使用NodeIterator那样,只要把createNodeIterator()的调用改为调用createTreeWalker(),这个函数接受同样的参数:

var oFilter = new Object;
oFilter.acceptNode = function (oNode) {
	return (oNode.tagName == "P") ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
};
var iterator = document.createTreeWalker(document, NodeFilter.SHOW_ALL, oFilter, false);

 
如果对将要遍历的DOM树的结构有所了解的话,TreeWalker更加有用;而同时,如果并不知道这个结构的话,使用NodeIterator更加实际有效。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics