2008 年 7 月 11 日 更新
虽然很多人都熟知文档对象模型(DOM)是处理 XML的基础,但使用 HTML 的浏览器开始使这个主题发生一些变化。随着更新的浏览器通过客户端脚本(比如 JavaScript)实现 W3C文档对象模型,现在 DOM 又经历了一个轮回。本文将介绍通过 JavaScript 实现 DOM,并描述 Web页面的构建,用户可以向这个页面添加并编辑注释。
注意:本文使用兼容 DOM 的浏览器,比如 Netscape 6.x、Internet Explorer 6 或 Mozilla 1.0。熟悉 Java 技术或其他语言的文档对象模型会有所帮助,但不是必要条件。不过您应该大体熟悉 JavaScript。
为什么使用 DOM 而不使用 DHTML?
在本文中,我从文档对象模型的角度分析 Web页面的结构:检查子节点和父节点,以及向现有文档添加并编辑节点。为了演示这个过程,我将构建一个页面。用户可以在这个页面上任意创建注释并编辑这些注释的内容(这个页面不会很复杂;我将把一些任务留给您,比如保存和移动内容以及重新调整内容的大小等)。既然使用 DHTML技术就可以轻松实现这些操作,为什么还要使用 DOM 呢?
开发 XML 的其中一股推动力是将 HTML 片段化,而 DHTML 顺应了这一潮流。虽然某些方面已经形成标准,但浏览器如何处理不同的方面仍然存在很大的分歧。DOM 是可以在整个领域范围内实现的标准接口集,因此编程人员只需编写一个版本的页面。
另外,Web 页面不断朝 XML 的方向发展。XHTML 1.0 只是由 HTML 4.0.1 改编而来的 XML,并且也越来越多地使用 XML 生成 Web 页面。最终,DOM 将是在这些页面内访问元素和文本的主要技术(也可将它用于 XSLT 样式表)。
基础页面
让我们从基础的页面开始,该页面包含一个工作区域和表单,它显示了已创建注释的数量:
清单 1. 基础页面
<html>
<head>
<title>Getting Sticky</title>
<style type="text/css">
* {font-family: sans-serif}
a {font-size: 6pt}
.editButton {font-size:6pt}
</style>
</head>
<body>
<div id="mainDiv" style="height:95%; width:95%; border:3px solid red;
padding: 10px;">
<h1>Getting Sticky</h1>
<form id="noteForm">
Current number of notes:
<input type="text" name="total" value="0" size="3"/>
<input type="button" value="Add a new note"/>
</form>
</div>
</body>
</html>
|
清单 1 展示了带有几种样式(只是为了使页面好看些)的基础页面。页面的正文包括一个单个的
div
元素,该元素包含一个 heading 元素(h1
)和一个 form
元素。即使是在没有使用 DOM 的浏览器里,也可以在表单内访问信息。
图 1. 基础页面

使用 DHTML
使用 DHTML 可以访问甚至修改表单字段的信息。例如,您可以创建一个脚本将当前表单的值增加 1,然后告诉页面在用户点击按钮时执行这个脚本:
清单 2. 增加当前的数值
<html><head>
<title>Getting Sticky</title>
<style type="text/css">
* {font-family: sans-serif}
a {font-size: 6pt}
.editButton {font-size:6pt}
</style>
<script type="text/javascript">
function incrementCurrent() {
current = parseInt(document.forms["noteForm"].total.value);
document.forms["noteForm"].total.value = current + 1;
}
</script>
</head><body>
<div id="mainDiv" style="height:95%; width:95%; border:3px solid red;
padding: 10px;">
<h1>Getting Sticky</h1>
<form id="noteForm">
Current number of notes:
<input type="text" name="total" value="0" size="3"/>
<input type="button" value="Add a new note"
onclick="incrementCurrent()"/>
</form>
</div>
</body></html>
|
在
清单 2 中,incrementCurrent()
函数接受文档对象,然后将 noteForm
对象从页面内的表单数组中抽出。该函数从
noteForm
对象获得表单字段 total
并检索值,然后在页面内更新这个值。
这种更改是即时的。更改页面、重新加载并反复按按钮,您将发现文本字段每一次都会相应地进行更新。
同样,您也可以使用 DHTML 属性检索 div
元素的文本。由于它有一个 mainDiv
的
id
,因此可以使用 innerHTML
属性,如:
theText = mainDiv.innerHTML;
在这个例子中,使用了两个 DHTML 技术:forms
数组,以及通过基于属性值的名称调用元素(而不是通过元素名或总体结构)。但存在的问题是这种方法不够通用。虽然可以对表单的名称使用一个变量,如果碰到不使用表单的呈现,应该怎么办呢?
DOM 和 JavaScript
如果存在一个定义文档对象模型的原则,它将把信息排列成父-子层次结构。例如,参看以下的 XML:
<parentElement><childElement>My Text Node</childElement></parentElement>
有 3 个节点:root 节点是 parentElement
。它有一个子元素 childElement
。childElement
元素有自己的父元素
parentElement
,作为子元素的文本节点的值是 “My Text Node”。这个文本节点的父元素是 childElement
。共享一个父元素的两个节点称为兄弟(sibling)节点。注意,文本就是它本身的节点。元素实际上并没有值,它们仅有文本子节点。
您应该比较熟悉如何使用 Java 技术或其他语言读取 XML 文档的结构。实施这个操作要用到一个带有定义良好的函数和对象属性的 API。例如,这个文档有一个作为其根元素的
html
元素,该元素有两个子元素 head
和 body
(为简单起见,我删除了正常情况下会出现在这些元素之间的空格;至于如何处理这些空格,不同的浏览器之间还没有达成一致)。要通过 Java 技术访问
body
元素,您可以使用几个不同的表达式,假如您已经命名了 Document
对象 document
。
第一个步骤是获得所有元素的子元素的列表,然后从该列表选择一个特定的条目,就像以下的例子一样:
bodyElement = document.getChildNodes().item(0).getChildNodes().item(1);
在这里,首先获得 html
元素(该元素是文档的第一个子元素),然后获得它的第二个子元素 body
(getChildNodes()
是基于零的)。另一种办法是将
html
元素作为第一个子元素直接访问,然后移动到它的第一个子元素(head
),最后移动到该元素的下一个兄弟元素(第二个子元素
body
):
bodyElement = document.getFirstChild().getFirstChild().getNextSibling();
从这里您可以获得节点的类型:
typeInt = bodyElement.getNodeType()
节点类型以整数返回,并且允许您适当地处理每一个节点;一个元素(类型 1
)有名称没有值,但是一个文本节点(类型 3
)有值没有名称。
了解了这些后,就可以获取元素的名称:
elementName = bodyElement.getNodeName();
或它的文本内容:
elementContent = bodyElement.getFirstChild().getNodeValue();
(记住,元素的文本本身就是一个节点,而该元素则是它的父节点)。
当将这些函数移动到 JavaScript 时,相同的基本 API 已经准备就绪,但处理方式有些不同。例如,可以直接访问属性,而不是通过 get
和
set
方法访问,因此 JavaScript 中的相同语句会表示为:
bodyElement = document.childNodes.item(0).childNodes.item(1);
bodyElement = document.firstChild.firstChild.nextSibling;
您可以从这里获得元素的类型和名称及其内容:
ElementType = bodyElement.nodeType;
elementName = bodyElement.nodeName;
elementContent = bodyElement.firstChild.nodeValue;
但是需要注意,只能更改属性的名称。返回对象的函数保持不变。例如,可以根据 ID 检索某个特定的对象,就像下面的示例一样:
formElement = document.getElementById("noteForm");
这只是基本原理,现在我们看看它的实际运行情况。
添加新的注释
实际节点本身只是一个带有标准文本和链接的框,这个框允许用户稍后再编辑文本,如
图 2 所示。
图 2. 新的节点

这个新节点与下面的 HTML 等效:
清单 3. 目标 HTML
<div id="note1" style="width: 100; height:100; border: 1px solid blue;
background-color: yellow; position: absolute;
top: 150; left: 135">
<a href="javascript:editNote('note1')">edit</a>
<br />
New note
</div>
|
使用标准的 DOM 添加实际元素,如
清单 4 所示:
清单 4. 添加新的注释元素
<html>
<head>
<title>Getting Sticky</title>
<style type="text/css">
* {font-family: sans-serif}
a {font-size: 6pt}
.editButton {font-size:6pt}
</style>
<script type="text/javascript">
...
function getCurrentNumber() {
formElement = document.getElementById("noteForm");
return formElement.childNodes.item(1).value;
}
function makeNewNote(){
mainDivElement = document.getElementById("mainDiv");
newNote = document.createElement("div");
newNote.setAttribute("id", "note"+getCurrentNumber());
mainDivElement.appendChild(newNote);
incrementCurrent();
}
</script>
</head>
<body>
<div id="mainDiv" style="height:85%; width:85%; border:3px solid red;
padding: 10px; z-index: -100" >
<h1>Getting Sticky</h1>
<form id="noteForm">
Current number of notes <input type="text" name="total" value="0"
size="3"/>
<input type="button" value="Add a new note"
onclick="makeNewNote()"/>
</form>
</div>
</body>
</html>
|
在这个示例中,更改了按钮从而执行 makeNewNote()
而不是 incrementCurrent()
,尽管
makeNewNote()
还使用该函数。首先,通过 getElementById()
获得针对主元素
div
的引用,这个元素最终会包含注释。然后可以使用 document
对象创建一个名为 div
的新元素,就像在其他语言中一样。要设置
id
属性,您只需要在新的元素上使用 setAttribute()
方法。
每一个注释都有一个独特的 id
属性,因此您需要知道当前的总和是多少。要获得这个信息,必须从 form 元素本身开始。可以从这里获取子元素列表。第一个(带有一个索引
0
)是文本,第二个是(带有一个索引 1
)是实际的 input
元素。
但 .value
又是什么呢?是不是输入错误?它应该是 nodeValue
,是吗?
实际上不是。记住,元素没有值。乍一看,好像我将 DOM 和 DHTML 属性混在一起,但实际上现在获取的元素不仅是 org.w3c.dom.Element
的实现,还是
org.w3c.dom.html.HTMLInputElement
(它也包含了一个代表表单字段值的值属性)的实现。在这一方面,DOM 模仿了一些(虽然不是全部)通过 DHTML 可以实现的属性。
设置了属性之后,只需要将新的 div
元素附加到 mainDiv
元素,div
元素将出现在这个位置上。或者,如果它有任何显示属性或文本的话,它至少会出现在这个位置上。
要添加样式信息,将需要实际使用 DHTML 样式对象:
清单 5. 添加样式信息
...
function makeNewNote(){
mainDivElement = document.getElementById("mainDiv");
newNote = document.createElement("div");
newNote.setAttribute("id", "note"+getCurrentNumber());
newNote.style.width="100";
newNote.style.height="100";
newNote.style.border="1px solid blue";
newNote.style.backgroundColor="yellow";
newNote.style.position="absolute";
newNote.style.top=(150);
newNote.style.left=(25 + 110*getCurrentNumber());
mainDivElement.appendChild(newNote);
incrementCurrent();
}
...
|
添加的结果是产生一个蓝边的黄色小框,如
图 3 所示。
图 3. 空的框

注意,注释的 left
属性取决于当前注释的数量,它随着每个注释的添加而增长。您可以通过这种方式添加一系列框,如
图 3 所示。
添加内容
添加 div
的内容会呈现一个小问题。我可以使用 innerHTML 属性:
newNote.innerHTML = "<a href=/"javascript:editNote('note"
+getCurrentNumber()+")/">edit</a><br />New note";
|
但我如何直接使用 DOM 方法来实现?首先想到的可能是简单地设置 div
元素的文本子节点的值:
noteText = document.createTextNode(
"<a href=/"javascript:editNote('note"+getCurrentNumber()+")/">"+
"edit</a><br />New note");
newNote.appendChild(noteText);
|
虽然文本真的得到了添加,但结果可能与预期不同,如
图 4 所示。
图 4. 框中的文本

问题是您并没有真的添加文本,而是混合了内容,包括文本和元素。浏览器认为您将这看作是 CDATA(完全按照字面意义得出),并且也没有创建元素。不是简单地在一个块中添加所有的内容,您必须实际添加每个元素:
清单 6. 添加内容
...
function makeNewNote(){
mainDivElement = document.getElementById("mainDiv");
newNote = document.createElement("div");
newNote.setAttribute("id", "note"+getCurrentNumber());
...
editLink = getEditLink("note"+getCurrentNumber());
newNote.appendChild(editLink);
newNote.appendChild(document.createElement("br"));
noteText = document.createTextNode("New Form");
newNote.appendChild(noteText);
mainDivElement.appendChild(newNote);
incrementCurrent();
}
function getEditLink(thisId){
editLink = document.createElement("a");
linkText = document.createTextNode("edit");
editLink.setAttribute("href", "javascript:editNote('"+thisId+"')");
editLink.appendChild(linkText);
return editLink;
}
...
|
首先,您已经创建了一个返回一个对象的新函数 getEditLink
。这个对象是用标准 DOM 方法创建的 a
元素。接下来,添加一个标准的 break 标记
br
,最后添加包含实际节点文本的节点。
结果是得到完成的节点,而元素保持完整并可使用。
更改现有的节点
现在有了内容,但怎样才能更改它呢?因为您单个地添加元素,所以只能编辑代表节点文本的单个文本节点。这可以通过 3 种方式来实现。首先删除有问题的节点,然后添加一个新的节点:
清单 7. 删除节点并添加一个新的节点
...
function editNote(editLink){
theDiv = document.getElementById(editLink);
newText = prompt("What should the note say?");
oldNode = theDiv.firstChild.nextSibling.nextSibling;
theDiv.removeChild(oldNode);
newNode = document.createTextNode(newText);
theDiv.appendChild(newNode);
}
...
|
另一种方法很简单,只需代换现有的节点:
清单 8. 替换一个节点
...
function editNote(editLink){
theDiv = document.getElementById(editLink);
newText = prompt("What should the note say?");
oldNode = theDiv.firstChild.nextSibling.nextSibling;
newNode = document.createTextNode(newText);
theDiv.replaceChild(newNode, oldNode);
}
...
|
在这个示例中,用 newNode
代替了 oldNode
,同时也相应地更改了文档。
最后一个办法是更改现有节点的文本:
清单 9. 更改现有的节点
...
function editNote(editLink){
theDiv = document.getElementById(editLink);
newText = prompt("What should the note say?");
theDiv.firstChild.nextSibling.nextSibling.nodeValue=newText;
}
...
|
因为 editNote
使用相应的 div
的 id
值作为参数,相同的函数可以用于任意节点,如
图 5 所示。
图 5. 最后的页面

结束语
在本文,您已经了解在 Web 页面的 JavaScript 中使用 DOM 的基础知识。您可以在使用 JavaScript 的地方(比如在 XSLT 样式表中)使用这些基本原理。
文档对象模型将 XML 文档内的元素、文本和其他类型的节点呈现为一系列的父子关系。操作这些单独的节点可以影响页面本身。除了 DOM Core方法以外,XHTML 页面也可以公开作为 DOM HTML 模块的一部分的属性和方法,DOM HTML 模块试图整合许多编程人员用了好几年的DHTML 属性。
分享到:
相关推荐
### JavaScript文档对象模型(DOM)详解 #### 一、引言 文档对象模型(Document Object Model,简称DOM),是W3C为了统一不同浏览器环境下的文档处理方式而制定的一套标准。这一标准的诞生,旨在解决早期浏览器混战...
文档对象模型(DOM)是Web开发中的核心技术,它允许开发者通过JavaScript等脚本语言来动态地访问和修改HTML或XML文档的结构、内容和样式。DOM是一个标准的接口,它将文档表示为一棵由节点组成的树,每个节点代表文档...
为了能够操纵浏览器和文档,JavaScript使用分层的父对象和子对象,这就是“文档对象模型”。这些对象的组织类似一个树型结构,并表示一个Web文档的所有内容和组件。 注意:”文档对象模型”不是JavaScript语言的一...
通过阅读《常用手册 DOM文档对象模型》,开发者不仅可以深入理解DOM的基本概念,还能掌握实际操作DOM的技巧,从而提高网页和应用程序的交互性和动态性。此外,对于学习前端开发和Web应用的人员来说,这是一份非常...
XML(eXtensible Markup Language)是一种用于标记...而提供的“八套Xml文档对象模型Dom书籍文档资料”应该包含了深入浅出的DOM理论讲解、实践案例分析以及相关的API使用指南,对于深入学习DOM和XML处理非常有价值。
**DOM文档对象模型** DOM(Document Object Model)是万维网联盟(W3C)制定的一种标准,它提供了一种结构化的表示XML或HTML文档的方法,并允许编程语言与这些文档进行交互。DOM将整个文档视为一个由节点组成的树形...
"DOM文档对象模型中文手册"是学习和查询DOM相关知识的重要资源,提供了关于DOM节点操作、事件处理、选择和遍历元素等方面的详细解释和示例。CodePub.chm格式的文件通常是一个帮助文档,用户可以通过它快速查找DOM...
JavaScript文档对象模型(DOM)是Web开发中一个关键的概念,它允许开发者通过JavaScript代码来操纵HTML或XML文档的结构、内容和样式。DOM定义了一种标准的、平台和语言无关的方式来表示XML或HTML文档,使得我们可以用...
文档对象模型(DOM)是Web开发中的一个关键概念,它为HTML和XML文档提供了一个结构化的表示,并允许程序和脚本动态地访问和更新文档内容、结构和样式。DOM是独立于语言的标准,这意味着任何支持DOM的编程语言都可以...
DOM将网页或XML文档解析成一个结构化的对象树,每个部分都可以通过JavaScript或其他编程语言进行访问和修改,从而实现动态更新和交互。这份"文档对象模型中文手册"是一个宝贵的资源,旨在帮助开发者深入理解和熟练...
文档对象模型(DOM)是Web开发中至关重要的一个部分,它提供了一种标准化的方式来解析、访问和修改HTML或XML文档的结构。DOM将文档视为一棵由节点组成的树,每个节点代表文档的一个部分,如元素、文本、注释等。DOM...
DOM文档对象模型是独立于语言的,这意味着在JavaScript、Python、Java等任何支持DOM的编程语言中,都可以使用相同的方法来处理XML或HTML文档。 DOM的主要概念包括节点、节点类型和DOM树。节点是DOM中最基本的单位,...
VBScript文档对象模型(DOM)是Web开发中的一个重要概念,特别是在使用VBScript进行客户端脚本编程时。DOM是一个标准,允许编程语言与HTML、XML等结构化文档进行交互,为这些文档提供了一种统一的、独立于平台和语言...
DOM(Document Object Model)是HTML和XML文档的标准对象模型,它将文档表示为树形结构,每个元素、属性和文本都转化为对象。JavaScript可以操作这些对象以改变页面内容。 1. DOM元素:每个HTML标签都对应一个DOM...
JavaScript文档对象模型(DOM)是Web开发中一个至关重要的概念,它允许开发者通过编程方式操纵HTML和XML文档的结构、内容和样式。DOM定义了一种标准的、与平台和语言无关的方式来表示和操作XML和HTML文档,使得...
### DOM (文档对象模型)详解 #### 一、DOM 的概念与作用 DOM,全称为 Document Object Model(文档对象模型),是一种被广泛应用于处理 XML 和 HTML 文档的标准接口。它由 W3C(World Wide Web Consortium)制定并...