第 28 章 使用DOM元素
现在我们可以把焦点转移到元素对象本身,给予它应有的重视了。
使用元素对象
HTMLElement对象提供了一组属性,你可以用它们来读取和修改被代表元素的数据。下表介绍了这些属性。
元素数据属性
属 性 | 说 明 | 返 回 |
---|---|---|
checked | 获取或设置checked属性是否存在 | 布尔值 |
classList | 获取或设置元素所属的类列表 | DOMTokenList |
className | 获取或设置元素所属的类列表 | 字符串 |
dir | 获取或设置dir属性的值 | 字符串 |
disabled | 获取或设置disabled属性是否存在 | 布尔值 |
hidden | 获取或设置hidden属性是否存在 | 布尔值 |
id | 获取或设置id属性的值 | 字符串 |
lang | 获取或设置lang属性的值 | 字符串 |
spellcheck | 获取或设置spellcheck属性是否存在 | 布尔值 |
tabindex | 获取或设置tabindex属性的值 | 数值 |
tagName | 返回标签名(标识元素类型) | 字符串 |
title | 获取或设置title属性的值 | 字符串 |
代码清单1展示了如何使用表中所列的一些基本属性。
代码清单1 使用基本元素数据属性
<!DOCTYPE HTML>
<html>
<head>
<title>使用基本元素数据属性</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="使用基本元素数据属性"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
p {border: medium double black;}
</style>
</head>
<body>
<p id="HZH_textblock" dir="ltr" lang="en-US">
白色的<span id="HZH_WindMill">风车</span>,安静的转着<br>
真实的感觉,梦境般遥远<br>
甜甜的<span id="HZH_SeaWater">海水</span>,复杂的眼泪<br>
<br>
你的<span id="HZH_World">世界</span>是一座城堡<br>
在大头贴画满心号<br>
</p>
<pre id="HZH_results"></pre>
<script>
var results = document.getElementById("HZH_results");
var elem = document.getElementById("HZH_textblock");
results.innerHTML += "tag: " + elem.tagName + "\n";
results.innerHTML += "id: " + elem.id + "\n";
results.innerHTML += "dir: " + elem.dir + "\n";
results.innerHTML += "lang: " + elem.lang + "\n";
results.innerHTML += "hidden: " + elem.hidden + "\n";
results.innerHTML += "disabled: " + elem.disabled + "\n";
</script>
</body>
</html>
从下面可以看到浏览器为这些属性所提供的结果。
使用类
你可以用两种方式处理某个元素所属的类。第一种方式是使用className属性,它会返回一个类的列表。通过改变这个字符串的值,你就能添加或移除类。你可以在代码清单2里看到用这种方式来读取和修改类。
提示
类的一个常见用途是有针对性地给元素应用样式。
代码清单2 使用className属性
<!DOCTYPE HTML>
<html>
<head>
<title>使用className属性</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="使用className属性"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
p {
border: medium double black;
}
p.newclass {
background-color: grey;
color: white;
}
</style>
</head>
<body>
<p id="HZH_textblock" class="HZH_TimeAndTide">
不知道在那天边可会有尽头<br>
<br>
只知道逝去光阴不会再回头<br>
<br>
每一串泪水伴每一个梦想<br>
<br>
不知不觉全溜走<br>
<br>
不经意在这圈中转到这年头<br>
<br>
只感到在这圈中经过顺逆流<br>
</p>
<button id="HZH_press">黄子涵请你按下</button>
<script>
document.getElementById("HZH_press").onclick = function(e) {
document.getElementById("HZH_textblock").className += " newclass";
};
</script>
</body>
</html>
在这个例子中,点击按钮会触发脚本,然后使一个新的类被附加到元素的类列表上。请注意,我需要给附加到className属性的值添加一个前置空格。这是因为浏览器期望获得由空格间隔的类列表。当我做出这样的修改后,浏览器就会应用那些基于类选择器的样式,这就意味着示例会发生明显的视觉变化,如下面所示。
当你想要快速给某个元素添加类时,className属性是易于使用的,但如果你想要做别的事(比如移除一个类),用它就很困难了。幸好,可以使用classList属性,它返回的是一个DOMTokenList对象。这个对象定义了一些有用的方法和属性来管理类列表,如下表所示。
DOMTokenList的成员
成 员 | 说 明 | 返 回 |
---|---|---|
add(<class> ) |
给元素添加指定的类 | void |
contains(<class> ) |
如果元素属于指定的类就返回true | 布尔值 |
length | 返回元素所属类的数量 | 数值 |
remove(<class >) |
从元素上移除指定的类 | void |
toggle(<class >) |
如果类不存在就添加它,如果存在就移除它 | 布尔值 |
除了这些属性和方法,还可以使用数组风格的表示法,通过索引来获得类。代码清单3展示了如何使用DOMTokenList对象。
代码清单3 使用classList属性
<!DOCTYPE HTML>
<html>
<head>
<title>使用classList属性</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="使用classList属性">
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
p {
border: medium double black;
}
p.HZH_newclass {
background-color: grey;
color: white;
}
</style>
</head>
<body>
<p id="HZH_textblock" class="HZH_DaveWang">
哭泣声绝无意义<br>
它不会扭转分开的心意<br>
梦似是失去收结一首诗<br>
仿佛听别人故事<br>
</p>
<pre id="HZH_results"></pre>
<button id="HZH_toggle">黄子涵请你切换类</button>
<script>
var HZH_results = document.getElementById("HZH_results");
document.getElementById("HZH_toggle").onclick = toggleClass;
listClasses();
function listClasses() {
var HZH_classlist = document.getElementById("HZH_textblock").classList;
HZH_results.innerHTML = "黄子涵提醒你当前类是:"
for (var HZH_i = 0; HZH_i < HZH_classlist.length; HZH_i++) {
HZH_results.innerHTML += HZH_classlist[HZH_i] + " ";
}
}
function toggleClass() {
document.getElementById("HZH_textblock").classList.toggle("HZH_newclass");
listClasses();
}
</script>
</body>
</html>
在这个例子里,listClasses函数使用classList属性来获取和枚举p元素所属的类,并使用数组风格的索引表示法来得到类名。
toggleClass函数会在点击按钮时被调用,它使用toggle方法添加和移除一个名为newclass的类。这个类关联了一个样式,从下面可以看到类的变化所带来的视觉效果。
使用元素属性
HTMLElement对象既有一些属性来对应最重要的HTML全局属性,又支持对单个元素的任意属性进行读取和设置。下表介绍了HTMLElement对象为这个目的所定义的可用方法和属性。
与HTML属性相关的属性和方法
成 员 | 说 明 | 返 回 |
---|---|---|
attributes | 返回应用到元素上的属性 | Attr[] |
dataset | 返回以data-开头的属性 | 字符串数组[<name >] |
getAttribute(<name >) |
返回指定属性的值 | 字符串 |
hasAttribute(<name >) |
如果元素带有指定的属性则返回true | 布尔值 |
removeAttribute(<name >) |
从元素上移除指定属性 | void |
setAttribute(<name > <value >) |
应用一个指定名称和值的属性 | void |
这四种操作属性的方法易于使用,所表现的行为也是可预料的。代码清单4演示了如何使用这些方法。
代码清单4 使用属性方法
<!DOCTYPE HTML>
<html>
<head>
<title>使用属性方法</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="使用属性方法"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
p {border: medium double black;}
</style>
</head>
<body>
<p id="HZH_textblock" class="">
写这高贵情书<br>
用自言自语作我的天书<br>
自己都不爱怎么相爱<br>
怎么可给爱人好处<br>
这千斤重情书在夜阑尽处<br>
</p>
<pre id="HZH_results"></pre>
<script>
var HZH_results = document.getElementById("HZH_results");
var HZH_elem = document.getElementById("HZH_textblock");
HZH_results.innerHTML = "元素是否具有lang属性:" + HZH_elem.hasAttribute("lang") + "\n";
HZH_results.innerHTML += "添加lang属性\n";
HZH_elem.setAttribute("lang", "en-US");
HZH_results.innerHTML += "属性值是:" + HZH_elem.getAttribute("lang") + "\n";
HZH_results.innerHTML += "为lang属性设置新值\n";
HZH_elem.setAttribute("lang", "en-UK");
HZH_results.innerHTML += "现在的属性值是:" + HZH_elem.getAttribute("lang") + "\n";
</script>
</body>
</html>
在这个例子里,我检查、添加并修改了lang属性的值。从下面中可以看到这段脚本所产生的效果。
使用以data-开头的属性
在DOM里可以通过dataset属性来操作这些自定义属性,它会返回一个包含值的数组,其索引根据的是名称的自定义部分。代码清单5包含了一个例子。
代码清单5 使用dataset属性
<!DOCTYPE HTML>
<html>
<head>
<title>使用dataset属性</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="使用dataset属性"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
p {border: medium double black;}
</style>
</head>
<body>
<p id="HZH_textblock" class="songer" data-songer="HZH_AlanTam" data-sentiment="HZH_like">
繁闹市停留 留下雨和愁<br>
人路过只有我静候<br>
提着伞停留 无力再抬头<br>
全为了心爱已被偷<br>
人和车的四周<br>
无言地我在走<br>
</p>
<pre id="HZH_results"></pre>
<script>
var HZH_results = document.getElementById("HZH_results");
var HZH_elem = document.getElementById("HZH_textblock");
for(var HZH_attr in HZH_elem.dataset) {
HZH_results.innerHTML += HZH_attr + "\n";
}
HZH_results.innerHTML += "歌手数据属性值:" + HZH_elem.dataset["songer"];
</script>
</body>
</html>
dataset属性返回的值数组不像通常的数组那样根据位置进行索引。如果你想要枚举以data-* 开头的各个属性,可以使用一条for...in语句,如示例所示。除此之外,还可以通过名称来请求值。请注意你只需要提供属性名称的自定义部分。举个例子,如果想要获得data-fruit属性的值,就应该请求
dataset["fruit"]
的值。从下面可以看到这段脚本的效果。
使用所有属性
可以通过attributes属性获得一个包含某元素所有属性的集合,它会返回一个由Attr对象构成的数组。下表介绍了Attr对象的属性。
Attr对象的属性
属 性 | 说 明 | 返 回 |
---|---|---|
name | 返回属性的名称 | 字符串 |
value | 获取或设置属性的值 | 字符串 |
代码清单6展示了如何使用attributes属性和Attr对象来读取与修改某个元素的属性。
代码清单6 使用attributes属性
<!DOCTYPE HTML>
<html>
<head>
<title>使用attributes属性</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="使用attributes属性"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
p {border: medium double black;}
</style>
</head>
<body>
<p id="HZH_textblock" class="songer" data-songer="谭咏麟" data-sentiment="HZH_like">
如果命里早注定分手<br>
无需为我假意挽留<br>
如果情是永恒不朽<br>
怎会分手<br>
以后让我倚在深秋<br>
回忆逝去的爱在心头<br>
回忆在记忆中的我<br>
今天曾泪流<br>
</p>
<pre id="HZH_results"></pre>
<script>
var HZH_results = document.getElementById("HZH_results");
var HZH_elem = document.getElementById("HZH_textblock");
var HZH_attrs = HZH_elem.attributes;
for(var HZH_i = 0; HZH_i < HZH_attrs.length; HZH_i++) {
HZH_results.innerHTML += "名字:" + HZH_attrs[HZH_i].name + "值:" + HZH_attrs[HZH_i].value + "\n";
}
HZH_attrs["data-songer"].value = "T-ara";
HZH_results.innerHTML += "Value of data-fruit attr: " + HZH_attrs["data-songer"].value;
</script>
</body>
</html>
正如你从上面的代码中看到的,Attr对象数组中的各个属性同时根据位置和名称进行索引。 在这个例子里,我枚举了应用到某个元素上的属性名称和值,然后修改了其中一个的值。从下面可以看到这段脚本的效果。
使用Text对象
元素的文本内容是由Text对象代表的,它在文档模型里表现为元素的子对象。代码清单7展示了带有一段文本内容的元素。
代码清单7 一个带有文本内容的元素
当浏览器在文档模型里生成p元素的代表时,元素自身会有一个HTMLElement对象,内容则会有一个Text对象,如下图所示。
如果一个元素拥有多个子对象且它们都包含文本,那么这些对象都会以同样的方式进行处理。代码清单8给这个段落添加了一个元素。
代码清单8 给段落添加一个元素
b元素的添加改变了用于代表p元素及其内容的节点层级结构,如下图所示。
p元素的第一个子对象是个Text对象,它代表从文本块开头到b元素的文本。然后是b元素,它有着自己的Text子对象,代表开始标签和结束标签之间的文本。接下来是p元素的最后一个子对象,这个Text对象代表b元素之后直到文本块末尾的文本。下表介绍了Text对象支持的成员。
Text对象的成员
成 员 | 说 明 | 返 回 |
---|---|---|
appendData(<string >) |
把指定字符串附加到文本块末尾 | void |
data | 获取或设置文本 | 字符串 |
deleteData(<offset >, <count >) |
从文本中移除字符串。第一个数字是偏移量,第二个是要移除的字符数量 | void |
insertData(<offset >, <string >) |
在指定偏移量处插入指定字符串 | void |
length | 返回字符的数量 | 数值 |
replaceData(<offset >, <count >, <string >) |
用指定字符串替换一段文本 | void |
replaceWholeText(<string >) |
替换全部文本 | Text |
splitText(<number >) |
将现有的Text元素在指定偏移量处一分为二 | Text |
substringData(<offset >, <count >) |
返回文本的子串 | 字符串 |
wholeText | 获取文本 | 字符串 |
不幸的是,没有什么方便的方法能定位Text元素,只能先找到它们的父元素对象,然后在其子对象中查找。这使得Text元素不必要地难以使用。代码清单9展示了某些Text元素方法和属性的用法。
代码清单9 处理文本
<!DOCTYPE HTML>
<html>
<head>
<title>处理文本</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="处理文本"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
p {border: medium double black;}
</style>
</head>
<body>
<p id="HZH_textblock" class="songer" data-songer="majiko" data-sentiment="HZH_like">
呐,若然能将一切舍弃的话<br>
笑着活下去这样的事就会变的轻松吗?<br>
胸口又再疼痛起来呢<br>
够了什么都不要说了啊<br>
</p>
<button id="HZH_pressme">黄子涵请你按下哦!</button>
<pre id="HZH_results"></pre>
<script>
var HZH_results = document.getElementById("HZH_results");
var HZH_elem = document.getElementById("HZH_textblock");
document.getElementById("HZH_pressme").onclick = function() {
var HZH_textElem = HZH_elem.firstChild;
HZH_results.innerHTML = "这个元素有" + HZH_textElem.length + "字符\n";
HZH_textElem.replaceWholeText("黄子涵告诉你这是一串新字符串。");
}
</script>
</body>
</html>
当button元素被按下,我会显示岀p元素第一个Text子对象里的字符数量,并用replaceWholeText方法修改它的内容。
警告
操作文本时有一点需要注意:空白字符是不会被压缩的。这就意味着你用来组织HTML结构的空格和其他空白字符都会被计算为文本的一部分。
修改模型
在之前,我向你展示了如何使用DOM来修改各个元素。比如,你可以修改它们的属性和文本内容。你能够这么做的原因是文档自身与DOM之间有着实时的连接。一旦你对DOM做了改动,浏览器就会让文档发生相应的变化。你可以进一步利用这种连接来改变文档自身的结构。你可以按照任何你想要的方式添加、移除和复制元素。具体而言就是改动DOM的层级结构,因为连接是实时的,所以你对层级结构所做的改动会立即反映到浏览器中。下表介绍了可用于修改DOM层级结构的属性和方法。
DOM操纵成员
成 员 | 说 明 | 返 回 |
---|---|---|
appendChild(HTMLElement) | 将指定元素添加为当前元素的子元素 | HTMLElement |
cloneNode(boolean) | 复制一个元素 | HTMLElement |
compareDocumentPosition(HTMLElement) | 判断一个元素的相对位置 | 数值 |
innerHTML | 获取或设置元素的内容 | 字符串 |
insertAdjacentHTML(<pos >, <text >) |
相对于元素插入HTML | void |
insertBefore(<newElem >, <childElem >) |
在第二个(子)元素之前插入第一个元素 | HTMLElement |
isEqualNode(<HTMLElement >) |
判断指定元素是否与当前元素相同 | 布尔值 |
isSameNode(HTMLElement) | 判断指定元素是否就是当前元素 | 布尔值 |
outerHTML | 获取或设置某个元素的HTML和内容 | 字符串 |
removeChild(HTMLElement) | 从当前元素上移除指定的子元素 | HTMLElement |
replaceChild(HTMLElement, HTMLElement) | 替换当前元素的某个子元素 | HTMLElement |
这些属性和方法对所有元素对象都是可用的。另外,document对象定义了两个允许你创建新元素的方法。当你想给文档添加内容时它们至关重要。下表介绍了这些创建方法。
DOM操纵成员
成 员 | 说 明 | 返 回 |
---|---|---|
createElement(<tag >) |
创建一个属于指定标签类型的新HTMLElement对象 | HIMLElement |
createTextNode(<text >) |
创建一个带有指定内容的新Text对象 | Text |
创建和删除元素
你需要通过document对象创建新的元素,然后找到一个现存的HTMLElement,并使用之前介绍的某种方法来插入它们。代码清单10对此进行了演示。
代码清单10 创建和删除元素
<!DOCTYPE HTML>
<html>
<head>
<title>创建和删除元素</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="创建和删除元素"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
table {
border: solid thin black;
border-collapse: collapse;
margin: 10px;
}
td { padding: 4px 5px;}
</style>
</head>
<body>
<table border="1">
<thead><th>名字</th><th>粉丝数</th></thead>
<tbody id="songerBody">
<tr><td>陈奕迅</td><td>422.3万</td></tr>
<tr><td>林俊杰</td><td>837.1万</td></tr>
</tbody>
</table>
<button id="HZH_add">添加元素</button>
<button id="HZH_remove">移除元素</button>
<script>
var HZH_tableBody = document.getElementById("songerBody");
document.getElementById("HZH_add").onclick = function() {
var HZH_row = HZH_tableBody.appendChild(document.createElement("tr"));
HZH_row.setAttribute("id", "newrow");
HZH_row.appendChild(document.createElement("td")).appendChild(document.createTextNode("周杰伦"));
HZH_row.appendChild(document.createElement("td")).appendChild(document.createTextNode("1286.2万"));
};
document.getElementById("HZH_remove").onclick = function() {
var HZH_row = document.getElementById("newrow");
HZH_row.parentNode.removeChild(HZH_row);
}
</script>
</body>
</html>
这个例子中的脚本使用DOM来添加和移除一张HTML table的行。在添加行时,我会首先创建一个tr元素,然后把它作为td和Text对象的父元素。请注意我是怎样利用方法返回的结果进行链式调用的,这样做同时也(略微)简化了代码。
如你所见,创建元素的过程很辛苦。你需要创建元素,把它与父元素进行关联,然后对所有的子元素或文本内容重复这一过程。移除元素的过程同样很别扭。必须找到元素,导航至它的父元素,然后使用removechild方法。从下面可以看到这段脚本的效果。
复制元素
可以使用cloneNode方法来复制现有的元素。这个方法有时候很方便,因为它允许你不必从头开始创建想要的元素。代码清单11演示了这种技巧。
代码清单11 复制元素
<!DOCTYPE HTML>
<html>
<head>
<title>复制元素</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="复制元素"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
table {
border: solid thin black;
border-collapse: collapse;
margin: 10px;
}
td { padding: 4px 5px;}
</style>
</head>
<body>
<table border="1">
<thead><tr><th>Multiply</th><th>Result</th></tr></thead>
<tbody id="HZH_MultiplyBody">
<tr><td class="HZH_sum">1×1</td><td class="HZH_result">1</td></tr>
</tbody>
</table>
<button id="HZH_add">黄子涵使它添加行</button>
<script>
var HZH_tableBody = document.getElementById("HZH_MultiplyBody");
document.getElementById("HZH_add").onclick = function() {
var HZH_count = HZH_tableBody.getElementsByTagName("tr").length + 1;
var HZH_newElem = HZH_tableBody.getElementsByTagName("tr")[0].cloneNode(true);
HZH_newElem.getElementsByClassName("HZH_sum")[0].firstChild.data = HZH_count + " × " + HZH_count;
HZH_newElem.getElementsByClassName("HZH_result")[0].firstChild.data = HZH_count * HZH_count;
HZH_tableBody.appendChild(HZH_newElem);
};
</script>
</body>
</html>
在这个例子中,我通过复制表格里现有的一行来创建更多的行。cloneNode方法的布尔值参数指定了是否应该同时复制该元素的所有子元素。在这个例子中,我将它设为true,因为我想让tr元素所含的那些td元素构筑起新行的结构。
提示
请注意示例中为了设置单元格文本而使用的别扭方法。处理Text对象真的很让人头疼。
移动元素
要把元素从文档的一处移到另一处,需要做的仅仅是把待移动的元素关联到新的父元素上,而不需要让该元素脱离它的初始位置。代码清单12通过把表格的某一行移至另一个表格对此进行了演示。
代码清单12 移动元素
<!DOCTYPE HTML>
<html>
<head>
<title>移动元素</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="移动元素"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
table {
border: solid thin black;
border-collapse: collapse;
margin: 10px;
float: left;
}
td { padding: 4px 5px;}
p { clear: left;}
</style>
</head>
<body>
<table border="1">
<thead><tr><th>歌手</th><th>粉丝数</th></tr></thead>
<tbody>
<tr><td>BY2</td><td>76.8万</td></tr>
<tr id="HZH_TerryLin"><td>林志炫</td><td>52.7万</td></tr>
</tbody>
</table>
<table border="1">
<thead><tr><th>歌手</th><th>粉丝数</th></tr></thead>
<tbody id="HZH_songerBody">
<tr><td>f(x)</td><td>26.4万</td></tr>
</tbody>
</table>
<p>
<button id="HZH_move">黄子涵使它移动行</button>
</p>
<script>
document.getElementById("HZH_move").onclick = function() {
var HZH_elem = document.getElementById("HZH_TerryLin");
document.getElementById("HZH_songerBody").appendChild(HZH_elem);
};
</script>
</body>
</html>
当button元素被按下后,脚本会移动id为apple的tr元素,具体做法是在id为fruitsBody的tbody元素上调用appendChild方法。这么做就实现了把该行从一个表格移动到另一个表格的效果,如下面所示。
比较元素对象
可以通过两种方式来比较元素对象。第一种方式是简单地检查它们是否代表了同一个元素,用isSameNode方法可以做到这一点。这让你能够比较从不同查询中获得的对象,如代码清单13所示。
代码清单13 比较元素对象
<!DOCTYPE HTML>
<html>
<head>
<title>比较元素对象</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="比较元素对象"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
table {
border: solid thin black;
border-collapse: collapse;
}
td { padding: 4px 5px;}
</style>
</head>
<body>
<table border="1">
<thead><tr><th>歌手</th><th>粉丝数</th></tr></thead>
<tbody id="HZH_songerBody">
<tr id="HZH_JoeyYung"><td>JoeyYung</td><td>60.2万</td></tr>
</tbody>
</table>
<pre id="HZH_results"></pre>
<script>
var HZH_elemByID = document.getElementById("HZH_JoeyYung");
var HZH_elemByPos = document.getElementById("HZH_songerBody").getElementsByTagName("tr")[0];
if (HZH_elemByID.isSameNode(HZH_elemByPos)) {
document.getElementById("HZH_results").innerHTML = "黄子涵告诉你:对象是相同的哦!";
}
</script>
</body>
</html>
此示例中的脚本用了两种不同的技巧来定位元素对象:通过id搜索和通过父元素里的标签类型搜索。isSameNode方法在比较这些对象时会返回true,因为它们代表的是同一个元素。
另一种方式是测试元素对象是否相同,可以用isEqualNode方法做到这一点。如果多个元素具有相同的类型,带有相同的属性值,其子元素也相同并且顺序一致,那么它们就是相同的。代码清单14演示了一对相同的元素。
代码清单14 使用相同的元素
<!DOCTYPE HTML>
<html>
<head>
<title>使用相同元素</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="使用相同元素"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
table {
border: solid thin black;
border-collapse: collapse;
margin: 2px 0px;
}
td { padding: 4px 5px;}
</style>
</head>
<body>
<table border="1">
<thead><tr><th>歌手</th><th>粉丝数</th></tr></thead>
<tbody>
<tr class="HZH_WangLeehom"><td>王力宏</td><td>172万</td></tr>
</tbody>
</table>
<table border="1">
<thead><tr><th>歌手</th><th>粉丝数</th></tr></thead>
<tbody>
<tr class="HZH_WangLeehom"><td>王力宏</td><td>172万</td></tr>
</tbody>
</table>
<pre id="HZH_results"></pre>
<script>
var HZH_elems = document.getElementsByClassName("HZH_WangLeehom");
if (HZH_elems[0].isEqualNode(HZH_elems[1])) {
document.getElementById("HZH_results").innerHTML = "黄子涵告诉你元素是一样的";
} else {
document.getElementById("HZH_results").innerHTML = "黄子涵告诉你元素是不一样的";
}
</script>
</body>
</html>
在这个例子里,虽然两个tr元素各自独立存在并处于文档的不同位置,但它们是相同的。如果我改变了其中的任何属性或者td子元素里的内容,那么这两个元素就不再是相同的了。
使用HTML片段
innerHTML属性,outerHTML属性和insertAdjacentHTML方法都是便利的语法捷径,它们让你能够使用HTML片段,从而不再需要创建元素和文本对象的详细层级结构。代码清单15演示了如何使用innerHTML和outerHTML属性从元素中获取HTML片段。
代码清单15 使用innerHTML和outerHTML属性
<!DOCTYPE HTML>
<html>
<head>
<title>使用innerHTML和outerHTML属性</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="使用innerHTML和outerHTML属性"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
table {
border: solid thin black;
border-collapse: collapse;
margin: 5px 2px;
float: left;
}
td { padding: 4px 5px;}
p {clear: left};
</style>
</head>
<body>
<table border="1">
<thead><tr><th>歌手</th><th>粉丝数</th></tr></thead>
<tbody>
<tr id="HZH_ChristopherWong"><td>黄凯芹</td><td>25.2万</td></tr>
</tbody>
</table>
<textarea rows="3" id="HZH_results"></textarea>
<p>
<button id="HZH_inner">黄子涵让你看看内层HTML</button>
<button id="HZH_outer">黄子涵让你看看外层HTML</button>
</p>
<script>
var HZH_results = document.getElementById("HZH_results");
var row = document.getElementById("HZH_ChristopherWong");
document.getElementById("HZH_inner").onclick = function() {
HZH_results.innerHTML = row.innerHTML;
};
document.getElementById("HZH_outer").onclick = function() {
HZH_results.innerHTML = row.outerHTML;
}
</script>
</body>
</html>
outerHTML属性返回一个字符串,它包含定义这个元素及其所有子元素的HTML。innerHTML属性则只返回子元素的HTML。在这个例子里,我定义了一对按钮来显示某个表格行的内部和外部HTML。我选择在一个textarea元素里显示内容,这样浏览器就会把这些属性返回的字符串视作文本,而非HTML。从下面可以看到这段脚本的效果。
【点击看效果】使用innerHTML和outerHTML属性
改变文档结构
你也可以使用outerHTML和innerHTML属性来改变文档的结构。如果使用了innerHTML属性,将它作为一种设置元素内容的简便方法,那么就不需要创建Text元素就可以使用该属性来设置文本内容。代码清单16展示了如何使用这些属性来修改文档模型。
代码清单16 修改文档模型
<!DOCTYPE HTML>
<html>
<head>
<title>修改文档模型</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="修改文档模型"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
table {
border: solid thin black;
border-collapse: collapse;
margin: 10px;
float: left;
}
td { padding: 4px 5px;}
p {clear: left;}
</style>
</head>
<body>
<table border="1">
<thead><tr><th>歌手</th><th>粉丝数</th></tr></thead>
<tbody>
<tr><td>方力申</td><td>4.7万</td></tr>
<tr id="HZH_LeonLaiMing"><td>黎明</td><td>25.8万</td></tr>
</tbody>
</table>
<table border="1">
<thead><tr><th>歌手</th><th>粉丝数</th></tr></thead>
<tbody id="songerBody">
<tr><td>Plum</td><td>Purple</td></tr>
<tr id="HZH_targetrow"><td colspan="2">黄子涵告诉你这是占位符</td></tr>
</tbody>
</table>
<p>
<button id="HZH_move">黄子涵使行移动</button>
</p>
<script>
document.getElementById("HZH_move").onclick = function() {
var HZH_source = document.getElementById("HZH_LeonLaiMing");
var HZH_target = document.getElementById("HZH_targetrow");
HZH_target.innerHTML = HZH_source.innerHTML;
HZH_source.outerHTML = '<tr id="HZH_targetrow"><td colspan="2">' + '黄子涵告诉你这是占位符</td>';
};
</script>
</body>
</html>
在这个例子里,我用innerHTML属性设置了某个表格行的子元素,并用outerHTML内联替换了某个元素。这些属性处理的是字符串,这就意味着你可以通过读取属性值或从头创建字符串来得到HTML片段,如前面的代码清单所示。从下面可以看到它的效果。
插入HTML片段
innerHTML和outerHTML属性对于替换现有的元素而言是很有用的,但是如果你想要用HTML片段来插入新元素,就必须使用insertAdjacentHTML方法。这个方法需要两个参数:第一个参数是下表中的某个值,它指明片段应该被插入到相对于当前元素的哪个位置,第二个参数是要插入的片段。
insertAdjacentHTML方法的定位参数值
值 | 说 明 |
---|---|
afterbegin | 将片段作为当前元素的第一个子元素插入 |
afterend | 将片段插入当前元素之后 |
beforebegin | 将片段插入当前元素之前 |
beforeend | 将片段作为当前元素的最后一个子元素插入 |
代码清单17展示了如何使用insertAdjacentHTML方法将HTML片段插入某个表格行元素的内部和周围。
代码清单17 使用insertAdjaCeirtHTML方法
<!DOCTYPE HTML>
<html>
<head>
<title>使用insertAdjacentHTML方法</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="使用insertAdjacentHTML方法"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<table border="1">
<thead><tr><th>歌手</th><th>粉丝数</th></tr></thead>
<tbody id="HZH_songerBody">
<tr id="HZH_targetrow"><td>Forget And Forgive</td></tr>
</tbody>
</table>
<p>
<button id="HZH_JolinTsai">蔡依林</button>
<button id="HZH_TimmyXu">许魏洲</button>
<button id="HZH_SamuelHui">许冠杰</button>
<button id="HZH_ChristopherWong">黄凯芹</button>
</p>
<script>
var target = document.getElementById("HZH_targetrow");
var HZH_buttons = document.getElementsByTagName("button");
for (var HZH_i = 0; HZH_i < HZH_buttons.length; HZH_i++) {
HZH_buttons[HZH_i].onclick = handleButtonPress;
}
function handleButtonPress(e) {
if (e.target.id == "HZH_JolinTsai") {
target.insertAdjacentHTML("afterbegin", "<td>蔡依林</td>");
} else if (e.target.id == "HZH_ChristopherWong") {
target.insertAdjacentHTML("beforeend", "<td>黄凯芹</td>");
} else if (e.target.id == "HZH_SamuelHui") {
target.insertAdjacentHTML("beforebegin", "<tr><td colspan='2'>许冠杰</td></tr>");
} else {
target.insertAdjacentHTML("afterend", "<tr><td colspan='2'>许魏洲</td></tr>");
}
}
</script>
</body>
</html>
在这个例子里,我使用不同的定位值来演示如何将HTML片段插入不同的位置。这个例子最好的理解方式是在浏览器中实际操作一下,不过从下面也可以看到它的基本效果。
向文本块插入元素
修改模型的另一种重要方式是向由Text对象代表的文本块添加元素。代码清单18展示了具体的做法。
代码清单18 将一个元素插入文本块
<!DOCTYPE HTML>
<html>
<head>
<title>将一个元素插入文本块</title>
<meta name="作者" content="黄子涵"/>
<meta name="描述" content="将一个元素插入文本块"/>
<link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<p id="HZH_textblock">
晚安 鹦鹉和孔雀<br>
花豹和人类 望着海面<br>
晚安 底片和唱片<br>
沉浮在浪间 就像诗篇<br>
晚安 自由女神漂到华尔街<br>
我们在甲板上摸到<br>
杜拜塔顶的塔尖<br>
晚安 海豚跃出西藏的屋檐<br>
原来幻想中的这天<br>
会比幻想更唯美<br>
</p>
<p>
<button id="HZH_insert">黄子涵请你插入元素</button>
</p>
<script>
document.getElementById("HZH_insert").onclick = function() {
var HZH_textblock = document.getElementById("HZH_textblock");
HZH_textblock.firstChild.splitText(10);
var HZH_newText = HZH_textblock.childNodes[1].splitText(4).previousSibling;
HZH_textblock.insertBefore(document.createElement("b"), HZH_newText).appendChild(HZH_newText);
}
</script>
</body>
</html>
在这个例子里,我完成了一项稍有难度的任务,即从现有的文本取出一个单词,然后让它变成新元素b的一个子元素。和之前这些例子一样,对模型进行操作就意味着要写一些繁琐的代码。下面展示了结果。