操纵 DOM
节点的概念
节点是 DOM
中最基本的对象类型。实际上,您将在本文中看到,基本上 DOM
定义的其他所有对象都是节点对象的扩展。但是在深入分析语义之前,必须了解节点所代表的概念,然后再学习节点的具体属性和方法就非常简单了。
在 DOM
树中,基本上一切都是节点。每个元素在最底层上都是 DOM
树中的节点。每个属性都是节点。每段文本都是节点。甚至注释、特殊字符(如版权符号 ©
)、DOCTYPE
声明(如果 HTML
或者 XHTML
中有的话)全都是节点。因此在讨论这些具体的类型之前必须清楚地把握什么是节点。
节点是……
用最简单的话说,节点就是 DMO
树中的任何事物。之所以用 “
事物”
这个模糊的字眼,是因为只能明确到这个程度。比如 HTML
中的元素(如 img
)和 HTML
中的文本片段(如 “Scroll down for more details”
)没有多少明显的相似之处。但这是因为您考虑的可能是每种类型的功能
,关注的是它们的不同点。
但是如果从另一个角度观察,DOM
树中的每个元素和每段文本都有一个父亲
,这个父节点可能是另一个元素(比如嵌套在 p
元素中的 img
)的孩子,或者 DOM
树中的顶层元素(这是每个文档中都出现一次的特殊情况,即使用 html
元素的地方)。另外,元素和文本都有一个类型
。显然,元素的类型就是元素,文本的类型就是文本。每个节点还有某种定义明确的结构:下面还有节点(如子元素)吗?有兄弟节点
(与元素或文本 “
相邻的”
节点)吗?每个节点属于哪个文档?
显然,大部分内容听起来很抽象。实际上,说一个元素的类型是元素似乎有点冒傻气。但是要真正认识到将节点作为通用对象类型的价值,必须抽象一点来思考。
通用节点类型
DOM
代码中最常用的任务就是在页面的 DOM
树中导航。比方说,可以通过其 “id”
属性定位一个 form
,然后开始处理那个 form
中内嵌的元素和文本。其中可能包含文字说明、输入字段的标签、真正的 input
元素,以及其他 HTML
元素(如 img
)和链接(a
元素)。如果元素和文本是完全不同的类型
,就必须为每种类型编写完全不同的代码。
如果使用一种通用节点类型情况就不同了。这时候只需要从一个节点移动到另一个节点,只有当需要对元素或文本作某种特殊处理时才需要考虑节点的类型
。 如果仅仅在 DOM
树中移动,就可以与其他节点类型一样用同样的操作移动到元素的父节点或者子节点。只有当需要某种节点类型的特殊性质时,如元素的属性,才需要对节点类型作 专门处理。将 DOM
树中的所有对象都看作节点可以简化操作。记住这一点之后,接下来我们将具体看看 DOM
节点构造应该提供什么,首先从属性和方法开始。
<!--[if !vml]-->
<!--[endif]-->
<!--[if !vml]-->
<!--[endif]-->
|
<!--[if !vml]-->
<!--[endif]-->
<!--[if !vml]-->
<!--[endif]-->
|
回页首
|
|
节点的属性
使用 DOM
节点时需要一些属性和方法,因此我们首先来讨论节点的属性和方法。DOM
节点的属性主要有:
- nodeName
报告节点的名称(详见下述)。
- nodeValue
提供节点的 “
值”
(详见后述)。
- parentNode
返回节点的父节点。记住,每个元素、属性和文本都有一个父节点。
- childNodes
是节点的孩子节点列表。对于 HTML
,该列表仅对元素有意义,文本节点和属性节点都没有孩子。
- firstChild
仅仅是 childNodes
列表中第一个节点的快捷方式。
- lastChild
是另一种快捷方式,表示 childNodes
列表中的最后一个节点。
- previousSibling
返回当前节点之前
的节点。换句话说,它返回当前节点的父节点的 childNodes
列表中位于该节点前面的那个节点(如果感到迷惑,重新读前面一句)。
- nextSibling
类似于 previousSibling
属性,返回父节点的 childNodes
列表中的下一个节点。
- attributes
仅用于元素节点,返回元素的属性列表。
其他少数几种属性实际上仅用于更一般的 XML
文档,在处理基于 HTML
的网页时没有多少用处。
不常用的属性
上述大部分属性的意义都很明确,除了 nodeName
和 nodeValue
属性以外。我们不是简单地解释这两个属性,而是提出两个奇怪的问题:文本节点的 nodeName
应该是什么
?类似地,元素的 nodeValue
应该是什么
?
如果这些问题难住了您,那么您就已经了解了这些属性固有的含糊性。nodeName
和 nodeValue
实际上并非适用于所有
节点类型(节点的其他少数几个属性也是如此)。这就说明了一个重要概念:任何这些属性都可能返回空值(有时候在 JavaScript
中称为 “
未定义”
)。比方说,文本节点的 nodeName
属性是空值(或者在一些浏览器中称为 “
未定义”
),因为文本节点没有名称。如您所料,nodeValue
返回节点的文本。
类似地,元素有 nodeName
,即元素名,但元素的 nodeValue
属性值总是空。属性同时具有 nodeName
和 nodeValue
。下一节我还将讨论这些单独的类型,但是因为这些属性是每个节点的一部分,因此在这里有必要提一提。
现在看看 清单 1
,它用到了一些节点属性。
清单 1.
使用 DOM
中的节点属性
// These first two lines get the DOM tree for the current Web page,
//
and then the <html> element for that DOM tree
var myDocument = document;
var htmlElement = myDocument.documentElement;
// What's the name of the <html> element? "html"
alert("The root element of the page is " + htmlElement.nodeName);
// Look for the <head> element
var headElement = htmlElement.getElementsByTagName("head")[0];
if (headElement != null) {
alert("We found the head element, named " + headElement.nodeName);
// Print out the title of the page
var titleElement = headElement.getElementsByTagName("title")[0];
if (titleElement != null) {
// The text will be the first child node of the <title> element
var titleText = titleElement.firstChild;
// We can get the text of the text node with nodeValue
alert("The page title is '" + titleText.nodeValue + "'");
}
// After <head> is <body>
var bodyElement = headElement.nextSibling;
while (bodyElement.nodeName.toLowerCase() != "body") {
bodyElement = bodyElement.nextSibling;
}
// We found the <body> element...
// We'll do more when we know some methods on the nodes.
}
|
<!--[if !vml]-->
<!--[endif]-->
<!--[if !vml]-->
<!--[endif]-->
|
<!--[if !vml]-->
<!--[endif]-->
<!--[if !vml]-->
<!--[endif]-->
|
回页首
|
|
节点方法
接下来看看所有节点都具有的方法(与节点属性一样,我省略了实际上不适用于多数 HTML DOM
操作的少数方法):
- insertBefore(newChild, referenceNode)
将 newChild
节点插入到 referenceNode
之前。记住,应该对 newChild
的目标父节点调用该方法。
- replaceChild(newChild, oldChild)
用 newChild
节点替换 oldChild
节点。
- removeChild(oldChild)
从运行该方法的节点中删除 oldChild
节点。
- appendChild(newChild)
将 newChild
添加到运行该函数的节点之中。newChild
被添加到目标节点孩子列表中的末端
。
- hasChildNodes()
在调用该方法的节点有孩子时则返回 true
,否则返回 false
。
- hasAttributes()
在调用该方法的节点有属性时则返回 true
,否则返回 false
。
注意,大部分情况下所有这些方法处理的都是节点的孩子。这是它们的主要用途。如果仅仅想获取文本节点值或者元素名,则不需要调用这些方法,使用节点属性就可以了。清单 2
在 清单 1
的基础上增加了方法使用。
清单 2.
使用 DOM
中的节点方法
// These first two lines get the DOM tree for the current Web page,
//
and then the <html> element for that DOM tree
var myDocument = document;
var htmlElement = myDocument.documentElement;
// What's the name of the <html> element? "html"
alert("The root element of the page is " + htmlElement.nodeName);
// Look for the <head> element
var headElement = htmlElement.getElementsByTagName("head")[0];
if (headElement != null) {
alert("We found the head element, named " + headElement.nodeName);
// Print out the title of the page
var titleElement = headElement.getElementsByTagName("title")[0];
if (titleElement != null) {
// The text will be the first child node of the <title> element
var titleText = titleElement.firstChild;
// We can get the text of the text node with nodeValue
alert("The page title is '" + titleText.nodeValue + "'");
}
// After <head> is <body>
var bodyElement = headElement.nextSibling;
while (bodyElement.nodeName.toLowerCase() != "body") {
bodyElement = bodyElement.nextSibling;
}
// We found the <body> element...
// Remove all the top-level <img> elements in the body
if (bodyElement.hasChildNodes()) {
for (i=0; i<bodyElement.childNodes.length; i++) {
var currentNode = bodyElement.childNodes[i];
if (currentNode.nodeName.toLowerCase() == "img") {
bodyElement.removeChild(currentNode);
}
}
}
}
|
测试一下!
目前虽然只看到了两个例子,清单 1
和 2
,不过通过这两个例子您应该能够了解使用 DOM
树能够做什么。如果要尝试一下这些代码,只需要将 清单 3
拖入一个 HTML
文件并保存,然后用 Web
浏览器打开。
清单 3.
包含使用 DOM
的 JavaScript
代码的 HTML
文件
<html>
<head>
<title>JavaScript and the DOM</title>
<script language="JavaScript">
function test() {
// These first two lines get the DOM tree for the current Web page,
//
and then the <html> element for that DOM tree
var myDocument = document;
var htmlElement = myDocument.documentElement;
// What's the name of the <html> element? "html"
alert("The root element of the page is " + htmlElement.nodeName);
// Look for the <head> element
var headElement = htmlElement.getElementsByTagName("head")[0];
if (headElement != null) {
alert("We found the head element, named " + headElement.nodeName);
// Print out the title of the page
var titleElement = headElement.getElementsByTagName("title")[0];
if (titleElement != null) {
// The text will be the first child node of the <title> element
var titleText = titleElement.firstChild;
// We can get the text of the text node with nodeValue
alert("The page title is '" + titleText.nodeValue + "'");
}
// After <head> is <body>
var bodyElement = headElement.nextSibling;
while (bodyElement.nodeName.toLowerCase() != "body") {
bodyElement = bodyElement.nextSibling;
}
// We found the <body> element...
// Remove all the top-level <img> elements in the body
if (bodyElement.hasChildNodes()) {
for (i=0; i<bodyElement.childNodes.length; i++) {
var currentNode = bodyElement.childNodes[i];
if (currentNode.nodeName.toLowerCase() == "img") {
bodyElement.removeChild(currentNode);
}
}
}
}
}
</script>
</head>
<body>
<p>JavaScript and DOM are a perfect match.
You can read more in <i>Head Rush Ajax</i>.</p>
<img src="http://www.headfirstlabs.com/Images/hraj_cover-150.jpg" />
<input type="button" value="Test me!" onClick="test();" />
</body>
</html>
|
API
设计问题
再看一看各种节点提供的属性和方法。对于那些熟悉面向对象(OO
)编程的人来说,它们说明了 DOM
的一个重要特点:DOM
并非完全面向对象的 API
。首先,很多情况下要直接使用对象的属性而不是调用节点对象的方法。比方说,没有 getNodeName()
方法,而要直接使用 nodeName
属性。因此节点对象(以及其他 DOM
对象)通过属性而不是函数公开了大量数据。
其次,如果习惯于使用重载对象和面向对象的 API
,特别是 Java
和 C++
这样的语言,就会发现 DOM
中的对象和方法命名有点奇怪。DOM
必须能用于 C
、Java
和 JavaScript
(这只是其中的几种语言),因此 API
设计作了一些折衷。比如,NamedNodeMap
方法有两种不同的形式:
- getNamedItem(String name)
- getNamedItemNS(Node node)
对于 OO
程序员来说这看起来非常奇怪。两个方法目的相同,只不过一个使用 String
参数而另一个使用 Node
参数。多数 OO API
中对这两种版本都会使用相同的方法名。运行代码的虚拟机将根据传递给方法的对象类型决定运行哪个方法。
问题在于 JavaScript
不支持这种称为方法重载
的技术。换句话说,JavaScript
要求每个方法或函数使用不同的名称。因此,如果有了一个名为 getNamedItem()
的接受字符串参数的方法,就不能再有另一个方法或函数也命名为 getNamedItem()
,即使这个方法的参数类型不同(或者完全不同的一组参数)。如果这样做,JavaScript
将报告错误,代码不会按照预期的方式执行。
从根本上说,DOM
有意识地避开了方法重载和其他 OO
编程技术。这是为了保证该 API
能够用于多种语言,包括那些不支持 OO
编程技术的语言。后果不过是要求您多记住一些方法名而已。好处是可以在任何语言中学习 DOM
,比如 Java
,并清楚同样的方法名和编码结构也能用于具有 DOM
实现的其他语言,如 JavaScript
。
让程序员小心谨慎
如果深入研究 API
设计或者仅仅非常关注 API
设计,您可能会问:“
为何节点类型的属性不能适用于所有节点?”
这是一个很好的问题,答案和政治以及决策制定而非技术原因关系更密切。简单地说,答案就是,“
谁知道!但有点令人恼火,不是吗?”
属性 nodeName
意味着允许每种类型的节点都有一个名字,但是很多情况下名字要么未定义,要么是对于程序员没有意义的内部名(比如在 Java
中,很多情况下文本节点的 nodeName
被报告为 “#text”
)。从根本上说,必须假设您得自己来处理错误。直接访问 myNode.nodeName
然后使用该值是危险的,很多情况下这个值为空。因此与通常的编程一样,程序员要谨慎从事。
<!--[if !vml]-->
<!--[endif]-->
<!--[if !vml]-->
<!--[endif]-->
|
<!--[if !vml]-->
|
分享到:
相关推荐
【Ajax第5部分-操纵DOM】是关于使用JavaScript来实时更新Web页面的技术。DOM,即文档对象模型,是Web页面的结构化表示,它将HTML和CSS转化为一系列可操作的对象。DOM树是DOM的一种可视化表示,它包含了页面的所有...
### 掌握Ajax系列之第五部分:操纵DOM详解 #### 使用JavaScript即时更新Web页面 在“掌握Ajax”系列的第五部分中,我们深入探讨了如何使用JavaScript操纵文档对象模型(DOM),以实现实时更新Web页面,而无需进行...
这一期文章将了解如何创建、删除和修改DOM树的各个部分,了解如何实现网页的即时更新。了解如何处理 Web页面的DOM树。比方说,如果向DOM树中增加一个元素,这个元素就会立即出现在用户的Web浏览器中 —— 不需要重新...
本示例展示了如何使用JavaScript操纵DOM来动态生成一个下拉列表框,即`<select>`元素及其内部的`<option>`元素。 首先,我们看到HTML的`<body>`标签有一个`onload`属性,它指定页面加载完成后执行的函数,这里是`...
在Web开发中,操纵DOM元素的属性是一个非常常见的任务,jQuery为此提供了非常方便的接口。本篇文章将详细介绍jQuery中用于操作DOM元素属性的两个非常重要的方法:attr()和removeAttr()。 首先,attr()方法是jQuery...
《使用JavaScript操纵DOM构建太阳系模型》 在Web开发领域,JavaScript是一种不可或缺的语言,它赋予了网页动态交互的能力。本文将深入探讨如何利用JavaScript操纵DOM(文档对象模型)来创建一个交互式的太阳系模型...
JavaScript DOM编程艺术第二版是一本深入探讨JavaScript与DOM(Document Object ...通过阅读这本书,开发者不仅能学会如何利用JavaScript操纵DOM,还能深入了解JavaScript语言本身,从而在Web开发领域取得更大的成就。
document 树结点 parentElement 父元素 parentNode 父结点 childNodes 所有子结点 有s哦 firstChild 第一个子结点 lastChild 最后一个子结点 nextSibling 下一个兄弟结点 previousSibling 上一个兄弟结点
这本书深入浅出地讲解了如何使用JavaScript来操纵DOM,从而实现丰富的用户界面和动态效果。 书中首先介绍了JavaScript的基础知识,包括变量、数据类型、函数等基本概念,为后续DOM操作打下坚实基础。接着,深入探讨...
《JavaScript DOM编程艺术(第2版)》这本书详细介绍了如何使用JavaScript来操纵DOM,实现网页的动态交互效果。通过深入学习本书中的内容,开发者可以更好地理解和掌握JavaScript与DOM的结合方式,提高Web开发的能力...
在这个“Javascript_Dom操作案例”中,我们将深入探讨如何利用JavaScript有效地操纵DOM元素,提升用户体验并实现动态网页功能。 1. **DOM基本概念**: DOM是一种标准,用于表示HTML或XML文档的树形结构。每个节点...
书中将详细介绍DOM的结构、节点操作、事件处理机制,以及如何使用JavaScript操纵DOM以实现丰富的用户界面效果。 本书的"清晰中文版"意味着读者可以更方便地理解和学习,避免了语言障碍,确保了学习过程的顺畅。书中...
使用VueJS进行模拟游戏一个使用vuejs操纵DOM的简单游戏您可以使用“攻击”,“特殊攻击”,“治疗”和“放弃”。 该项目基于Udemy的VueJS课程。
这篇博文(虽然链接无法直接访问)可能详细介绍了如何使用C#控制浏览器并操纵DOM。以下是一些关键知识点: 1. **Web自动化框架**:C#中最常用的Web自动化框架是Selenium WebDriver,它支持多种浏览器,如Chrome、...
### JavaScript DOM编程艺术知识点概述 #### 一、DOM基础概念 **1.1 DOM简介** ...通过学习这些知识点,开发者可以更好地理解和掌握如何使用JavaScript操纵DOM,从而构建出更加动态和响应式的Web应用。
《JavaScript DOM编程艺术(第2版)》是深入学习JavaScript与DOM操作的重要参考资料,它涵盖了JavaScript...通过学习本书,读者将能够熟练地使用JavaScript操纵DOM,构建出交互性更强、用户体验更佳的网页和应用程序。
尽管DOM本身并不依赖于任何特定的编程语言,但在Web开发中最常见的使用方式是通过JavaScript来访问和操纵DOM。JavaScript提供了对DOM的访问接口,使得开发者能够动态地更改网页的内容。 ##### 2.3 如何访问DOM? 在...
这本书全面覆盖了使用JavaScript操纵DOM的各种技术,帮助开发者提升在网页交互和动态效果方面的技能。 首先,书中会介绍JavaScript基础,包括变量、数据类型、控制流语句、函数等核心概念,这是理解和应用DOM编程的...
MochiKit.DOM模块是库的核心部分,它专门设计用于处理XHTML文档,使得在JavaScript中操纵DOM对象变得更加简单和直观。 XML在Ajax应用中扮演着关键角色,因为DOM是XML和HTML文档的主要接口。虽然ECMAScript...