黄子涵

第 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属性

当你想要快速给某个元素添加类时,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的类。这个类关联了一个样式,从下面可以看到类的变化所带来的视觉效果。

【点击看效果】使用classList属性

使用元素属性

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"]的值。从下面可以看到这段脚本的效果。

【点击看效果】使用dataset属性

使用所有属性

可以通过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对象数组中的各个属性同时根据位置和名称进行索引。 在这个例子里,我枚举了应用到某个元素上的属性名称和值,然后修改了其中一个的值。从下面可以看到这段脚本的效果。

【点击看效果】使用attributes属性

使用Text对象

元素的文本内容是由Text对象代表的,它在文档模型里表现为元素的子对象。代码清单7展示了带有一段文本内容的元素。

代码清单7 一个带有文本内容的元素

image

当浏览器在文档模型里生成p元素的代表时,元素自身会有一个HTMLElement对象,内容则会有一个Text对象,如下图所示。

image

如果一个元素拥有多个子对象且它们都包含文本,那么这些对象都会以同样的方式进行处理。代码清单8给这个段落添加了一个元素。

代码清单8 给段落添加一个元素

image

b元素的添加改变了用于代表p元素及其内容的节点层级结构,如下图所示。

image

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片段插入不同的位置。这个例子最好的理解方式是在浏览器中实际操作一下,不过从下面也可以看到它的基本效果。

【点击看效果】使用insertAdjacentHTML方法

向文本块插入元素

修改模型的另一种重要方式是向由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的一个子元素。和之前这些例子一样,对模型进行操作就意味着要写一些繁琐的代码。下面展示了结果。

【点击看效果】将一个元素插入文本块

posted @ 2021-10-31 10:45  黄子涵  阅读(57)  评论(0编辑  收藏  举报