--- title: 操作文档 slug: Learn/JavaScript/Client-side_web_APIs/Manipulating_documents translation_of: Learn/JavaScript/Client-side_web_APIs/Manipulating_documents ---
在编写web页面或应用时,你最想做的事情之一就是以某种方式操作文档结构。这通常使用一套大量使用{{domxref("Document")}}对象来控制HTML和样式信息的文档对象模型(DOM)来实现,在本文中,我们可以更详细的看到怎样使用DOM,连同一些其他有趣的API以有趣的方式改变你的环境
前提: | 基础的计算机常识,基本了解HTML、CSS和JavaScript - 包括JavaScript对象。 |
---|---|
目标: | 熟悉核心DOM API, 以及其他和DOM与文档操作相关的常见API。 |
web浏览器的软件中有很多活动的程序片段,而许多片段web开发人员无法使用JavaScript来控制或操作,因此Web浏览器是一个很复杂的软件组合。你可能认为这样的限制是不是好事,但是浏览器被锁定是有充分理由的,主要集中在安全方面。如果一个网站可以访问您存储的密码或其他敏感信息,犹如你一样登录到网站,试想会发生什么?
尽管有局限性,Web API仍然允许我们访问许多的功能,使我们用web页做很多事情。有几个在代码中经常引用的非常明显的部位 - 下面的图表表示了直接出现在web页面视图中的浏览器的主要部分:
在本文中,我们主要关注操作文档,但是也会稍微关注一下其他有用的部位。
在浏览器标签中当前载入的文档用文档对象模型来表示。这是一个由浏览器生成的“树结构”,使编程语言可以很容易的访问HTML结构 — 例如浏览器自己在呈现页面时,使用它将样式和其他信息应用于正确的元素,而页面呈现完成以后,开发人员可以用JavaScript操作DOM。
我们已经创建一个简单的例子dom-example.html (see it live also). 在你的浏览器中打开它 — 这是一个很简单的页面,包含了一个{{htmlelement("section")}} 元素,里面有一个图像和有链接的段落。HTML源码如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Simple DOM example</title> </head> <body> <section> <img src="dinosaur.png" alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth."> <p>Here we will add a link to the <a href="https://www.mozilla.org/">Mozilla homepage</a></p> </section> </body> </html>
另一方面,DOM树如下所示:
注意: 这个DOM树状图是用Ian Hickson的Live DOM viewer生成的
这里你可以看到,文档中每个元素和文本在树中都有它们自己的入口 — 称之为节点。你将用不同的术语来描述节点的类型和它们相对于其他节点的位置:
HTML
节点(其他标记词汇,如SVG和定制XML将有不同的根元素)。IMG
是SECTION
的子节点。IMG
是SECTION
的子节点,也是一个后代节点。IMG
不是BODY
的子节点,因为它在树中低了BODY
两级,但它是BODY
的后代之一。BODY
是SECTION
的父节点。IMG
和P
是兄弟。在用DOM工作之前,熟悉这些术语是很有用的,因为你将会遇到大量代码术语的使用。你在研究CSS时也会遇到这些术语(例如后代选择器、子选择器)
要开始学习DOM操作,我们先做一个实际的例子。
</body>
标签上面加入<script></script>
元素。var link = document.querySelector('a');
link.textContent = 'Mozilla Developer Network';
link.href = 'https://developer.mozilla.org';
注意,和JavaScript中的许多事情一样,有很多方法可以选择一个元素,并在一个变量中存储一个引用。{{domxref("Document.querySelector()")}}是推荐的主流方法,它允许你使用CSS选择器选择元素,使用很方便。上面的querySelector()
调用会匹配它在文档中遇到的第一个{{htmlelement("a")}}元素。如果想对多个元素进行匹配和操作,你可以使用{{domxref("Document.querySelectorAll()")}},这个方法匹配文档中每个匹配选择器的元素,并把它们的引用存储在一个array中。
对于获取元素引用,还有一些更旧的方法,如:
id
属性值已知的元素,例如<p id="myId">My paragraph</p>
。ID作为参数传递给函数,即 var elementRef = document.getElementById('myId')
。<p>
s, <a>
。元素类型作为参数传递给函数,即var elementRefArray = document.getElementsByTagName('p')
.在较老的浏览器中使用这两种方法而不是流行的querySelector()
方法,但这样并不方便。看一看你还可以发现别的什么!
以上只是让你稍微尝试一下你可以做的事情,让我们进一步看看我们可以怎样来创建新的元素。
var sect = document.querySelector('section');
var para = document.createElement('p'); para.textContent = 'We hope you enjoyed the ride.';
sect.appendChild(para);
var text = document.createTextNode(' — the premier source for web development knowledge.');
var linkPara = document.querySelector('p'); linkPara.appendChild(text);
这是给DOM添加节点要做的大部分工作 — 在构建动态接口时,你将做大量使用这些方法(我们在后面可以看到一些例子)。
也许有时候你想移动或从DOM中删除节点,这是完全可能的。
如果你想把具有内部链接的段落移到sectioin的底部,简单的做法是:
sect.appendChild(linkPara);
这样可以把段落下移到section的底部。你可能想过要做第二个副本,但是情况并非如此 — linkPara
是指向该段落唯一副本的引用。如果你想做一个副本并也把它添加进去,只能用{{domxref("Node.cloneNode()")}} 方法来替代。
删除节点也非常的简单,至少,你拥有要删除的节点和其父节点的引用。在当前情况下,我们只要使用{{domxref("Node.removeChild()")}}即可,如下:
sect.removeChild(linkPara);
要删除一个仅基于自身引用的节点可能稍微有点复杂,这也是很常见的。没有方法会告诉节点删除自己,所以你必须像下面这样操作。
linkPara.parentNode.removeChild(linkPara);
把上述代码行加到你的代码中去
通过JavaScript以不同的方式来操作CSS样式是可能的。
首先,使用 {{domxref("Document.stylesheets")}}返回{{domxref("CSSStyleSheet")}}数组,获取绑定到文档的所有样式表的序列。然后添加/删除想要的样式。然而,我们并不想扩展这些特性,因此它们在操作样式方面有点陈旧和困难,而现在有了更容易的方法。
第一种方法是直接在想要动态设置样式的元素内部添加内联样式。这是用{{domxref("HTMLElement.style")}}属性来实现。这个属性包含了文档中每个元素的内联样式信息。你可以设置这个对象的属性直接修改元素样式。
para.style.color = 'white'; para.style.backgroundColor = 'black'; para.style.padding = '10px'; para.style.width = '250px'; para.style.textAlign = 'center';
<p style="color: white; background-color: black; padding: 10px; width: 250px; text-align: center;">We hope you enjoyed the ride.</p>
注意: CSS样式的JavaSript属性版本以小驼峰式命名法书写,而CSS版本带连接符号(backgroundColor
对 background-color
)。确保你不会混淆,否则就不能工作。
现在我们来看看另一个操作文档样式的常用方法。
<style> .highlight { color: white; background-color: black; padding: 10px; width: 250px; text-align: center; } </style>
para.setAttribute('class', 'highlight');
两种方式各有优缺点,选择哪种取决于你自己。第一种方式无需安装,适合简单应用,第二种方式更加正统(没有CSS和JavaScript的混合,没有内联样式,而这些被认为是不好的体验)。当你开始构建更大更具吸引力的应用时,你可能会更多地使用第二种方法,但这完全取决于你自己。
在这一点上,我们还没有做任何有用的事!使用JavaScript创建静态内容是毫无意义的 — 最好将其写入HTML,而不使用JavaScript。用JavaScript创建内容也有其他问题(如不能被搜索引擎读取),比HTML复杂得多。
在接下来的几节中我们将看看DOM API一些更实际的用途。
注意: 你可以在GitHub上找到演示程序finished version of the dom-example.html (see it live also).
到目前为止,我们只真正看到使用{{domxref("Node")}}和{{domxref("Document")}} 特性来操纵文档,但是没有理由不能从其他来源获取数据并在UI中使用它。想想我们最新文件中的演示例子 maps-example.html — 那里我们获取一些位置数据并用来显示你所在区域的地图。你只要确保你的数据格式正确;使用JavaScript比其他许多语言更容易,因为它是弱类型的——例如,当你想把它们打印到屏幕上时,数字会自动转换成字符串。
在这个例子中,我们解决了一个常见的问题 — 不管窗口的大小是多少,确保应用程序和它所在的窗口视图一样大。在玩游戏的情况下,想在游戏中尽可能多地使用屏幕区域,这种方法是很有用的。
一开始,要做一个window-resize-example.html和bgtile.png文件的本地拷贝。打开文件看一看 — 你可以看到我们用一个{{htmlelement("div")}}元素包裹屏幕的小部分,用来获得应用的background tile。我们也用它来表示应用的UI区域。
var div = document.querySelector('div'); var WIDTH = window.innerWidth; var HEIGHT = window.innerHeight;
div.style.width = WIDTH + 'px'; div.style.height = HEIGHT + 'px';
window.onresize = function() { WIDTH = window.innerWidth; HEIGHT = window.innerHeight; div.style.width = WIDTH + 'px'; div.style.height = HEIGHT + 'px'; }
注意: 如果你被卡住了,可查看finished window resize example (see it live also).
作为文章的收尾,我们想给你一个小小的挑战 — 我们要做一个简单的购物单的例子,使用表单的输入框和按钮动态的向购物单中添加购物项。在输入中添加项,然后按下按钮:
完成后的演示程序看起来有点像这样的:
要完成实验,要按照下面的步骤,确保购物单的行为如上所述。
''
使其为空focus()
方法聚焦输入框准备输入下一个购物项。注意: 如果你卡住了,请查看finished shopping list (see it running live also.)
我们已经结束了对文档和DOM操作的研究。在这一点上,你应该了解Web浏览器在控制文档和用户Web体验的其他方面方面的重要部分。更重要的是,你应该了解什么是文档对象模型,怎样操作它来创建有用的功能。
你还可以使用更多的特性来操作文档,检查一些参考,看看你能发现些什么?
(MDN上有完整的Web API 列表,参见Web API接口参考 !)