客户端网页API(一)——操作文档

在编写web页面或应用时,你最想做的事情之一就是以某种方式操作文档结构。这通常使用一套大量使用Document对象来控制HTML和样式信息的文档对象模型(DOM)来实现,在本文中,我们可以更详细的看到怎样使用DOM,连同一些其他有趣的API以有趣的方式改变你的环境


web浏览器的重要部分

web浏览器的软件中有很多活动的程序片段,而许多片段web开发人员无法使用JavaScript来控制或操作,因此Web浏览器是一个很复杂的软件组合。你可能认为这样的限制是不是好事,但是浏览器被锁定是有充分理由的,主要集中在安全方面。如果一个网站可以访问您存储的密码或其他敏感信息,犹如你一样登录到网站,试想会发生什么?

尽管有局限性,Web API仍然允许我们访问许多的功能,使我们用web页做很多事情。有几个在代码中经常引用的非常明显的部位 - 下面的图表表示了直接出现在web页面视图中的浏览器的主要部分:

  • window 是载入浏览器的标签,在JavaScript中用 Window 对象来表示,使用这个对象的可用方法,你可以返回窗口的大小(Window.innerWidthWindow.innerHeight),操作载入窗口的文档,存储客户端上文档的特殊数据(例如使用本地数据库或其他存储设备),为当前窗口绑定 event handler,等等。
  • navigator 表示浏览器存在于web上的状态和标识(即用户代理)。在JavaScript中,用 Navigator 来表示。你可以用这个对象获取一些信息,比如来自用户摄像头的地理信息、用户偏爱的语言、多媒体流等等。
  • document(在浏览器中用DOM表示)是载入窗口的实际页面,在JavaScript中用 Document 对象表示,你可以用这个对象来返回和操作文档中HTML和CSS上的信息。例如获取DOM中一个元素的引用,修改其文本内容,并应用新的样式,创建新的元素并添加为当前元素的子元素,甚至把他们一起删除。

在本文中,我们主要关注操作文档,但是也会稍微关注一下其他有用的部位。


文档对象模型

在浏览器标签中当前载入的文档用文档对象模型来表示。这是一个由浏览器生成的“树结构”,使编程语言可以很容易的访问HTML结构 — 例如浏览器自己在呈现页面时,使用它将样式和其他信息应用于正确的元素,而页面呈现完成以后,开发人员可以用JavaScript操作DOM。

一个简单的示例

<!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中。
  • 根节点: 树中顶层节点,在HTML的情况下,总是一个 HTML 节点(其他标记词汇,如SVG和定制XML将有不同的根元素)。
  • 子节点: 直接位于另一个节点内的节点。例如上面例子中,IMGSECTION 的子节点。
  • 后代节点: 位于另一个节点内任意位置的节点。例如 上面例子中,IMGSECTION 的子节点,也是一个后代节点。IMG 不是 BODY 的子节点,因为它在树中低了 BODY 两级,但它是 BODY 的后代之一。
  • 父节点: 里面有另一个节点的节点。例如上面的例子中 BODYSECTION 的父节点。
  • 兄弟节点: DOM树中位于同一等级的节点。例如上面例子中,IMGP 是兄弟。
  • 文本节点: 包含文字串的节点

在用DOM工作之前,熟悉这些术语是很有用的,因为你将会遇到大量代码术语的使用。你在研究CSS时也会遇到这些术语(例如后代选择器、子选择器)


基本的DOM操作

要开始学习DOM操作,我们先做一个实际的例子。

  1. 本地备份dom-example.html page和与之相关的 image
  2. 在闭合的 </body> 标签上面加入 <script></script> 元素。
  3. 要操作DOM内的元素,首先需要选择它,并将它的引用存储在一个变量中。在script元素中,添加下列代码行
var link = document.querySelector('a');
  1. 现在你有了一个存储在变量中的元素引用,你可以使用它的可用属性和方法来操作它(在 <a> 元素的情况下定义为接口 HTMLAnchorElement,它更常常用的父接口是 HTMLElement 和表示DOM中所有节点的 Node)。首先,更新 Node.textContent 属性的值来修改链接中的文字。在上面的代码后面加入一行代码:
link.textContent = 'Mozilla Developer Network';
  1. 我们也能修改链接指向的URL,使得它被点击时不会走向错误的位置。在底部再加入下列代码:
link.href = 'https://developer.mozilla.org';

注意,和JavaScript中的许多事情一样,有很多方法可以选择一个元素,并在一个变量中存储一个引用。Document.querySelector() 是推荐的主流方法,它允许你使用CSS选择器选择元素,使用很方便。上面的querySelector() 调用会匹配它在文档中遇到的第一个 <a> 元素。如果想对多个元素进行匹配和操作,你可以使用Document.querySelectorAll() ,这个方法匹配文档中每个匹配选择器的元素,并把它们的引用存储在一个 array 中。

对于获取元素引用,还有一些更旧的方法,如:

  • Document.getElementById(),选择一个 id 属性值已知的元素,例如 <p id="myId">My paragraph</p>ID 作为参数传递给函数,即 var elementRef = document.getElementById('myId')
  • Document.getElementsByTagName(),返回页面中包含的所有已知类型元素的数组。如 <p>s, <a>。元素类型作为参数传递给函数,即 var elementRefArray = document.getElementsByTagName('p').

在较老的浏览器中使用这两种方法而不是流行的 querySelector() 方法,但这样并不方便。看一看你还可以发现别的什么!

创建并放置新的节点

以上只是让你稍微尝试一下你可以做的事情,让我们进一步看看我们可以怎样来创建新的元素。

  1. 回到当前的例子,我们先获取到 <section> 元素的引用 — 在已有 script 中添加下列代码(其他代码也同样处理):
var sect = document.querySelector('section');
  1. 现在用 Document.createElement() 创建一个新的段落,用与之前相同的方法赋予相同的文本:
var para = document.createElement('p');
para.textContent = 'We hope you enjoyed the ride.';
  1. 现在可以用 Node.appendChild() 方法在后面追加新的段落:
sect.appendChild(para);
  1. 最后,在内部链接的段落中添加文本节点,完美的结束句子。首先我们要使用 Document.createTextNode() 创建一个文本节点:
var text = document.createTextNode(' — the premier source for web development knowledge.');
  1. 现在获取内部连接的段落的引用,并把文本节点绑定到这个节点上:
var linkPara = document.querySelector('p');
linkPara.appendChild(text);

这是给DOM添加节点要做的大部分工作 — 在构建动态接口时,你将做大量使用这些方法(我们在后面可以看到一些例子)。

移动和删除元素

也许有时候你想移动或从DOM中删除节点,这是完全可能的。

如果你想把具有内部链接的段落移到 sectioin 的底部,简单的做法是:

sect.appendChild(linkPara);

这样可以把段落下移到 section 的底部。你可能想过要做第二个副本,但是情况并非如此 — linkPara 是指向该段落唯一副本的引用。如果你想做一个副本并也把它添加进去,只能用 Node.cloneNode() 方法来替代。

删除节点也非常的简单,至少,你拥有要删除的节点和其父节点的引用。在当前情况下,我们只要使用Node.removeChild() 即可,如下:

sect.removeChild(linkPara);

要删除一个仅基于自身引用的节点可能稍微有点复杂,这也是很常见的。没有方法会告诉节点删除自己,所以你必须像下面这样操作。

linkPara.parentNode.removeChild(linkPara);

把上述代码行加到你的代码中去

操作样式

通过JavaScript以不同的方式来操作CSS样式是可能的。

首先,使用 Document.stylesheets 返回 CSSStyleSheet 数组,获取绑定到文档的所有样式表的序列。然后添加/删除想要的样式。然而,我们并不想扩展这些特性,因此它们在操作样式方面有点陈旧和困难,而现在有了更容易的方法。

第一种方法是直接在想要动态设置样式的元素内部添加内联样式。这是用 HTMLElement.style 属性来实现。这个属性包含了文档中每个元素的内联样式信息。你可以设置这个对象的属性直接修改元素样式。

  1. 把下面代码加入到我们的例子中:
para.style.color = 'white';
para.style.backgroundColor = 'black';
para.style.padding = '10px';
para.style.width = '250px';
para.style.textAlign = 'center';
  1. 重新载入页面,你将看到样式已经应用到段落中。如果在浏览器的 Page Inspector/DOM inspector 中查看段落,你会看到这些代码的确为文档添加了内联样式:
<p style="color: white; background-color: black; padding: 10px; width: 250px; text-align: center;">We hope you enjoyed the ride.</p>

现在我们来看看另一个操作文档样式的常用方法。

  1. 删除之前添加到JavaScript中的五行代码。
  2. 在HTML的 <head> 中添加下列代码 :
<style>
.highlight {
  color: white;
  background-color: black;
  padding: 10px;
  width: 250px;
  text-align: center;
}
</style>
  1. 现在我们改为使用HTML操作的常用方法 — Element.setAttribute() — 这里有两个参数,你想在元素上设置的属性,你要为它设置的值。在这种情况下,我们在段落中设置类名为highlight:
para.setAttribute('class', 'highlight');
  1. 刷新页面,看不到改变 — CSS仍然应用到段落,但是这次给出CSS规则选择的类不是内联CSS样式。

两种方式各有优缺点,选择哪种取决于你自己。第一种方式无需安装,适合简单应用,第二种方式更加正统(没有CSS和JavaScript的混合,没有内联样式,而这些被认为是不好的体验)。当你开始构建更大更具吸引力的应用时,你可能会更多地使用第二种方法,但这完全取决于你自己。

在这一点上,我们还没有做任何有用的事!使用JavaScript创建静态内容是毫无意义的 — 最好将其写入HTML,而不使用JavaScript。用JavaScript创建内容也有其他问题(如不能被搜索引擎读取),比HTML复杂得多。

在接下来的几节中我们将看看DOM API一些更实际的用途。


从Window对象中获取有用的信息

到目前为止,我们只真正看到使用Node和Document 特性来操纵文档,但是没有理由不能从其他来源获取数据并在UI中使用它。

在下面这个例子中,我们解决了一个常见的问题 — 不管窗口的大小是多少,确保应用程序和它所在的窗口视图一样大。在玩游戏的情况下,想在游戏中尽可能多地使用屏幕区域,这种方法是很有用的。

一开始,要做一个window-resize-example.htmlbgtile.png文件的本地拷贝。打开文件看一看 — 你可以看到我们用一个 <div> 元素包裹屏幕的小部分,用来获得应用的background tile。我们也用它来表示应用的UI区域。

  1. 首先,获取这个div的引用,然后获取视窗(显示文档的内部窗口)的宽度和高度, 并存入变量中 — 这两个值包含在 Window.innerWidthWindow.innerHeight 属性中。在已存在的 <script> 元素中加入下列代码:
var div = document.querySelector('div');
var WIDTH = window.innerWidth;
var HEIGHT = window.innerHeight;
  1. 接下来,我们将动态地改变 div 的宽度和高度,使其等于视窗的宽度和高度。 在您的代码下面添加以下两行:
div.style.width = WIDTH + 'px';
div.style.height = HEIGHT + 'px';
  1. 保存并刷新浏览器 — 现在可以看到不管你使用什么大小的屏幕,div 变得和视窗一样大。如果要调整窗口大小使其更大,你可以看到div会保持相同大小 — 因为我们只能设置一次。
  2. 在我们调整窗口时,我们怎样用事件来调整 div 的大小? Window 对象有一个称为 resize 的可用事件。每次窗口调整大小时都会触发该事件 — 我们可以通过 Window.onresize 事件处理程序来访问它,并返回每次改变大小的代码。在代码底部添加下列程序:
window.onresize = function() {
  WIDTH = window.innerWidth;
  HEIGHT = window.innerHeight;
  div.style.width = WIDTH + 'px';
  div.style.height = HEIGHT + 'px';
}

案例:一个动态的购物清单

作为文章的收尾,我们想给你一个小小的挑战 — 我们要做一个简单的购物单的例子,使用表单的输入框和按钮动态的向购物单中添加购物项。在输入中添加项,然后按下按钮:

  • 购物项应该出现在清单中。
  • 每个购物项都应该给出一个按钮,可以按下按钮从清单中删除该项。
  • 输入框应该是空白的并已聚焦,为你准备好输入另一个项。

完成后的演示程序看起来有点像这样的:

要完成实验,要按照下面的步骤,确保购物单的行为如上所述。

  1. 首先,下载shopping-list.html文件,并存入本地。你会看到它有一些极小的CSS,一个带有 labelinputbuttonlist 和一个空的 list 以及 <script> 元素。要添加的所有程序都在 script 里面。
  2. 创建三个变量来保存list(<ul>)<input><button> 元素的引用。
  3. 创建一个函数响应点击按钮。
  4. 在函数体内,开始要在一个变量中存储输入框的当前值。
  5. 然后,为输入框元素设置空字符 - ''使其为空
  6. 创建三个新元素 — 一个 list 项(<li>),<span><button>,并把它们存入变量之中。
  7. spanbutton 作为 list 项的子节点。
  8. 把之前保存的输入框元素的值设置为 span 的文本内容,按钮的文本内容设置为’Delete
  9. list 项设置为 list 的子节点。
  10. 为删除按钮绑定事件处理程序。当点击按钮时,删除它所在的整个 list 项。
  11. 最后,使用 focus() 方法聚焦输入框准备输入下一个购物项。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值