原文:Pro jQuery 2.0
协议:CC BY-NC-SA 4.0
一、将 jQuery 放入上下文
从本质上来说,jQuery 做了一些听起来很枯燥的事情:它允许你通过操作浏览器在处理 HTML 时创建的模型来修改网页的内容,这个过程被称为 DOM(文档对象模型)操作,我将在后面详细描述。如果您已经阅读了这本书,那么您可能已经使用另一个 JavaScript 库或内置的 web 浏览器 API(应用编程接口)完成了一些 DOM 操作,现在您想以更好的方式完成它。
jQuery 超越更好。这使得 DOM 操作成为一种乐趣,有时甚至是真正的快乐。jQuery 的工作方式非常优雅,它将一项可能非常枯燥的任务转化为简单易行的工作。一旦开始使用 jQuery,就没有回头路了。以下是我在项目中使用 jQuery 的主要原因。
- jQuery 富于表现力。我可以用更多的代码做更多的工作。
- *jQuery 方法适用于多个元素。*选择-迭代-修改的 DOM API 方法消失了,这意味着更少的
for
循环来迭代元素和更少的错误。 - jQuery 处理浏览器之间的实现差异。我不用担心 Internet Explorer (IE)是否以古怪的方式支持某个特性,比如;我只需告诉 jQuery 我想要什么,它就能解决我的实现差异。
- jQuery 是开源的。当我不明白一些事情是如何工作的,或者我没有得到我期望的结果时,我可以通读 JavaScript 代码,如果需要的话,进行修改。
jQuery 的天才之处在于,它将 web 开发中的一些主要工作变得简单、快速和容易。我不能要求更多了。当然,并不是一切都是完美的,有一两个粗糙的边缘,我会在进入细节时解释。但是即使偶尔会有瑕疵,我还是喜欢使用 jQuery,我希望您会发现它同样引人入胜,令人愉快。
了解 jQuery UI 和 jQuery Mobile
除了核心的 jQuery 库之外,我还介绍了 jQuery UI 和 jQuery Mobile ,它们是构建在 jQuery 之上的用户界面(UI)库。jQuery UI 是一个通用的 UI 工具包,可以在任何设备上使用,jQuery Mobile 是为智能手机和平板电脑等支持触摸的设备设计的。
了解 jQuery 插件
jQuery 插件扩展了基本库的功能。有些插件非常好,应用非常广泛,我在本书中已经介绍过了。有很多可用的插件(尽管质量可能有所不同),因此如果您不喜欢我在本书中描述的插件,您可以确信有一种替代方法可用。
我需要知道什么?
在阅读本书之前,您应该熟悉 web 开发的基础知识,了解 HTML 和 CSS(级联样式表)的工作原理,并且,理想情况下,具备 JavaScript 的工作知识。如果你对其中的一些细节不太清楚,我在第二章第一章、第三章第三章和第四章第五章提供了 HTML、CSS 和 JavaScript 的刷新工具。但是,你不会找到关于 HTML 元素和 CSS 属性的全面参考。在一本关于 jQuery 的书中,没有足够的空间来涵盖整个 HTML。如果你想要 HTML 和 CSS 的完整参考,那么我推荐我的另一本书:HTML 5 权威指南,也是由 Apress 出版的。
这本书的结构是什么?
这本书分为六个部分,每个部分涵盖一系列相关的主题。
第一部分:做好准备
本书的第一部分提供了您需要为本书的其余部分做准备的信息。它包括本章和 HTML、CSS 和 JavaScript 的入门/刷新。在这一章的后面,我将描述你需要的软件,以便跟随。
第二部分:使用 jQuery
本书的第二部分向您介绍了 jQuery 库,从一个基本示例开始,逐步扩展到包括每个核心特性 :元素选择、DOM 操作、事件和效果。
第三部分:使用数据和 Ajax
本书的第三部分展示了 jQuery 如何使处理内联或远程数据成为可能。我将向您展示如何从数据中生成 HTML 内容,如何验证输入到 web 表单中的数据,以及如何使用 jQuery 执行异步操作,包括 Ajax。
第四部分:使用 jQuery UI
jQuery UI 是我在本书中描述的两个用户界面库之一。jQuery UI 构建于核心 jQuery 库之上并与之集成,允许您为 web 应用创建丰富且响应迅速的界面。
第五部分:使用 jQuery Mobile
jQuery Mobile 是我在本书中介绍的另一个用户界面库。jQuery Mobile 构建在 jQuery 之上,并结合了 jQuery UI 的一些基本功能,但已经针对创建智能手机和平板电脑界面进行了优化。jQuery Mobile 中可用的 UI 小部件较少,但那些受支持的小部件针对触摸交互和较小显示器上的显示进行了优化。
第六部分:高级功能
本书的最后一部分描述了一些不常用的 jQuery 和 jQuery UI 特性,这些特性在复杂的项目中可能会有所帮助。这些高级特性需要对 HTML、CSS 和 jQuery 本身有更好的理解。在阅读第三十六章时,一点异步编程的基础知识很有帮助。
这个版本有什么新内容?
从这本书的第一版开始,jQuery、jQuery UI 和 jQuery Mobile 都发生了实质性的变化。
核心 jQuery 有什么新特性?
核心 jQuery 库的 API 非常稳定。几年前,jQuery 团队开始列出他们打算进行的更改,这些更改随着 jQuery 1.9 版的发布而实现。其中一些变化相当大,我已经在本书第二部分的每一章中指出了这些变化。
好消息是,这些变化非常罕见,API 可能会在几年内保持稳定。这并不是说不会增加新的特性,但是你今天开发的代码在未来一段时间内不需要修改就可以继续工作。
坏消息是,jQuery 团队在发布 jQuery 1.9 时做了一些不寻常的事情——他们还发布了 jQuery 2.0,因此他们将开发分成并行发布的两个系列:jQuery 1 . x 和 jQuery 2.x。这两个发布系列具有相同的 API,但 jQuery 2.x 不支持 IE 的 6、7 和 8 版本。
IE 的旧版本因其对 HTML、CSS 和 JavaScript 的非标准方法而臭名昭著,删除所有对奇怪行为的检查和相关的变通办法使 jQuery 2.x 变得更小更快。
提示在撰写本文时,jQuery 的当前版本是 2.0.2 和 1.10.1。理解 jQuery 2.0.2 并不能取代 1.10.1 版是很重要的。它们都是最新版本,唯一的区别是 jQuery 1.10.1 保留了对 Internet Explorer 旧版本的支持。
如果您确定您的用户都不会安装 Internet Explorer 6、7 或 8,那么您应该使用 jQuery 2.x。如果情况不是这样,或者您不确定,那么您应该使用 jQuery 1.x。这些版本的 IE 仍然被广泛使用,尤其是在大公司中,您应该仔细考虑使用 2.x 行的影响。
在编程书籍的理想化世界中没有遗留用户,我将在本书的大部分内容中使用 jQuery 2.0.2 库——但是您可以替换任何版本的 jQuery 1.x 行(从版本 1.9 开始)并获得相同的结果,同时保留对旧版本 IE 的支持。
提示我在第四部分描述 jQuery Mobile 的时候用的是 jQuery 1.x。jQuery Mobile 往往落后于主要的 jQuery 版本,在我写这篇文章时,它只支持 jQuery 1.x。
jQuery UI 有什么新特性?
jQuery UI 也进行了更新。使用现有用户界面小部件的 API 已经更新,更加一致,并且与支撑它们的 HTML 元素更加紧密地配合,并且添加了一些新的小部件。在本书的整个第三部分中,您会发现我在每章的开头都展示了重要的变化,就像我在第二部分中展示 jQuery 本身的变化一样。
jQuery Mobile 有什么新特性?
自从这本书的前一版以来,jQuery Mobile 已经成熟了很多。API 已经标准化,添加了新的小部件,整体开发人员体验与 jQuery 和 jQuery UI 更加一致。为了反映这种成熟,我完全重写了第四部分,使其与本书的其余部分保持一致。还有更多的示例、参考表和特定功能的演示。
还有什么新鲜的?
从第十二章开始,我使用模板从数据中生成 HTML 元素。这是一项重要的技术,我经常使用。我在以前版本中使用的库已经到了它的生命的尽头,我已经选择了一个替代品。新的库没有直接集成到 jQuery 中,所以在第十二章中,我提供了一个自定义插件,使得使用我选择的模板库更容易与 jQuery 一起使用。第十二章之后的所有例子都被修改以使用新的库。
我改变了用于测试移动应用的工具集,更喜欢使用基于云的测试服务,而不是维护自己的模拟器。我在第二十七章中解释了我这样做的原因。
有很多例子吗?
有个载荷的例子。jQuery 的一个优点是几乎任何任务都可以用几种不同的方式执行,这允许您开发个人的 jQuery 风格。为了展示您可以采用的不同方法,我包含了许多不同的示例——事实上,数量如此之多,以至于我在某些章节中只包含了您正在使用的完整 HTML 文档一次,以便包含所有内容。每章的第一个例子是一个完整的 HTML 文档,如清单 1-1 所示。
清单 1-1 。完整的示例文档
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<link rel="stylesheet" type="text/css" href="styles.css"/>
<script src="jquery-2.0.2.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$("img:odd").mouseenter(function (e) {
$(this).css("opacity", 0.5);
}).mouseout(function (e) {
$(this).css("opacity", 1.0);
});
});
</script>
</head>
<body>
<h1>Jacqui's Flower Shop</h1>
<form method="post">
<div id="oblock">
<div class="dtable">
<div id="row1" class="drow">
<div class="dcell">
<img src="aster.png"/><label for="aster">Aster:</label>
<input name="aster" value="0" required>
</div>
<div class="dcell">
<img src="daffodil.png"/><label for="daffodil">Daffodil:</label>
<input name="daffodil" value="0" required >
</div>
<div class="dcell">
<img src="rose.png"/><label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
</div>
<div id="row2" class="drow">
<div class="dcell">
<img src="peony.png"/><label for="peony">Peony:</label>
<input name="peony" value="0" required>
</div>
<div class="dcell">
<img src="primula.png"/><label for="primula">Primula:</label>
<input name="primula" value="0" required>
</div>
<div class="dcell">
<img src="snowdrop.png"/><label for="snowdrop">Snowdrop:</label>
<input name="snowdrop" value="0" required>
</div>
</div>
</div>
</div>
<div id="buttonDiv"><button type="submit">Place Order</button></div>
</form>
</body>
</html>
该列表摘自第五章。不要担心它做什么;请注意,每章的第一个例子是一个完整的 HTML 文档,类似于清单 1-1 中所示。几乎所有的例子都基于相同的基本 HTML 文档,显示了一个简单的花店。这不是最激动人心的例子,但它是独立的,包含了我们在使用 jQuery 时感兴趣的所有内容。
对于第二个和随后的示例,我只向您展示发生变化的元素。这通常只是script
元素,也就是 jQuery 代码所在的位置。您可以发现部分清单,因为它以省略号(...
)开始和结束,如清单 1-2 所示。
清单 1-2 。部分列表
...
<script type="text/javascript">
jQuery(document).ready(function () {
jQuery("img:odd").mouseenter(function(e) {
jQuery(this).css("opacity", 0.5);
}).mouseout(function(e) {
jQuery(this).css("opacity", 1.0);
});
});
</script>
...
清单 1-2 是第五章中的后续清单。您可以看到只出现了script
元素,我突出显示了一些语句。这就是我如何将您的注意力吸引到示例中展示我正在使用的 jQuery 特性的部分。在这样的部分清单中,只有我显示的元素与本章开始时显示的完整文档有所不同。
我将本书中的例子非常集中在个人特征上。这是为了让您更好地了解 jQuery 的运行方式。但是在这样做的时候,你可能看不到不同的特性是如何组合在一起的,所以在本书的每一部分的结尾,都有一个简短的章节,在这个章节中,我重构了示例文档,将前面章节中的所有主题合并在一起,并给出了一个可能的联合视图。
从哪里可以获得示例代码?
你可以在 Apress 网站的源代码/下载区(www.apress.com
)下载本书所有章节的所有例子。下载是免费的,它包括重新创建示例所需的所有支持资源,而不必输入它们(包括图像、JavaScript 库和 CSS 样式表)。您不必下载代码,但这是试验示例和将技术剪切并粘贴到您自己的项目中的最简单的方法。
提示尽管我只列出了章节中许多代码清单的变化,但是源代码下载中的每个例子都是一个完整的 HTML 文档,您可以直接将其加载到浏览器中。
这本书我需要什么软件?
为了遵循本书中的示例,您将需要各种软件,如以下部分所述。
获取 jQuery
您首先需要的是 jQuery 库,它可以从http://jquery.com
获得。在网站的首页有一个下载按钮和一个选择生产或开发版本的选项,如图 1-1 所示。
图 1-1 。下载 jQuery 库
您需要下载本书第 1-4 和第六部分的 jQuery 2.x 和第五部分的 jQuery 1.x。您将使用这本书的开发版本。我将在第五章中解释这些版本之间的区别,并向您展示如何建立 jQuery 库。
提示我在第十七章和第二十七章分别告诉你如何获取和安装 jQuery UI 和 jQuery Mobile 库。
获取 HTML 编辑器
web 开发最重要的工具之一是编辑器,您可以用它来创建 HTML 文档。HTML 只是文本,所以你可以使用一个非常基本的编辑器,但是有一些专用的包可以使开发更加流畅和简单,其中许多都是免费的。
当我写这本书的第一版时,我使用了活动状态下的 Komodo Edit。它是免费的;很简单;它对 HTML、JavaScript 和 jQuery 有很好的支持;还有 Windows、Mac 和 Linux 版本。详见http://activestate.com
。
不过最近换了微软的 Visual Studio。我的许多书都是关于微软的网络堆栈,我在 Windows 上写代码。Visual Studio 的最新版本对 HTML 编辑提供了出色的支持,可以在不依赖 Microsoft web stack 的情况下使用。我为这本书使用了 Visual Studio 2012 Express,这是免费提供的—参见http://www.microsoft.com/visualstudio
。(也有付费版本——毕竟这是微软的——但是 jQuery 开发不需要额外的特性。)
作为替代,JsFiddle 是一个流行的在线编辑器,它支持使用 jQuery。我并不喜欢它(它的结构与我的开发习惯相冲突),但是它看起来确实非常灵活和强大。它是免费使用的,可在http://jsfiddle.net
获得。
注我推荐这本书里的几款产品,但只是因为它们是我使用和喜欢的产品。除了出版我所有书籍的出版公司 Apress 之外,我与 Active State、微软或任何其他公司都没有任何关系。我为我使用的每一个网络服务和开发工具支付全价;我没有得到任何特殊的支持或秘密访问开发团队,我收到的唯一的钱来自版税(我非常感谢您的购买——谢谢)。
获得网络浏览器
您需要一个 web 浏览器来查看 HTML 文档并测试 jQuery 和 JavaScript 代码。我喜欢谷歌浏览器:我发现它很快,我喜欢简单的用户界面,开发者工具也相当不错。每当你在这本书里看到一个截图(这是经常发生的),你看到的都会是谷歌 Chrome。
也就是说,你不必使用和我一样的浏览器,但是我建议你选择一个有好的开发工具的。Mozilla Firefox 通过 Firebug 扩展提供了一些优秀的 JavaScript 工具,您可以在http://getfirebug.com
获得。
如果你不喜欢 Chrome 或 Firefox,那么你的下一个最佳选择是 Internet Explorer。很多网络程序员在道德上反对 IE,但版本 10 非常好,当 Chrome 以一种意想不到的方式运行时,我经常用它来快速检查是否正常。
获得网络服务器
如果您想重新创建本书中的示例,您将需要一个 web 服务器,以便浏览器有地方加载示例 HTML 文档和相关资源(如图像和 JavaScript 文件)。很多 web 服务器都是可用的,而且大部分都是开源和免费的。你使用哪个网络服务器并不重要。我在本书中使用了微软的互联网信息服务(IIS ),但这仅仅是因为我已经安装了一台 Windows 服务器并准备就绪。
获取 Node.js
从第三部分开始,除了常规的 web 服务器之外,您还将使用Node.js
。Node.js
目前非常流行,但我使用它的原因很简单,它是基于 JavaScript 的,所以你不必处理一个单独的 web 应用框架。你不会深入了解关于Node.js
的任何细节,我会把它当作一个黑盒(尽管我会向你展示服务器脚本,如果你感兴趣的话,你可以看看服务器上发生了什么)。
可以从http://nodejs.org
下载Node.js
。有一个预编译的 Windows 二进制文件和源代码,您可以为其他平台构建。在这本书里,我使用的是 0.10.13 版本,在你读到这本书的时候,这个版本很可能已经被取代了,但是服务器脚本应该还能正常工作,没有任何问题。
设置和测试 Node.js
测试Node.js
最简单的方法是使用一个简单的脚本。将清单 1-3 中的内容保存到一个名为NodeTest.js
的文件中。我在与我的Node.js
二进制文件相同的目录下完成了这个操作。
清单 1-3 。Node.js 测试脚本
var http = require('http');
var url = require('url');
http.createServer(function (req, res) {
console.log("Request: " + req.method + " to " + req.url);
res.writeHead(200, "OK");
res.write("<h1>Hello</h1>Node.js is working");
res.end();
}).listen(80);
console.log("Ready on port 80");
这是一个简单的测试脚本,当它接收到一个 HTTP GET
请求时返回一个 HTML 片段。
提示如果最后一句话没有完全说明白,不要担心。使用 jQuery 不需要知道 HTTP 和 web 服务器是如何工作的,我在第二章的中提供了一个 HTML 速成班。
要测试Node.js
,运行二进制文件,将刚刚创建的文件指定为参数。对于我的 Windows 安装,我在控制台提示符下键入了以下内容:
node NodeTest.js
为了确保一切正常,导航到运行Node.js
的机器上的端口 80。您应该会看到与图 1-2 非常相似的东西,表明一切都在预期之中。
图 1-2 。测试 Node.js
我在不同于普通 web 服务器的机器上运行Node.js
,这意味着使用端口 80 不会给我带来任何问题。如果您只有一台机器可用,那么在端口 80 上运行 web 服务器,并将Node.js
脚本更改为使用另一个端口。我在清单 1-3 中突出显示了测试脚本中指定使用哪个端口的部分。
图像属性
在本书中,我在例子中使用了一组图像。感谢以下人员善意地允许使用他们的照片:霍里亚·瓦兰、大卫·肖特、盖沙博伊 500 、田中久约、梅尔维·埃斯凯利宁、花式速度女王、艾伦“克雷吉 3000 、克雷吉、诺索古德和梅拉路易丝。
摘要
在这一章中,我概述了这本书的内容和结构,并列出 jQuery web 开发所需的软件,所有这些都可以免费获得。接下来的三章将更新你在 HTML、CSS 和 JavaScript 方面的基本技能。如果你熟悉这些主题,那么跳到第五章,我将在那里介绍 jQuery。
二、 HTML 优先
在本书中,我们将花大量的时间处理 HTML 文档。在这一章中,我列出了你需要的信息来理解我们在本书后面要做的事情。这不是一个 HTML 教程,而是我在后面章节所依赖的 HTML 关键特性的总结。
HTML 的最新版本被称为 HTML5 ,它本身就是一个话题。HTML5 有 100 多个元素,每个元素都有自己的用途和功能。也就是说,你只需要 HTML 的基础知识就可以理解 jQuery 是如何工作的,但是如果你想了解 HTML 的细节,那么我推荐我的另一本书:HTML 5权威指南,也是由 Apress 出版的。
介绍基本的 HTML 文档
最好的起点是查看 HTML 文档。从这样的文档中,你可以看到所有 HTML 文档遵循的基本结构和层次。清单 2-1 显示了一个简单的 HTML 文档。我在这一章中使用这份文档来介绍 HTML 的核心概念。
清单 2-1 。一个简单的 HTML 文档
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<script src="jquery-2.0.2.js" type="text/javascript"></script>
<style>
h1 {
width: 700px; border: thick double black; margin-left: auto;
margin-right: auto; text-align: center; font-size: x-large; padding: .5em;
color: darkgreen; background-image: url("border.png");
background-size: contain; margin-top: 0;
}
.dtable {display: table;}
.drow {display: table-row;}
.dcell {display: table-cell; padding: 10px;}
.dcell > * {vertical-align: middle}
input {width: 2em; text-align: right; border: thin solid black; padding: 2px;}
label {width: 5em; padding-left: .5em;display: inline-block;}
#buttonDiv {text-align: center;}
#oblock {display: block; margin-left: auto; margin-right: auto; width: 700px;}
</style>
</head>
<body>
<h1>Jacqui's Flower Shop</h1>
<form method="post">
<div id="oblock">
<div class="dtable">
<div class="drow">
<div class="dcell">
<img src="aster.png"/><label for="aster">Aster:</label>
<input name="aster" value="0" required>
</div>
<div class="dcell">
<img src="daffodil.png"/><label for="daffodil">Daffodil:</label>
<input name="daffodil" value="0" required >
</div>
<div class="dcell">
<img src="rose.png"/><label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
</div>
<div class="drow">
<div class="dcell">
<img src="peony.png"/><label for="peony">Peony:</label>
<input name="peony" value="0" required>
</div>
<div class="dcell">
<img src="primula.png"/><label for="primula">Primula:</label>
<input name="primula" value="0" required>
</div>
<div class="dcell">
<img src="snowdrop.png"/><label for="snowdrop">Snowdrop:</label>
<input name="snowdrop" value="0" required>
</div>
</div>
</div>
</div>
<div id="buttonDiv"><button type="submit">Place Order</button></div>
</form>
</body>
</html>
这是一个简短的基本 HTML 文档,但是它包含了一些与 HTML 相关的最重要的特征。你可以在图 2-1 中看到该文档如何出现在浏览器中。
图 2-1 。在浏览器中显示 HTML 文档示例
理解 HTML 元素的结构
HTML 的核心是元素,它告诉浏览器 HTML 文档的每个部分代表什么样的内容。以下是示例中的一个元素:
...
<h1>Jacqui's Flower Shop</h1>
...
这个元素有三个部分:开始标签,结束标签,内容,如图图 2-2 所示。
图 2-2 。简单 HTML 元素的剖析
这个元素的名称(也称为标签名称或者仅仅是标签)是h1
,它告诉浏览器标签之间的内容应该被当作一个顶级头。您可以通过将标签名称放在尖括号、<
和>
字符中来创建开始标签。除了在左尖括号(<
)后面添加一个/
字符之外,您可以用类似的方式创建结束标记。
了解属性
您可以通过向元素添加属性来为浏览器提供附加信息。 清单 2-2 显示了示例文档中一个带有属性的元素。
清单 2-2 。定义属性
...
<label for="aster">Aster:</label>
...
这是一个label
元素,它定义了一个名为for
的属性。我强调了属性,以便更容易看到。属性总是被定义为开始标记的一部分。这个属性有一个 名称和一个 值。名字是for
,数值是aster
。并非所有属性都需要值;仅仅定义它们就向浏览器发送了一个信号,表明您需要与该元素相关联的某种行为。清单 2-3 显示了一个具有这种属性的元素的例子。
清单 2-3 。定义不需要值的属性
...
<input name="snowdrop" value="0" required>
...
这个元素有三个属性。前两个值name
和value
被赋值。(这可能会有点混乱。这些属性的名字是name
和value
。name
属性的值是snowdrop
,value
属性的值是0
。)第三个属性正好是required
这个词。这是一个不需要值的属性的例子,尽管您可以通过将属性值设置为其名称(required="required"
)或使用空字符串(required=""
)来定义一个值。
id 和类属性
在这本书里有两个属性特别重要:属性的id
和class
。使用 jQuery 需要执行的最常见的任务之一是在文档中定位一个或多个元素,以便对它们执行某种操作。id
和class
属性对于在 HTML 文档中定位一个或多个元素非常有用。
使用 id 属性
使用id
属性为文档中的元素定义一个惟一的标识符。对于id
属性,不允许两个元素具有相同的值。清单 2-4 显示了一个使用了id
属性的简单 HTML 文档。
清单 2-4 。使用 id 属性
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
</head>
<body>
<h1 id="mainheader">Welcome to Jacqui's Flower Shop</h1>
<h2 id="openinghours">We are open 10am-6pm, 7 days a week</h2>
<h3 id="holidays">(closed on national holidays)</h3>
</body>
</html>
我已经在文档中的三个元素上定义了id
属性。h1
元素的id
值为mainheader
,h2
元素的id
值为openinghours
,h3
元素的id
值为holidays
。使用id
值可以让您在文档中找到特定的元素。
使用类属性
属性任意地将元素关联在一起。许多元素可以被分配到同一个类,元素可以属于多个类,如清单 2-5 所示。
清单 2-5 。使用 class 属性
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
</head>
<body>
<h1 id="mainheader" class="header">Welcome to Jacqui's Flower Shop</h1>
<h2 class="header info">We are open 10am-6pm, 7 days a week</h2>
<h3 class="info">(closed on national holidays)</h3>
</body>
</html>
在清单 2-5 中,h1
元素属于header
类,h2
元素属于header
和info
类,h3
元素属于info
类。如您所见,您可以将一个元素添加到多个类中,只需用空格分隔类名。
了解元素内容
元素可以包含文本,但也可以包含其他元素。以下是包含其他元素的元素的示例:
...
<div class="dcell">
<img src="rose.png"/>
<label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
...
div
元素包含另外三个元素:一个img
、label
和一个input
元素。您可以定义多个层次的 嵌套元素,而不仅仅是这里显示的一个层次。像这样嵌套元素是 HTML 中的一个关键概念,因为它将外部元素的重要性传递给了内部元素(这是我稍后要讨论的主题)。您可以混合文本内容和其他元素,如下所示:
...
<div class="dcell">
Here is some text content
<img src="rose.png"/>
Here is some more text!
<input name="rose" value="0" required>
</div>
...
了解无效元素
HTML 规范包括可能不包含内容的元素。这些被称为 void 或自闭元素,它们没有单独的结束标签。以下是 void 元素的示例:
...
<img src="rose.png"/>
...
在单个标记中定义了一个 void 元素,并在最后一个尖括号(>
字符)前添加了一个/
字符。严格来说,最后一个属性的最后一个字符和/
字符之间应该有一个空格,如下:
...
<img src="rose.png" />
...
然而,浏览器在解释 HTML 时是宽容的,您可以省略空格字符。当元素引用外部资源时,通常使用 Void 元素。在这种情况下,img
元素用于链接到名为rose.png
的外部图像文件。
了解文档结构
有一些关键元素定义了任何 HTML 文档的基本结构:DOCTYPE
、html
、head
和body
元素。清单 2-6 显示了这些元素之间的关系,删除了其余的内容。
清单 2-6 。HTML 文档的基本结构
<!DOCTYPE html>
<html>
<head>
...*head content*...
</head>
<body>
...*body content*...
</body>
</html>
这些元素中的每一个在 HTML 文档中都扮演着特定的角色。DOCTYPE
元素告诉浏览器这是一个 HTML 文档,更确切地说,这是一个 HTML5 文档。早期版本的 HTML 需要额外的信息。例如,下面是 HTML4 文档的DOCTYPE
元素:
...
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
...
html
元素表示包含 HTML 内容的文档区域。这个元素总是包含另外两个关键的结构元素:head
和body
。正如我在本章开始时所说的,我不打算讨论单个的 HTML 元素。它们太多了,描述 HTML5 完全花了我 HTML5 书 1000 多页。也就是说,我将提供我使用的元素的简要描述,以便您对文档的功能有一个好的了解。表 2-1 总结了来自清单 2-1 的示例文档中使用的元素,其中一些我将在本章稍后部分详细描述。
表 2-1 。示例文档中使用的 HTML 元素
元素 | 描述 |
---|---|
DOCTYPE | 指示文档中内容的类型 |
body | 表示包含内容元素的文档区域(在“理解内容元素”一节中描述) |
button | 表示一个按钮;通常用于向服务器提交一个表单 |
div | 通用元素;通常用于为文档添加结构,以用于演示目的 |
form | 表示一个 HTML 表单,它允许您从用户那里收集数据,并将它们发送到服务器进行处理 |
h1 | 降级标题 |
head | 表示文档中包含元数据的区域(在“了解元数据元素”一节中描述) |
html | 表示文档中包含 HTML 的区域(通常是整个文档) |
img | 降级图像 |
input | 表示用于从用户处收集单个数据项的输入字段,通常作为 HTML 表单的一部分 |
script | 表示将作为文档的一部分执行的脚本,通常是 JavaScript |
style | 表示 CSS 设置的区域;参见第三章 |
title | 表示文档的标题;由浏览器用来设置用于显示文档内容的窗口或选项卡的标题 |
了解元数据元素
head
元素包含文档的元数据——换句话说,一个或多个描述或操作文档内容的元素,但不直接由浏览器显示。示例文档在head
部分包含三个元数据元素:title
、script
和style
。title
元素是最基本的,这个元素的内容被浏览器用来设置窗口或标签的标题,所有的 HTML 文档都需要有一个title
元素。其他两个元素对本书来说更重要,我将在接下来的章节中解释。
理解脚本元素
script
元素允许您在代码中包含 JavaScript。一旦我开始深入介绍 jQuery,您就会经常看到这个元素。示例文档包含一个script
元素,如清单 2-7 所示。
清单 2-7 。示例文档中的脚本元素
...
<script src="jquery-2.0.2.js" type="text/javascript"></script>
...
当您为script
元素定义src
属性时,您是在告诉浏览器您想要加载包含在另一个文件中的 JavaScript。在这种情况下,这是主 jQuery 库,浏览器将在文件jquery-2.0.2.js
中找到它。一个 HTML 文档可以包含不止一个script
元素,如果你愿意,可以在开始和结束标签之间包含 JavaScript 代码,如清单 2-8 所示。
清单 2-8 。使用 script 元素定义内联 JavaScript 代码
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<script src="jquery-2.0.2.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#mainheader').css("color", "red");
});
</script>
</head>
<body>
<h1 id="mainheader" class="header">Welcome to Jacqui's Flower Shop</h1>
<h2 class="header info">We are open 10am-6pm, 7 days a week</h2>
<h3 class="info">(closed on national holidays)</h3>
</body>
</html>
这个例子有两个script
元素。第一个是将 jQuery 库导入到文档中,第二个是使用一些基本 jQuery 功能的简单脚本。暂时不要担心第二个脚本会做什么。我将在第五章开始适当地进入 jQuery。在 HTML 文档中,script
元素可以出现在head
或body
元素中。在本书中,我倾向于将脚本只放在head
元素中,但这只是个人偏好的问题。
提示script
元素的顺序很重要。您必须先导入 jQuery 库,然后才能使用它的特性。
了解样式元素
style
元素是将级联样式表(CSS)属性引入文档的一种方式。简而言之,您可以使用 CSS 来管理文档在浏览器中显示给用户时的呈现方式。清单 2-9 显示了示例文档中的style
元素及其内容。
清单 2-9 。使用样式元素
...
<style>
h1 {
width: 700px; border: thick double black; margin-left: auto;
margin-right: auto; text-align: center; font-size: x-large; padding: .5em;
color: darkgreen; background-image: url("border.png");
background-size: contain; margin-top: 0;
}
.dtable {display: table;}
.drow {display: table-row;}
.dcell {display: table-cell; padding: 10px;}
.dcell > * {vertical-align: middle}
input {width: 2em; text-align: right; border: thin solid black; padding: 2px;}
label {width: 5em; padding-left: .5em;display: inline-block;}
#buttonDiv {text-align: center;}
#oblock {display: block; margin-left: auto; margin-right: auto; width: 700px;}
</style>
...
浏览器维护一组属性,这些属性的值用于控制每个元素的外观。style
元素允许您选择元素并更改一个或多个属性的值。我会在第三章中更详细地讨论这个问题。
与script
元素一样,style
元素也可以出现在head
和body
元素中,但是在本书中,你会发现我只将它们放在了head
部分,就像示例文档中一样。这又是个人喜好问题;我喜欢把我的风格和我的内容分开。
理解内容元素
元素包含了 HTML 文档中的内容。这些是浏览器将向用户显示的元素,元数据元素,如script
和style
,将对这些元素进行操作。
理解语义/表示差异
HTML5 的主要变化之一是哲学上的:元素的语义意义和元素对内容表示的影响之间的分离。这是一个明智的想法。您使用 HTML 元素为内容提供结构和含义,然后通过对元素应用 CSS 样式来控制内容的表示。并不是每一个 HTML 文档的消费者都需要显示它们(例如,因为 HTML 的一些消费者是自动化程序而不是浏览器),并且保持表示独立使得 HTML 更容易处理和自动提取含义。
这个概念是 HTML 的核心。您应用元素来表示您正在处理的内容类型。人们善于根据上下文推断意义。例如,你马上就明白了这一部分的标题从属于前面的标题,因为它是用较小的字体印刷的(也因为这是你在你读过的大多数非小说类书籍中看到的一种模式)。
计算机也不能推断任何地方的上下文,因此,每个 HTML 元素都有特定的含义。例如,article
元素表示适合于联合的自包含内容,h1
元素表示内容部分的标题。清单 2-10 显示了一个使用元素赋予结构和意义的示例文档。
清单 2-10 。使用 HTML 元素为内容添加结构和意义
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
</head>
<body>
<article>
<header>
<hgroup>
<h1>New Delivery Service</h1>
<h2>Color and Beauty to Your Door</h2>
</hgroup>
</header>
<section>
We are pleased to announce that we are starting a home delivery service for
your flower needs. We will deliver within a 20 mile radius of the store
for free and $1/mile thereafter. All flowers are satisfaction-guaranteed and
we offer free phone-based consultation.
</section>
<section>
Our new service starts on <b>Wednesday</b> and there is a $10 discount
for the first 50 customers.
</section>
<footer>
<nav>
More Information:
<a href="http://jacquisflowershop.com">Learn More About Fruit</a>
</nav>
</footer>
</article>
</body>
</html>
关于何时应用section
或article
元素,没有硬性规定,但我建议你在内容中始终如一地应用它们。像section
和article
这样的元素不向浏览器提供任何关于它们包含的内容应该如何显示的信息。这是语义/表示分歧的核心。对于大多数 HTML 元素,浏览器有一个样式约定,它决定了如果不使用 CSS 改变演示文稿,它们将如何显示,但其思想是您将自由地使用 CSS 来创建您的文档所需的演示文稿。这是你可以用style
元素做的事情,jQuery 在script
元素中很容易做到。
HTML4 中存在的一些元素是在没有将表示和意义分开的概念时创建的,这将我们置于一个奇怪的境地。这种奇怪现象的一个例子是b
元素。在 HTML5 之前,b
元素指示浏览器将开始和结束标签包含的内容显示为粗体文本。在 HTML5 中,元素不仅仅是表示性的,因此b
元素的定义被修改如下:
b
元素表示从其周围内容偏移的一段文本,没有传达任何额外的强调或重要性,并且传统的印刷呈现是粗体文本;例如,文档摘要中的关键字,或者评论中的产品名称。
—HTML:标记语言,w3c.org
这是一种冗长的说法,即b
元素告诉浏览器将文本加粗。b
元素没有语义意义;这是所有关于介绍。这个含糊其辞的定义告诉了我们一些关于 HTML5 的重要事情:我们正处于一个过渡时期。我们希望元素和它们的表示完全分离,但现实是我们也希望保持与无数使用早期 HTML 版本编写的文档的兼容性,所以我们不得不妥协。
理解表单和输入
示例文档主体中最有趣的元素之一是form
元素。这是一种可以用来从用户那里收集数据的机制,这样就可以将数据发送到服务器。正如您将在第三部分中看到的,jQuery 对处理表单有很好的支持,包括直接在核心库中和在一些常用的插件中。清单 2-11 显示了示例文档中的body
元素及其内容,其中包括form
元素。
清单 2-11 。示例文档的内容元素
...
<body>
<h1>Jacqui's Flower Shop</h1>
<form method="post">
<div id="oblock">
<div class="dtable">
<div class="drow">
<div class="dcell">
<img src="aster.png"/><label for="aster">Aster:</label>
<input name="aster" value="0" required>
</div>
<div class="dcell">
<img src="daffodil.png"/><label for="daffodil">Daffodil:</label>
<input name="daffodil" value="0" required >
</div>
<div class="dcell">
<img src="rose.png"/><label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
</div>
<div class="drow">
<div class="dcell">
<img src="peony.png"/><label for="peony">Peony:</label>
<input name="peony" value="0" required>
</div>
<div class="dcell">
<img src="primula.png"/><label for="primula">Primula:</label>
<input name="primula" value="0" required>
</div>
<div class="dcell">
<img src="snowdrop.png"/><label for="snowdrop">Snowdrop:</label>
<input name="snowdrop" value="0" required>
</div>
</div>
</div>
</div>
<div id="buttonDiv"><button type="submit">Place Order</button></div>
</form>
</body>
...
当有一个form
元素时,通常可以在附近找到input
元素。这是您用来从用户那里获取特定信息的元素。清单 2-12 展示了一个来自文档的input
元素的例子。
清单 2-12 。使用输入元素
...
<input name="snowdrop" value="0" required>
...
这个input
元素从用户那里收集一个名为snowdrop
的数据项的值,它的初始值为零。required
属性告诉浏览器,除非用户为这个数据项提供了一个值,否则不能将表单发送到服务器。这是 HTML5 中的一个新特性,叫做表单验证 ,但是坦率地说,使用 jQuery 可以实现更好的验证,正如我在第三部分中演示的那样。
与表单密切相关的是button
元素,它通常用于向服务器提交表单(也可以用于将表单重置为初始状态)。清单 2-13 显示了我在示例文档中定义的button
元素。
清单 2-13 。使用按钮元素
...
<button type="submit">Place Order</button>
...
将type
属性设置为submit
告诉浏览器当按钮被按下时我希望表单被提交。button
元素的内容显示在浏览器的按钮控件内,如图 2-3 所示。
图 2-3 。使用按钮元素的内容
了解结构元素
您会注意到在example
文档的主体中有许多div
元素。这是一个没有特定语义意义的元素,通常只是用来控制内容的布局。在示例文档的情况下,我使用div
元素创建一个表布局,这样div
元素包含的元素就在一个网格中呈现给用户。布局通过包含在style
元素中的一些 CSS 应用于div
元素。我将在整本书中使用 CSS,我会在第三章给出一个快速入门。
借助外部资源了解元素
有些元素允许您将外部资源引入文档。一个很好的例子是img
元素,您可以使用它向文档添加图像。在清单 2-1 中的示例文档中,我使用了img
元素来显示出售的不同花卉的图片,如清单 2-14 所示。
清单 2-14 。使用 img 元素引用外部图像
...
<img src="snowdrop.png"/>
...
src
属性用于指定图像。我用过图片snowdrop.png
。这是一个相对 URL (统一资源定位器)的例子,这意味着浏览器将使用包含该元素的文档的 URL 来计算出我想要的图像的 URL。
相对 URL 的替代方法是一个绝对 URL (也称为完全限定 URL )。这是一个定义了所有基本组件的 URL,如图 2-4 所示。(我已经在图 2-4 中包括了端口,但是如果省略,那么浏览器将使用与方案相关的默认端口。对于http
方案,这是端口80
。)
图 2-4 。URL 的基本结构
为每一个你想要的资源输入完全合格的 URL 是令人厌烦的,这就是为什么相对 URL 如此有用。当我为img
元素的src
属性指定一个值snowdrop.png
时,我告诉浏览器它可以在获取包含img
元素的文档的相同位置找到图像。表 2-2 显示了你可以使用的不同种类的相对 URL 和从它们创建的绝对 URL。这些都假设文档是从http://www.jacquisflowershop.com/jquery/example.html
加载的。
表 2-2 。相对 URL 格式
相对 URL | 等于 |
---|---|
snowdrop.png | http://www.jacquisflowershop.com/jquery/snowdrop.png |
/snowdrop.png | http://www.jacquisflowershop.com/snowdrop.png |
/ | http://www.jacquisflowershop.com/jquery/ |
//www.mydomain.com/index.html | http://www.mydomain.com/index.html |
表中的最后一个例子很少使用,因为它没有节省太多的输入,但是它可以用来确保使用与检索 HTML 文档相同的方案来请求资源。这避免了通过加密连接请求某些内容(使用https
方案)和通过未加密连接请求其他内容(使用http
方案)的问题。一些浏览器,尤其是 Internet Explorer 和 Google Chrome,不喜欢混合安全和不安全的内容,并且会在出现这种情况时警告用户。
注意您可以使用两个句点(..
)相对于 web 服务器上包含主 HTML 文档的目录进行导航。我建议避免使用这种技术,尤其是因为作为一种安全预防措施,许多 web 服务器会拒绝包含这些字符的请求。
了解元素层次结构
HTML 文档中的元素形成了一个自然的层次结构。html
元素包含body
元素,后者包含内容元素,每个内容元素可以无限地包含其他元素*。*
*当您想要导航文档时,理解这种层次结构是很重要的,无论是使用 CSS 应用样式(我在第三章中描述了这一点)还是使用 jQuery 在文档中查找元素(我将在第二部分中解释)。
层次结构中最重要的部分是元素之间的关系。为了帮助我描述这些关系,我在图 2-5 中描述了花店示例文档中一些元素的层次结构。
图 2-5 。文档层次结构的一部分
图 2-5 只显示了文档中元素层次结构的一部分,所以你可以看到关系直接对应于一个元素可以包含另一个元素的方式。有各种各样的关系,如以下部分所述。
了解父子关系
例如,当一个元素包含另一个元素时,就存在父子关系。form
元素是图中body
元素的子。相反,body
元素是form
元素的父元素。一个元素可以有多个子元素,但只能有一个父元素。在图 2-5 中,body
元素有两个子元素(form
和h1
元素),并且是它们的父元素。
父子关系仅存在于元素和直接包含在其中的元素之间。例如,div
元素是form
元素的子元素,但它们不是body
元素的子元素。
孩子关系有一些变化。第一个子元素是文档中首先定义的子元素。例如,h1
元素是body
元素的第一个子元素。最后一个子元素是文档中定义的最后一个子元素。form
元素是body
元素的最后一个子元素。也可以参考nth-child
,从第一个子元素开始,开始计数子元素,直到到达n
(从1
开始计数)。
理解祖孙关系
一个元素的后代是它的子元素,子元素的子元素,依此类推。事实上,任何直接或间接包含的元素都是后代。例如,body
元素的后代是h1
、form
和两个div
元素,图 2-5 中显示的所有元素都是html
元素的后代。
相反的关系是祖先,它们是元素的父元素、父元素的父元素等等。例如,对于form
元素,后代是body
和html
元素。两个div
元素有相同的祖先集:form
、body
和html
元素。
了解兄弟姐妹关系
兄弟元素是共享一个公共父元素的元素。在图 2-5 中,h1
和form
元素是兄弟元素,因为它们共享body
元素作为它们的父元素。当与兄弟姐妹一起工作时,我们倾向于参考下一个兄弟姐妹和上一个兄弟姐妹。这些是在当前元素之前和之后定义的兄弟元素。并非所有元素都有上一个和下一个同级元素;第一个和最后一个子元素只有一个。
理解文档对象模型
当浏览器加载并处理一个 HTML 文档时,它会创建文档对象模型 (DOM)。DOM 是一种模型,其中 JavaScript 对象用于表示文档中的每个元素,DOM 是一种机制,通过它可以以编程方式处理 HTML 文档的内容。
注意原则上,DOM 可以用于浏览器想要实现的任何编程语言。实际上,JavaScript 主导着主流浏览器,所以我不打算区分作为抽象概念的 DOM 和作为相关 JavaScript 对象集合的 DOM。
您应该关心我在上一节中描述的元素之间的关系的原因之一是它们保存在 DOM 中。因此,您可以使用 JavaScript 遍历对象网络,以了解所表示的文档的性质和结构。
提示使用 DOM 意味着使用 JavaScript。如果你需要复习 JavaScript 语言的基础知识,请参见第四章。
在本章的这一部分,我将展示 DOM 的一些基本特性。在本书的其余部分,我将重点介绍如何使用 jQuery 访问 DOM,但是在这一节中,我将向您展示一些内置的支持,部分是为了强调 jQuery 方法可以更加优雅。
使用 DOM
为 DOM 中所有类型的元素定义基本功能的 JavaScript 对象称为HTMLElement
。HTMLElement
对象定义了所有 HTML 元素类型共有的属性和方法,包括表 2-3 中显示的属性。
表 2-3 。基本 html 元素属性
财产 | 描述 | 返回 |
---|---|---|
className | 获取或设置元素所属的类的列表 | string |
id | 获取或设置 id 属性的值 | string |
lang | 获取或设置 lang 属性的值 | string |
tagName | 返回标记名(指示元素类型) | string |
还有更多的属性可用。确切的设置取决于您正在使用的 HTML 版本。但是这四点足以让我演示 DOM 的基本工作方式。
DOM 使用从HTMLElement
派生的对象来表示每个元素类型的独特特征。例如, HTMLImageElement
对象用于表示 DOM 中的img
元素,该对象定义了src
属性,对应于img
元素的src
属性。我不打算详细讨论特定于元素的对象,但是作为一个规则,您可以依赖于与元素属性相对应的可用属性。
您通过全局document
变量访问 DOM,该变量返回一个Document
对象。Document
对象代表浏览器正在显示的 HTML 文档,并定义了一些允许你在 DOM 中定位对象的方法,如表 2-4 所述。
表 2-4 。记录查找元素的方法
财产 | 描述 | 返回 |
---|---|---|
getElementById(<id>) | 返回具有指定的 id 值的元素 | HTMLElement |
getElementsByClassName(<class>) | 返回具有指定的类值的元素 | HTMLElement[] |
getElementsByTagName(<tag>) | 返回指定类型的元素 | HTMLElement[] |
querySelector(<selector>) | 返回与指定 CSS 选择器匹配的第一个元素 | HTMLElement |
querySelectorAll(<selector>) | 返回与指定 CSS 选择器匹配的所有元素 | HTMLElement[] |
再说一次,我只是挑选对本书有用的方法。表格中描述的最后两种方法使用了 CSS 选择器,我在第三章中描述过。清单 2-15 展示了如何使用Document
对象在文档中搜索特定类型的元素。
清单 2-15 。在 DOM 中搜索元素
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<script src="jquery-2.0.2.js" type="text/javascript"></script>
<style>
h1 {
width: 700px; border: thick double black; margin-left: auto;
margin-right: auto; text-align: center; font-size: x-large; padding: .5em;
color: darkgreen; background-image: url("border.png");
background-size: contain; margin-top: 0;
}
.dtable {display: table;}
.drow {display: table-row;}
.dcell {display: table-cell; padding: 10px;}
.dcell > * {vertical-align: middle}
input {width: 2em; text-align: right; border: thin solid black; padding: 2px;}
label {width: 5em; padding-left: .5em;display: inline-block;}
#buttonDiv {text-align: center;}
#oblock {display: block; margin-left: auto; margin-right: auto; width: 700px;}
</style>
</head>
<body>
<h1>Jacqui's Flower Shop</h1>
<form method="post">
<div id="oblock">
<div class="dtable">
<div class="drow">
<div class="dcell">
<img src="aster.png"/><label for="aster">Aster:</label>
<input name="aster" value="0" required>
</div>
<div class="dcell">
<img src="daffodil.png"/><label for="daffodil">Daffodil:</label>
<input name="daffodil" value="0" required >
</div>
<div class="dcell">
<img src="rose.png"/><label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
</div>
<div class="drow">
<div class="dcell">
<img src="peony.png"/><label for="peony">Peony:</label>
<input name="peony" value="0" required>
</div>
<div class="dcell">
<img src="primula.png"/><label for="primula">Primula:</label>
<input name="primula" value="0" required>
</div>
<div class="dcell">
<img src="snowdrop.png"/><label for="snowdrop">Snowdrop:</label>
<input name="snowdrop" value="0" required>
</div>
</div>
</div>
</div>
<div id="buttonDiv"><button type="submit">Place Order</button></div>
</form>
<script>
var elements = document.getElementsByTagName("img");
for (var i = 0; i < elements.length; i++) {
console.log("Element: " + elements[i].tagName + " " + elements[i].src);
}
</script>
</body>
</html>
在清单 2-15 中,我在body
元素的末尾添加了一个script
元素。当浏览器在文档中找到一个script
元素时,它们会在文档的其余部分被加载和处理之前,立即执行 JavaScript 语句。当您使用 DOM 时,这会带来一个问题,因为这意味着您通过Document
对象对元素的搜索是在您感兴趣的对象在模型中被创建之前执行的。为了避免这种情况,我将script
元素放在了文档的末尾。正如我在第二部分中解释的那样,jQuery 提供了一种处理这个问题的好方法。
在这个脚本中,我使用了getElementsByTagName
方法来查找文档中所有的 img
元素。该方法返回一个对象数组,我枚举该数组以将每个对象的tagName
和src
属性值打印到控制台。写入控制台的输出如下:
Element: IMG http://www.jacquisflowershop.com/jquery/aster.png
Element: IMG http://www.jacquisflowershop.com/jquery/daffodil.png
Element: IMG http://www.jacquisflowershop.com/jquery/rose.png
Element: IMG http://www.jacquisflowershop.com/jquery/peony.png
Element: IMG http://www.jacquisflowershop.com/jquery/primula.png
Element: IMG http://www.jacquisflowershop.com/jquery/snowdrop.png
修改 DOM
DOM 中的对象是活动的*,这意味着改变 DOM 对象属性的值会影响浏览器显示的文档。清单 2-16 显示了一个具有这种效果的脚本。(我只是在这里显示了script
元素,以减少重复。文档的其余部分与清单 2-15 中的相同。)*
*清单 2-16 。修改 DOM 对象属性
...
<script>
var elements = document.getElementsByTagName("img");
for (var i = 0; i < elements.length; i++) {
elements[i].src = "snowdrop.png";
}
</script>
...
在这个脚本中,我将所有img
元素的src
属性值设置为snowdrop.png
。你可以在图 2-6 中看到效果。
图 2-6 。使用 DOM 修改 HTML 文档
修改样式
您可以使用 DOM 来更改 CSS 属性的值。(第三章如果你需要的话提供了 CSS 的入门。)DOM API 对 CSS 的支持是全面的,但最简单的技术是使用由HTMLElement
对象定义的style
属性。由style
属性返回的对象定义了与 CSS 属性相对应的属性(我意识到这句话里有很多属性,对此我深表歉意)。
CSS 和style
返回的对象定义的属性命名方案略有不同。例如,background-color
CSS 属性变成了style.backgroundColor
对象属性。清单 2-17 展示了使用 DOM 来管理样式。
清单 2-17 。使用 DOM 修改元素样式
...
<script>
var elements = document.getElementsByTagName("img");
for (var i = 0; i < elements.length; i++) {
if (i > 0) {
elements[i].style.opacity = 0.5;
}
}
</script>
...
在这个脚本中,我更改了文档中除第一个img
元素之外的所有元素的opacity
属性值。我保留了一个元素不变,所以你可以看到图 2-7 中的不同。
图 2-7 。使用 JavaScript 更改 CSS 属性值
处理事件
事件是浏览器发送的信号,指示 DOM 中一个或多个元素的状态变化。有一系列事件来表示不同种类的状态变化。例如,当用户单击文档中的元素时会触发click
事件,当用户提交表单时会触发submit
元素。很多事件是有关联的。例如,当用户将鼠标移动到一个元素上时会触发mouseover
事件,当用户再次将鼠标移出时会触发mouseout
事件。您可以通过将 JavaScript 处理函数与 DOM 元素的事件相关联来响应事件。每次触发事件时,都会执行处理函数中的语句。清单 2-18 给出了一个例子。
清单 2-18 。处理事件
...
<script>
var elements = document.getElementsByTagName("img");
for (var i = 0; i < elements.length; i++) {
elements[i].onmouseover = handleMouseOver;
elements[i].onmouseout = handleMouseOut;
}
function handleMouseOver(e) {
e.target.style.opacity = 0.5;
}
function handleMouseOut(e) {
e.target.style.opacity = 1;
}
</script>
...
这个脚本定义了两个处理函数,我将它们指定为img
DOM 对象上的 onmouseover
和onmouseout
属性的值。这个脚本的效果是,当鼠标在图像上时,图像变得部分透明,当鼠标退出时,图像恢复正常。我不打算深入探讨 DOM API 事件处理机制,因为 jQuery 对事件的支持是第二部分的主题。然而,我确实想看看传递给事件处理函数的对象:Event
对象。表 2-5 显示了Event
对象中最重要的成员。
表 2-5 。事件对象的功能和属性
名字 | 描述 | 返回 |
---|---|---|
type | 事件的名称(即鼠标悬停 | string |
target | 事件的目标元素 | HTMLElement |
currentTarget | 当前正在调用其事件侦听器的元素 | HTMLElement |
eventPhase | 事件生命周期中的阶段 | number |
bubbles | 如果事件将在文档中冒泡,则返回true;否则返回假 | boolean |
cancelable | 如果事件有可以取消的默认动作,则返回true;否则返回假 | boolean |
stopPropagation() | 触发当前元素的事件侦听器后,停止事件在元素树中的流动 | void |
stopImmediatePropagation() | 立即停止事件在元素树中的流动;当前元素的未触发事件侦听器将被忽略 | void |
preventDefault() | 阻止浏览器执行与事件关联的默认操作 | void |
defaultPrevented | 如果调用了 preventDefault() ,则返回 true | boolean |
在前面的例子中,我使用了target
属性来获取触发事件的元素。其他一些成员与事件流和默认动作相关,我将在下一节简要解释。这一章我只是在打基础。
了解事件流程
一个事件的生命周期有三个阶段:捕获、目标和冒泡。当事件被触发时,浏览器识别与事件相关的元素,该元素被称为事件的目标。浏览器识别body
元素和目标之间的所有元素,并检查它们中的每一个,以查看它们是否有任何事件处理程序请求被通知它们后代的事件。浏览器在触发目标本身上的处理程序之前触发任何这样的处理程序。(我将在第二部分向您展示如何请求后代事件的通知。)
一旦捕获阶段完成,您就进入到目标阶段,,这是三个阶段中最简单的。当捕获阶段完成时,浏览器触发已经添加到目标元素的事件类型的任何侦听器。
一旦目标阶段完成,浏览器就开始沿着祖先元素链向上返回到 body 元素。在每个元素中,浏览器检查是否有事件类型的侦听器不支持捕获(我将在第二部分解释如何实现)。并非所有事件都支持冒泡。您可以使用bubbles
属性查看事件是否会冒泡。值true
表示事件会冒泡,false
表示不会。
了解默认操作
一些事件定义了触发事件时将执行的默认操作。例如,a
元素上的click
事件的默认动作是浏览器将在href
属性中指定的 URL 处加载内容。当一个事件有一个默认动作时,它的cancelable
属性的值将是true
。您可以通过调用preventDefault
方法来停止默认动作的执行。注意,调用preventDefault
函数不会停止事件在捕获、目标和冒泡阶段的流动。这些阶段仍将执行,但浏览器不会在冒泡阶段结束时执行默认操作。您可以通过读取defaultPrevented
属性来测试查看preventDefault
函数是否被早期的事件处理程序调用过。如果它返回true
,那么preventDefault
函数已经被调用。
摘要
在这一章中,我带你游览了 HTML,尽管没有详细描述 100 多个元素中的任何一个。我向您展示了如何创建和构造一个基本的 HTML 文档,元素如何包含文本内容和其他元素的混合,以及这如何导致具有特定关系类型的元素层次结构。我还向您展示了 DOM API 的基本用法以及它如何处理元素选择和事件——正如您将在本书中看到的,使用 jQuery 的一个主要原因是因为它隐藏了 DOM API 的细节,并使处理 HTML 元素和表示它们的 JavaScript 对象变得简单而容易。在第三章中,我提供了一个级联样式表的快速入门,它用于控制 HTML 元素的呈现。**
三、CSS 优先
级联样式表(CSS)是控制 HTML 元素外观(更恰当的说法是表示)的手段。CSS 对 jQuery 有着特殊的意义,原因有二。首先,你可以使用 CSS 选择器(我在本章中描述了它)告诉 jQuery 如何在 HTML 文档中查找元素。第二个原因是 jQuery 最常见的任务之一是改变应用于元素的 CSS 样式。
有超过 130 个 CSS 属性,每个属性控制一个元素表现的一个方面。与 HTML 元素一样,CSS 属性太多了,我无法在本书中描述它们。相反,我关注的是 CSS 如何工作以及如何将样式应用于元素。如果你想详细了解 CSS,那么我推荐我的另一本书:html 5权威指南,也是由 Apress 出版的。
CSS 入门
当浏览器在屏幕上显示一个元素时,它使用一组称为 CSS 属性 的属性来决定元素应该如何呈现。清单 3-1 显示了一个简单的 HTML 文档。
清单 3-1 。一个简单的 HTML 文档
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
</head>
<body>
<h1>New Delivery Service</h1>
<h2>Color and Beauty to Your Door</h2>
<h2>(with special introductory offer)</h2>
<p>We are pleased to announce that we are starting a home delivery service for
your flower needs. We will deliver within a 20 mile radius of the store
for free and $1/mile thereafter.</p>
</body>
</html>
你可以在图 3-1 中看到浏览器是如何显示文档的。
图 3-1 。在浏览器中显示简单文档
CSS 属性有很多*——太多了,本书无法详细介绍——但是你可以通过查看表 3-1 中的少量属性来了解 CSS 是如何工作的。*
*表 3-1 。一些 CSS 属性
财产 | 描述 |
---|---|
color | 设置元素的前景色(通常设置文本的颜色) |
background-color | 设置元素的背景色 |
font-size | 设置元素中包含的文本所使用的字体大小 |
border | 设置元素的边框 |
我没有为这些 CSS 属性定义值,但是浏览器仍然能够显示内容,如图 3-1 所示,每个内容元素都以不同的方式呈现。即使您没有为 CSS 属性提供值,浏览器仍然必须显示元素,因此每个元素都有一个样式约定——当 HTML 文档中没有设置其他值时,它使用 CSS 属性的默认值。HTML 规范定义了元素的样式约定,但是浏览器可以随意改变它们,这就是为什么你会看到,比如说,Google Chrome 和 Internet Explorer 之间样式约定的变化。表 3-2 显示了 Google Chrome 为表 3-1 中所列的属性 I 使用的默认值。
表 3-2 。一些 CSS 属性及其样式约定值
从表中可以看出,所有三种类型的元素的color
、background-color
和border
属性的值都相同,只有font-size
属性发生了变化。在这一章的后面,我将描述这些属性值所使用的单位——但是现在,我们将把重点放在设置属性值上,而不用担心这些值用什么单位来表示。
设置内联值
为 CSS 属性设置值的最直接的方法是将style
属性应用于我们想要改变其表示的元素。清单 3-2 展示了这是如何做到的。
清单 3-2 。使用样式属性设置元素的 CSS 属性
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
</head>
<body>
<h1>New Delivery Service</h1>
<h2 style="background-color: grey; color: white">Color and Beauty to Your Door</h2>
<h2>(with special introductory offer)</h2>
<p>We are pleased to announce that we are starting a home delivery service for
your flower needs. We will deliver within a 20 mile radius of the store
for free and $1/mile thereafter.</p>
</body>
</html>
在清单 3-2 中,我使用了样式声明来指定两个 CSS 属性的值。你可以在图 3-2 中看到属性值的剖析。
图 3-2 。样式属性值的剖析
每个样式声明指定要更改的属性的名称和要使用的值,用冒号(:
)分隔。您可以使用分号(;
)将多个声明放在一起。在图 3-2 中,我将background-color
的值设置为grey
,将color
属性的值设置为white
。这些值在h2
元素的style
属性中指定,并且只影响该元素(文档中的其他元素不受影响,即使它们也是h2
元素)。在图 3-3 的中,您可以看到这些新属性值对第一个h2
元素的影响。
图 3-3 。更改 h2 元素的 style 属性中 CSS 值的效果
定义嵌入样式
使用style
属性很简单,但是它只适用于单个元素。您可以对想要更改的每个元素使用style
属性,但是很快就会变得难以管理并且容易出错,尤其是如果您需要在以后进行修改的话。一个更强大的技术是使用style
元素(而不是style
属性)来定义一个嵌入样式,并指示浏览器使用选择器来应用它。清单 3-3 显示了一种嵌入式风格。
清单 3-3 。定义嵌入样式
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
h2 { background-color: grey; color: white;}
</style>
</head>
<body>
<h1>New Delivery Service</h1>
<h2>Color and Beauty to Your Door</h2>
<h2>(with special introductory offer)</h2>
<p>We are pleased to announce that we are starting a home delivery service for
your flower needs. We will deliver within a 20 mile radius of the store
for free and $1/mile thereafter.</p>
</body>
</html>
我们仍然在嵌入式风格中使用声明,但是它们被括在大括号中({
和}
字符),并且在它们前面有一个选择器。你可以在图 3-4 中看到嵌入式风格的剖析。
图 3-4 。嵌入式风格的剖析
提示我把style
元素放在了head
元素中,但是我也可以把它放在body
元素中。我更喜欢对样式使用head
元素,因为我喜欢将内容从控制外观的 CSS 中分离出来的想法。
CSS 选择器在 jQuery 中很重要,因为它们是选择元素并对其执行操作的基础。我在示例中使用的选择器是h2
,这意味着大括号中包含的样式声明应该应用于文档中的每个h2
元素。你可以在图 3-5 的中看到这对h2
元素的影响。
图 3-5 。嵌入样式的效果
您可以使用一个style
元素来包含多个嵌入样式。清单 3-4 显示了您在第二章中第一次看到的花店文档,它有一组更复杂的样式。
清单 3-4 。HTML 文档中一组更复杂的样式
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<script src="jquery-2.0.2.js" type="text/javascript"></script>
<style>
h1 {
width: 700px; border: thick double black; margin-left: auto;
margin-right: auto; text-align: center; font-size: x-large; padding: .5em;
color: darkgreen; background-image: url("border.png");
background-size: contain; margin-top: 0;
}
.dtable {display: table;}
.drow {display: table-row;}
.dcell {display: table-cell; padding: 10px;}
.dcell > * {vertical-align: middle}
input {width: 2em; text-align: right; border: thin solid black; padding: 2px;}
label {width: 5em; padding-left: .5em;display: inline-block;}
#buttonDiv {text-align: center;}
#oblock {display: block; margin-left: auto; margin-right: auto; width: 700px;}
</style>
</head>
<body>
<h1>Jacqui's Flower Shop</h1>
<form method="post">
<div id="oblock">
<div class="dtable">
<div class="drow">
<div class="dcell">
<img src="aster.png"/><label for="aster">Aster:</label>
<input name="aster" value="0" required>
</div>
<div class="dcell">
<img src="daffodil.png"/><label for="daffodil">Daffodil:</label>
<input name="daffodil" value="0" required>
</div>
<div class="dcell">
<img src="rose.png"/><label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
</div>
<div class="drow">
<div class="dcell">
<img src="peony.png"/><label for="peony">Peony:</label>
<input name="peony" value="0" required>
</div>
<div class="dcell">
<img src="primula.png"/><label for="primula">Primula:</label>
<input name="primula" value="0" required>
</div>
<div class="dcell">
<img src="snowdrop.png"/><label for="snowdrop">Snowdrop:</label>
<input name="snowdrop" value="0" required>
</div>
</div>
</div>
</div>
<div id="buttonDiv"><button type="submit">Place Order</button></div>
</form>
</body>
</html>
清单 3-4 中的style
元素包含几个嵌入样式,其中一些,尤其是带有h1
选择器的元素,定义了许多属性的值。
定义外部样式表
您可以创建一个单独的样式表,而不是在每个 HTML 文档中定义相同的样式集。这是一个独立的文件,带有传统的.css
文件扩展名,你可以将你的风格放入其中。清单 3-5 显示了文件styles.css
的内容,我已经将花店文档中的样式放入其中。
清单 3-5 。styles.css 文件
h1 {
min-width: 700px; border: thick double black; margin-left: auto;
margin-right: auto; text-align: center; font-size: x-large; padding: .5em;
color: darkgreen; background-image: url("border.png");
background-size: contain; margin-top: 0;
}
.dtable {display: table;}
.drow {display: table-row;}
.dcell {display: table-cell; padding: 10px;}
.dcell > * {vertical-align: middle}
input {width: 2em; text-align: right; border: thin solid black; padding: 2px;}
label {width: 5em; padding-left: .5em;display: inline-block;}
#buttonDiv {text-align: center;}
#oblock {display: block; margin-left: auto; margin-right: auto; min-width: 700px;}
你不需要在样式表中使用style
元素。您只需直接定义选择器和声明。然后使用link
元素将样式带入文档,如清单 3-6 所示。
清单 3-6 。导入外部样式表
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<script src="jquery-2.0.2.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="styles.css" />
</head>
<body>
<h1>Jacqui's Flower Shop</h1>
<form method="post">
<div id="oblock">
<div class="dtable">
<div class="drow">
<div class="dcell">
<img src="aster.png"/><label for="aster">Aster:</label>
<input name="aster" value="0" required>
</div>
<div class="dcell">
<img src="daffodil.png"/><label for="daffodil">Daffodil:</label>
<input name="daffodil" value="0" required>
</div>
<div class="dcell">
<img src="rose.png"/><label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
</div>
<div class="drow">
<div class="dcell">
<img src="peony.png"/><label for="peony">Peony:</label>
<input name="peony" value="0" required>
</div>
<div class="dcell">
<img src="primula.png"/><label for="primula">Primula:</label>
<input name="primula" value="0" required>
</div>
<div class="dcell">
<img src="snowdrop.png"/><label for="snowdrop">Snowdrop:</label>
<input name="snowdrop" value="0" required>
</div>
</div>
</div>
</div>
<div id="buttonDiv"><button type="submit">Place Order</button></div>
</form>
</body>
</html>
您可以根据需要链接到任意多个样式表,每个link
元素引用一个样式表。如果用同一个选择器定义两个样式,导入样式表的顺序很重要。最后加载的将是应用的那个。
了解 CSS 选择器
注意在花店样式表中有不同种类的选择器:一些是元素名称(比如h1
和input
),一些以句点开头(比如.dtable
和.row
),还有一些以英镑开头(#butonDiv
和#oblock
)。如果你特别细心,你会注意到其中一个选择器有多个组件:.dcell > *
。每个 CSS 选择器选择文档中的元素,不同种类的选择器告诉浏览器以不同的方式寻找元素。在本节中,我描述了 CSS 定义的不同种类的选择器,从核心选择器 开始,表 3-3 总结了这些选择器。
表 3-3 。核心选择器
选择器 | 描述 |
---|---|
* | 选择所有元素 |
<type> | 选择指定类型的元素 |
.<class> | 选择特定类的元素(不考虑元素类型) |
<type>.<class> | 选择属于指定类成员的指定类型的元素 |
#<id> | 为 id 属性选择具有指定值的元素 |
这些选择器是使用最广泛的(例如,它们涵盖了我在示例文档中定义的大多数样式)。
按属性选择
虽然基本的选择器作用于id
和class
属性(我在第二章中描述过),但是也有选择器可以让你处理任何属性。表 3-4 对它们进行了描述。
表 3-4 。属性选择器
选择器 | 描述 |
---|---|
[attr] | 选择定义属性 attr 的元素,而不考虑分配给该属性的值 |
[attr="val"] | 选择定义属性并且该属性的值为值的元素 |
[attr^="val"] | 选择定义属性的元素,其属性值以字符串 val 开始 |
[attr$="val"] | 选择定义属性并且其属性值以字符串 val 结尾的元素 |
[attr*="val"] | 选择定义属性并且其属性值包含字符串 val 的元素 |
[attr∼="val"] | 选择定义属性并且其属性值包含多个值的元素,其中一个值为值 |
[attr|="val"] | 选择定义属性的元素,其值是用连字符分隔的值列表,第一个是值 |
清单 3-7 显示了一个简单的嵌入样式的文档,它的选择器是基于属性的。
清单 3-7 。使用属性选择器
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
[lang] { background-color: grey; color: white;}
[lang="es"] {font-size: 14px;}
</style>
</head>
<body>
<h1 lang="en">New Delivery Service</h1>
<h2 lang="en">Color and Beauty to Your Door</h2>
<h2 lang="es">(Color y belleza a tu puerta)</h2>
<p>We are pleased to announce that we are starting a home delivery service for
your flower needs. We will deliver within a 20 mile radius of the store
for free and $1/mile thereafter.</p>
</body>
</html>
第一个选择器匹配任何具有lang
属性的元素,第二个选择器匹配任何lang
属性值为es
的元素。你可以在图 3-6 中看到这些风格的效果。
图 3-6 。使用属性选择器应用样式
注意这个图有一些重要的地方需要注意。看看h2
元素是如何受到嵌入样式的和的影响的。第一种样式应用于所有具有lang
属性的元素。第二种样式应用于所有具有值为es
的lang
属性的元素。文档中的第二个h2
元素满足这两个条件,因此background-color
、color
和font-size
属性的值都被更改。我将在“理解样式级联”一节中详细解释这是如何工作的
按关系选择
在第二章的中,我解释了元素(以及在 DOM 中表示它们的对象)有一个层次结构,它产生了不同种类的关系。有 CSS 选择器允许你根据那些关系选择元素,如表 3-5 所述。
表 3-5 。关系选择器
选择器 | 描述 |
---|---|
<selector> <selector> | 选择与第二个选择器匹配并且是第一个选择器匹配的元素的后代的元素 |
<selector> > <selector> | 选择与第二个选择器匹配的元素,以及与第一个选择器匹配的元素的子元素 |
<selector> + <selector> | 选择与第二个选择器匹配并且是与第一个选择器匹配的元素的下一个同级元素 |
<selector> ∼ <selector> | 选择与第二个选择器匹配的元素,并且这些元素是与第一个选择器匹配的元素的同级元素(并且出现在第一个选择器之后) |
我在花店示例文档中使用了其中一个选择器,如下所示:
.dcell > * {vertical-align: middle}
这个选择器匹配所有属于dcell
类的元素的子元素,声明将vertical-align
属性设置为值middle
。清单 3-8 展示了其他一些正在使用的关系选择器。
清单 3-8 。使用关系选择器
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
h1 ∼ [lang] { background-color: grey; color: white;}
h1 + [lang] {font-size: 12px;}
</style>
</head>
<body>
<h1 lang="en">New Delivery Service</h1>
<h2 lang="en">Color and Beauty to Your Door</h2>
<h2 lang="es">(Color y belleza a tu puerta)</h2>
<p>We are pleased to announce that we are starting a home delivery service for
your flower needs. We will deliver within a 20 mile radius of the store
for free and $1/mile thereafter.</p>
</body>
</html>
我已经使用了清单 3-8 中的两个兄弟选择器。第一个选择器使用波浪号(∼
)字符,匹配任何具有lang
属性的元素,该属性在h1
元素之后定义,并且是其同级元素。在示例文档中,这意味着两个h2
元素都被选中(因为它们具有属性,是h1
元素的兄弟元素,并且是在h2
元素之后定义的)。第二个选择器,使用加号字符的那个,是相似的,但是只匹配一个h1
元素的直接兄弟。这意味着只选择了第一个h2
元素。在图 3-7 中可以看到效果。
图 3-7 。使用兄弟关系选择器
使用伪元素和伪类选择器进行选择
CSS 支持一组伪元素和伪类选择器。这些提供了方便的功能,并不直接对应于文档中的元素或类成员。表 3-6 描述了这些选择器。
表 3-6 。伪选择器
选择器 | 描述 |
---|---|
:active | 选择用户当前激活的元素;这通常是指当鼠标按钮被按下时指针下的那些元素 |
:checked | 选择处于选中状态的元素 |
:default | 选择默认元素 |
:disabled | 选择处于禁用状态的元素 |
:empty | 选择不包含子元素的元素 |
:enabled | 选择处于启用状态的元素 |
:first-child | 选择作为其父元素的第一个子元素的元素 |
:first-letter | 选择文本块的第一个字母 |
:first-line | 选择文本块的第一行 |
:focus | 选择具有焦点的元素 |
:hover | 选择占据屏幕上鼠标指针下方位置的元素 |
:in-range :out-of-range | 选择指定范围内或范围外的受约束的输入元素 |
:lang(<language>) | 基于 lang 属性的值选择元素 |
:last-child | 选择作为其父元素的最后一个子元素的元素 |
:link | 选择链接元素 |
:nth-child(n) | 选择其父元素的第 n 个子元素 |
:nth-last-child(n) | 选择从其父元素的最后一个子元素开始第 n 个元素 |
:nth-last-of-type(n) | 选择从其父元素定义的类型的最后一个子元素开始的第 n 个元素 |
:nth-of-type(n) | 选择属于其父元素定义的类型的第 n 个子元素 |
:only-child | 选择由其父元素定义的唯一元素 |
:only-of-type | 选择由其父元素定义的类型的唯一元素 |
:required :optional | 基于必需的属性的存在,选择输入元素 |
:root | 选择文档中的根元素 |
:target | 选择由 URL 片段标识符引用的元素 |
:valid :invalid | 根据表单中的输入验证选择有效或无效的输入元素 |
:visited | 选择用户已经访问过的链接元素 |
清单 3-9 展示了一些伪选择器的使用。
清单 3-9 。使用伪选择器
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
:nth-of-type(2) { background-color: grey; color: white;}
p:first-letter {font-size: 40px;}
</style>
</head>
<body>
<h1 lang="en">New Delivery Service</h1>
<h2 lang="en">Color and Beauty to Your Door</h2>
<h2 lang="es">(Color y belleza a tu puerta)</h2>
<p>We are pleased to announce that we are starting a home delivery service for
your flower needs. We will deliver within a 20 mile radius of the store
for free and $1/mile thereafter.</p>
</body>
</html>
您可以单独使用伪选择器,或者作为另一个选择器的修饰符。我已经在清单 3-9 中展示了这两种方法。第一个选择器匹配任何属于其父元素定义的类型的第二个元素。第二个选择器匹配任何p
元素的第一个字母。你可以在图 3-8 中看到这些风格的应用。
图 3-8 。使用伪选择器来应用样式
联合和否定选择器
通过将选择器排列在一起,可以获得额外的灵活性。具体来说,您可以通过合并选择和通过否定反转选择来创建联合。这两种方法在表 3-7 中均有描述。
表 3-7 。灵活安排选择器
选择器 | 描述 |
---|---|
<selector>, <selector> | 选择第一个选择器匹配的元素和第二个选择器匹配的元素的并集 |
:not(<selector>) | 选择与指定选择器不匹配的元素 |
清单 3-10 展示了如何创建并集和反集。
清单 3-10 。使用选择器联合和求反
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
h1, h2 { background-color: grey; color: white;}
:not(html):not(body):not(:first-child) {border: medium double black;}
</style>
</head>
<body>
<h1 lang="en">New Delivery Service</h1>
<h2 lang="en">Color and Beauty to Your Door</h2>
<p>We are pleased to announce that we are starting a home delivery service for
your flower needs. We will deliver within a 20 mile radius of the store
for free and $1/mile thereafter.</p>
</body>
</html>
清单 3-10 中的第一个选择器是h1
和h2
选择器的联合。正如您所想象的,这匹配文档中的所有h1
和h2
元素。第二个选择器有点深奥。我想演示如何使用伪选择器作为其他伪选择器的修饰符,包括否定。
...
:not(html):not(body):not(:first-child) {border: medium double black;}
...
该选择器匹配任何不是html
元素、不是body
元素并且不是其父元素的第一个子元素的元素。你可以在图 3-9 中看到这个例子中的样式是如何应用的。
图 3-9 。创建选择器联合和否定
了解样式层叠
理解样式表的关键是理解它们如何级联和继承。HTML 文档中的 CSS 属性可能有多个来源,而层叠和继承是浏览器确定应该使用哪些值来显示元素的方法。您已经看到了定义样式的三种不同方式(内嵌、嵌入和来自外部样式表),但是还有另外两种样式来源:浏览器样式和用户样式。
如果没有指定其他样式,浏览器样式 (更确切地说是用户代理样式)是浏览器应用于元素的样式约定。你在本章开始时看到了一个使用样式约定的例子。
此外,大多数浏览器允许用户定义自己的样式表。这些样式表包含的样式被称为用户样式 。这不是一个广泛使用的特性,但是那些定义自己的样式表的用户通常非常重视能够这样做,尤其是因为它提供了一种使页面更易访问的方法。
每个浏览器都有自己的用户风格机制。例如,Windows 上的谷歌 Chrome 在用户的个人资料目录中创建了一个名为User StyleSheets\Custom.css
的文件。添加到这个文件中的任何样式都将应用到用户访问的任何站点上,服从我在下一节中描述的级联规则。
了解样式如何级联
现在您已经看到了浏览器必须考虑的所有样式来源,您可以看看浏览器在显示元素时查找属性值的顺序。
- 内联样式(使用元素上的
style
属性定义的样式) - 嵌入样式(在
style
元素中定义的样式) - 外部样式(使用
link
元素导入的样式) - 用户样式(由用户定义的样式)
- 浏览器样式(浏览器应用的样式约定)
假设浏览器需要显示一个p
元素。它需要知道应该使用什么颜色来显示文本,这意味着它需要为 CSS color
属性找到一个值。首先,它将检查试图显示的元素是否有定义了color
值的内联样式,如下所示:
...
<pstyle="color: red">We are pleased to announce that we are starting a home delivery
service for your flower needs. We will deliver within a 20 mile radius of the store
for free and $1/mile thereafter.</p>
...
如果没有内联样式,那么浏览器将查找包含应用于该元素的样式的style
元素,如下所示:
...
<style>
p {color: red};
</style>
...
如果没有这样的style
元素,浏览器会查看通过link
元素加载的样式表,依此类推,直到浏览器为color
属性找到一个值,这意味着如果没有其他值可用,就使用默认浏览器样式中定义的值。
提示前三种属性来源(内嵌样式、嵌入样式和样式表)统称为作者样式。用户样式表中定义的样式称为用户样式,浏览器定义的样式称为浏览器样式。
调整重要样式的顺序
您可以通过将属性值标记为重要 来覆盖正常的层叠顺序,如清单 3-11 中的所示。
清单 3-11 。将样式属性标记为重要
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
p {color: black !important; }
</style>
</head>
<body>
<h1 lang="en">New Delivery Service</h1>
<h2 lang="en">Color and Beauty to Your Door</h2>
<pstyle="color: red">We are pleased to announce that we are starting a home delivery
service for your flower needs. We will deliver within a 20 mile radius of the store
for free and $1/mile thereafter.</p>
</body>
</html>
通过将!important
追加到声明中,可以将单个值标记为重要。浏览器优先选择重要的样式,而不管它们是在哪里定义的。您可以在图 3-10 中看到属性重要性的影响,其中color
属性的嵌入值覆盖了内嵌值(这在打印页面上可能有点难以辨认,但是所有的文本都是黑色的)。
图 3-10 。重要属性值覆盖内联属性值
提示唯一优先于您定义的重要值的是在用户样式表中定义的重要值。对于常规值,作者样式在用户样式之前使用,但是在处理重要值时,情况正好相反。
特异性和顺序评估平分秋色
如果有两种样式可以应用于在同一级联级别定义的元素,并且它们都包含浏览器正在寻找的 CSS 属性值,那么我们就进入了平局决胜的情况。为了决定使用哪个值,浏览器评估每种风格的特异性,并选择最具体的一个。浏览器通过计算三种不同的特征来确定一种风格的特殊性。
- 样式选择器中的
id
值的数量 - 选择器中其他属性和伪类的数量
- 选择器中元素名称和伪元素的数量
浏览器会组合每个评估的值,并应用最具体的样式的属性值。你可以在清单 3-12 中看到一个简单的特异性例子。
清单 3-12 。风格的特殊性
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
p {background-color: grey; color: white;}
p.details {color:red;}
</style>
</head>
<body>
<h1 lang="en">New Delivery Service</h1>
<h2 lang="en">Color and Beauty to Your Door</h2>
<p class="details">We are pleased to announce that we are starting a home delivery
service for your flower needs. We will deliver within a 20 mile radius of the store
for free and $1/mile thereafter.</p>
</body>
</html>
在评估特异性时,您以a
- b
- c
的形式创建一个数字,其中每个字母都是所统计的三个特征之一的总和。这不是三位数。如果样式的a
值最大,则样式更具体。只有当a
值相等时,浏览器才会比较b
值。在这种情况下,b
值越大的样式越特殊。只有当a
和b
值相同时,浏览器才会考虑c
值。这意味着1
- 0
- 0
的特异性分数比0
- 5
- 5
的特异性分数更高。
在这种情况下,选择器p.details
包含一个class
属性,这意味着样式的特异性是0
- 1
- 1
( 0
id 值+ 1
其他属性+ 1
元素名称)。另一个选择器的特异性为0
- 0
- 1
(不包含id
值或其他属性,只有一个元素名)。
当呈现一个p
元素时,浏览器将为color
属性寻找一个值。如果p
元素是details
类的成员,那么带有p.details
选择器的样式将是最具体的,并且将使用red
的值。对于所有其他p
元素,将使用值white
。在图 3-11 中,您可以看到浏览器如何选择和应用该示例的值。
图 3-11 。基于特定性应用样式中的值
当样式中定义了具有相同特性的值时,浏览器会根据定义值的顺序选择它所使用的值。最后定义的是将要使用的。清单 3-13 显示了一个包含两种相同特定样式的文档。
清单 3-13 。同样独特的风格
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
p.details {color:red;}
p.information {color: blue;}
</style>
</head>
<body>
<h1 lang="en">New Delivery Service</h1>
<h2 lang="en">Color and Beauty to Your Door</h2>
<p class="details information">We are pleased to announce that we are starting a home
Delivery service for your flower needs. We will deliver within a 20 mile radius of
the store for free and $1/mile thereafter.</p>
</body>
</html>
在style
元素中定义的两种样式具有相同的特异性分数,并且都适用于p
元素。当浏览器在页面中显示p
元素时,它将为color
属性选择blue
属性,因为这是后一种样式中定义的值。你可以在图 3-12 中看到这一点。
图 3-12 。根据定义样式的顺序选择属性值
提示这些特异性规则仅适用于在同一层级定义的样式。例如,这意味着在style
属性中定义的属性总是优先于在style
元素中定义的样式。
了解 CSS 单位
在本章的前面,我向你展示了浏览器默认使用的 CSS 属性的值。这些是例子中一些元素的样式约定,我在表 3-8 中复制了这些信息。
表 3-8 。一些 CSS 属性及其值
CSS 定义了一系列不同的单元类型,在接下来的章节中,我将展示一些更常用的单元类型,包括我在本书中使用的单元类型。
使用 CSS 颜色
许多 CSS 属性都使用颜色,包括我在本章中使用的color
和background-color
属性。指定颜色的最简单方法是使用预定义的颜色名称,或者为每个红色、绿色和蓝色分量使用十进制或十六进制值。十进制数值用逗号分隔,十六进制数值通常以#
为前缀,如#ffffff
,代表白色。你可以在表 3-9 中看到一些预定义的颜色名称及其十进制和十六进制的对等物。
表 3-9 。选定的 CSS 颜色
这些被称为基本颜色名称。CSS 还定义了扩展颜色。这里不胜枚举,但你可以在www.w3.org/TR/css3-color
找到完整的列表。除了基本颜色之外,还有许多细微的变化。作为一个例子,表 3-10 显示了可以使用的灰色阴影扩展集。
表 3-10 。选定的 CSS 颜色
颜色名称 | 十六进制 | 小数 |
---|---|---|
darkgrey | #a9a9a9 | 169,169,169 |
darkslategrey | #2f4f4f | 47,79,79 |
dimgrey | #696969 | 105,105,105 |
grey | #808080 | 128,128,128 |
lightgrey | #d3d3d3 | 211,211,211 |
lightslategrey | #778899 | 119,136,153 |
slategrey | #708090 | 112,128,144 |
指定更复杂的颜色
颜色名称和简单的十六进制值不是指定颜色的唯一方式。许多功能允许您选择颜色。表 3-11 描述了每个可用的功能。
表 3-11 。CSS 颜色函数
功能 | 描述 | 例子 |
---|---|---|
rgb(r, g, b) | 使用 RGB(红、绿、蓝)模型指定颜色。 | color: rgb(112, 128, 144) |
rgba(r, g, b, a) | 使用 RGB 模型指定颜色,并添加 alpha 值来指定不透明度。(值为 0 表示完全透明;值为 1 表示完全不透明。) | color: rgba(112, 128, 144, 0.4) |
hsl(h, s, l) | 使用色调、饱和度和亮度(HSL)模型指定颜色。 | color: hsl(120, 100%, 22%) |
hsla(h, s, l, a) | 类似于 HSL,但是增加了一个 alpha 值来指定不透明度。 | color: hsla(120, 100%, 22%, 0.4) |
你可以使用rgba
函数来指定一个透明的颜色,但是如果你想要一个完全透明的元素,那么你可以使用特殊的颜色值transparent
。
了解 CSS 长度
许多 CSS 属性要求您指定一个长度,例如font-size
属性,它用于指定用于呈现元素内容的字体大小。指定长度时,将单位数和单位标识符连接在一起,中间没有任何空格或其他字符。例如,font-size
属性的值20pt
表示由pt
标识符表示的 20 个单位(它们是点,稍后解释)。CSS 定义了两种长度单位:绝对长度单位和相对于另一个属性的长度单位。我将在接下来的章节中解释这两个问题。
使用绝对长度
绝对单位是真实世界的测量值。CSS 支持五种类型的绝对单位,表 3-12 对此进行了描述。
表 3-12 。绝对测量单位
单位标识符 | 描述 |
---|---|
中的 | 英寸 |
厘米 | 厘米 |
毫米 | 毫米 |
pt | 磅(1 磅等于 1/72 英寸) |
pc | 十二点活字(1 点活字等于 12 点) |
您可以在样式中混合和匹配单位,以及混合绝对和相对单位。如果您事先知道内容将如何呈现,例如在设计印刷时,绝对单位会很有用。我在我的 CSS 项目中很少使用绝对单位——我发现相对单位更灵活,更容易维护,我很少创建必须符合现实世界测量的内容。
提示你可能想知道像素在绝对单位表中的位置。事实上,CSS 试图让像素成为一个相对的度量单位,尽管可悲的是,规范在这方面做了拙劣的尝试。您可以在“使用像素”一节中了解更多信息
使用相对长度
相对长度比绝对长度更复杂,需要简洁明了的语言来明确定义它们的含义。相对单位是用其他单位来衡量的。不幸的是,CSS 规范中的语言不够精确(这个问题已经困扰 CSS 多年)。这意味着 CSS 定义了广泛的有趣和有用的相对度量,但你不能使用其中的一些,因为它们没有广泛或一致的浏览器支持。表 3-13 显示了 CSS 定义的、在主流浏览器中可以依赖的相对单位。
表 3-13 。CSS 相对测量单位
单位标识符 | 描述 |
---|---|
全身长的 | 相对于元素的字体大小 |
不包括 | 相对于元素字体的 x 高度 |
雷姆 | 相对于根元素的字体大小 |
像素 | CSS 像素的数量(假设在 96 dpi 的显示器上) |
% | 另一财产价值的百分比 |
当您使用相对单位时,您实际上是指定了另一个度量的倍数。清单 3-14 给出了一个设置与font-size
相关的属性的例子。
清单 3-14 。使用相对单位
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
p.details {
font-size: 15pt;
height: 3em;
border: thin solid black;
}
</style>
</head>
<body>
<h1 lang="en">New Delivery Service</h1>
<h2 lang="en">Color and Beauty to Your Door</h2>
<p class="details information">We are pleased to announce that we are starting a home
delivery service for your flower needs. We will deliver within a 20 mile radius of
the store for free and $1/mile thereafter.</p>
</body>
</html>
在这个例子中,我已经指定了height
属性的值(它设置了一个元素的高度)为3em
,这意味着p
元素应该被渲染,使得元素在屏幕上的高度是font-size
的三倍。你可以在图 3-13 中看到浏览器如何显示这些元素。我添加了一个边框(使用border
属性),这样你可以更容易地看到元素的大小。
图 3-13 。使用相对测量的效果
使用像素
CSS 中的像素可能不是你所期望的。术语像素的通常含义是指显示器上最小的可寻址单元:一个像素。CSS 尝试做一些不同的事情,定义一个像素如下:
参考像素是设备上一个像素的视角,像素密度为 96 dpi,与阅读器的距离为一臂长。
这就是困扰 CSS 的那种模糊定义。我不想咆哮,但是依赖于用户手臂长度的规范是有问题的。幸运的是,主流浏览器忽略了 CSS 定义的像素和显示中的像素之间的差异,并将 1 像素视为 1/96 英寸。(这是标准的 Windows 像素密度;在具有不同像素密度的显示器的平台上的浏览器通常实现一种转换,使得 1 像素仍然是大约 1/96 英寸。)
提示虽然没什么用,但是你可以在www.w3.org/TR/CSS21/syndata.html#length-units
阅读 CSS 像素的完整定义。
这样做的净效果是,尽管 CSS 像素是一个相对的度量单位,但它们被浏览器视为一个绝对的单位。清单 3-15 演示了在 CSS 样式中指定像素。
清单 3-15 。在样式中使用像素单位
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
p.details {
font-size: 20px;
width: 400px;
border: thin solid black;
}
</style>
</head>
<body>
<h1 lang="en">New Delivery Service</h1>
<h2 lang="en">Color and Beauty to Your Door</h2>
<p class="details information">We are pleased to announce that we are starting a home
delivery service for your flower needs. We will deliver within a 20 mile radius of
the store for free and $1/mile thereafter.</p>
</body>
</html>
在清单 3-15 中,我用像素表示了font-size
和width
属性(width
属性是对height
属性的补充,它设置了一个元素的宽度)。你可以在图 3-14 中看到浏览器如何应用这种风格。
图 3-14 。以像素为单位指定单位
提示虽然我经常在 CSS 中使用像素作为单位,但这往往是习惯问题。我发现em
单位更灵活。这是因为只有当我需要改变时,我才需要改变字体的大小,而样式的其他部分可以无缝地工作。重要的是要记住,虽然 CSS 像素是相对单位,但实际上它们是绝对单位,因此可能是不灵活的。
使用百分比
您可以将度量单位表示为另一个属性值的百分比。你可以使用%
(百分比)单位 来完成,如清单 3-16 中的所示。
清单 3-16 。将单位表示为另一个属性值的百分比
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
p.details {
font-size: 200%;
width: 50%;
border: thin solid black;
}
</style>
</head>
<body>
<h1 lang="en">New Delivery Service</h1>
<h2 lang="en">Color and Beauty to Your Door</h2>
<p class="details information">We are pleased to announce that we are starting a home
delivery service for your flower needs. We will deliver within a 20 mile radius of
the store for free and $1/mile thereafter.</p>
</body>
</html>
使用百分比作为单位有两个复杂之处。首先,不是所有的属性都可以用这种方式表示,其次,可以用百分比表示的每个属性分别定义了百分比所指的其他属性。例如,font-size
属性使用从父元素继承的font-size
值,width
属性使用包含元素的width
。
使用速记属性和自定义值
并非所有属性都使用单位和颜色设置。有些人有特殊的价值观,这是他们所控制的那种行为所独有的。一个很好的例子是border
属性,我在一些清单中使用它来绘制元素的边框。您使用三个值来设置border
属性,如下所示:
...
border: thin solid black;
...
第一个值是边框的粗细,第二个值是边框的样式,最后一个值是边框的颜色。表 3-14 显示了可用于指定边框粗细的值。
表 3-14 。边框宽度值
价值 | 描述 |
---|---|
<长度> | 以 CSS 度量单位表示的长度,如 em 、 px 或 cm |
< perc > % | 将围绕其绘制边框的区域的宽度的百分比 |
thin``medium | 预设宽度,其含义由每个浏览器定义,但逐渐变粗 |
表 3-15 显示了可用于边框样式的值。
表 3-15 。边框样式的值
价值 | 描述 |
---|---|
none | 不会绘制任何边框 |
dashed | 边框将是一系列矩形虚线 |
dotted | 边界将是一系列圆点 |
double | 边界将是两条平行线,两条平行线之间有一个间隙 |
groove | 边框看起来会凹陷到页面中 |
inset | 边框将使内容看起来凹陷到页面中 |
outset | 边界将是这样的,内容看起来从页面上升 |
ridge | 边框将从页面上凸起 |
solid | 边界将是一条单一的、完整的线 |
通过将这些表中的值与一种颜色相结合,可以获得各种各样的边框效果。您可以在图 3-15 中看到浏览器中显示的样式范围。
图 3-15 。边框样式
border
属性也是一个很好的简写属性 的例子。这些属性允许您在一个声明中设置几个相关属性的值。这意味着前面所示的border
等价于下面的 12 个声明:
border-top-color: black;
border-top-style: solid;
border-top-width: thin;
border-bottom-color: black;
border-bottom-style: solid;
border-bottom-width: thin;
border-left-color: black;
border-left-style: solid;
border-left-width: thin;
border-right-color: black;
border-right-style: solid;
border-right-width: thin;
CSS 允许您深入细节并设置单个属性进行精细控制,或者在所有相关值都相同时使用简写属性。
摘要
在这一章中,我给了你一个 CSS 的简要概述,向你展示了如何使用style
属性设置属性,如何使用style
元素(包括各种可用的选择器),以及浏览器如何使用层叠和特异性来确定当元素被显示时哪些属性值应该被应用于元素。最后,我浏览了 CSS 单元、自定义值和速记属性。可以用多种不同的方式表达属性值,这为 CSS 样式增加了灵活性(也增加了一点混乱)。
在第四章中,我介绍了 JavaScript 的基础知识,这是定义 jQuery 功能并将其应用于 HTML 内容的方法。*
四、JavaScript 优先
jQuery 是一个 JavaScript 库,可以添加到 HTML 文档中,由浏览器执行。您还可以通过向文档添加自己的代码来利用 jQuery 库的特性——这需要对如何编写 JavaScript 有一个基本的了解。在这一章中,我提供了 JavaScript 语言的初级读本,重点放在与 jQuery 相关的特性上。
JavaScript 作为一种编程语言有着好坏参半的名声。诚然,JavaScript 经历了一段艰难的生活,在它有机会完全成熟之前就匆匆通过了标准化,这给 JavaScript 的工作方式留下了一些奇怪之处。但是大多数对 JavaScript 的抱怨来自开发人员,他们发现 JavaScript 的工作方式与他们首选的后端语言(如 C#、Java 或 Python)并不完全相同。
一旦克服了接受 JavaScript 是一种独立语言的障碍,你将会发现一种灵活的、动态的、令人愉快的语言。当然,仍然有一些奇怪的地方,但是总的体验是积极的,只要稍加努力,你就会发现 JavaScript 是一种富有表现力和有价值的语言。
如果你是编程新手,一个好的起点是发布在流行网站【Lifehacker.com】的一系列文章。不需要任何编程知识,所有的例子都是用 JavaScript 编写的。该指南可从这里获得:http://lifehacker.com/5744113/learn-to-code-the-full-beginners-guide
。
准备使用 JavaScript
JavaScript 代码作为脚本添加到 HTML 文档中——浏览器将执行的 JavaScript 语句块——并且有不同的方式可以添加脚本。您可以定义一个内联脚本 ,其中脚本的内容是 HTML 文档的一部分。您还可以定义一个外部脚本 ,其中 JavaScript 包含在一个单独的文件中,并通过 URL 引用(这就是您访问 jQuery 库的方式,您将在第二部分中看到)。这两种方法都依赖于script
元素。在这一章中,我将使用内联脚本。你可以在清单 4-1 中看到一个简单的例子。
清单 4-1 。一个简单的内联脚本
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
console.log("Hello");
</script>
</head>
<body>
This is a simple example
</body>
</html>
该脚本向控制台写入一条消息。控制台是浏览器提供的一个基本的(但是有用的)工具,可以让你在脚本执行时显示调试信息。每个浏览器都有不同的控制台显示方式。对于谷歌浏览器,你可以从Tools
菜单中选择JavaScript console
。你可以在图 4-1 中看到控制台是如何在 Chrome 中显示的;其他浏览器也有类似的功能。
图 4-1 。谷歌浏览器 JavaScript 控制台
您可以看到控制台窗口中显示了调用console.log
方法的输出,以及消息来源的详细信息(在本例中是在example.html
文件的第 6 行)。这一章,我就不截图了;我将展示一些例子的结果。例如,对于清单 4-1 中的,输出如下:
Hello
我在本章的后面格式化了一些结果,使它们更容易阅读。在接下来的小节中,我将向您展示 JavaScript 语言的核心特性。如果你有过用其他现代语言编程的经验,你会发现 JavaScript 的语法和风格很熟悉——尽管正如我在本章开始时所说的,有些奇怪。
使用语句
基本的 JavaScript 构建块是 语句。每条语句代表一条命令,语句通常以分号(;
)结束。分号是可选的,但是使用分号会使代码更容易阅读,并且允许在一行中有多个语句。清单 4-2 显示了一个脚本中的一对语句,它们是使用一个script
元素定义的。
清单 4-2 。使用 JavaScript 语句
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
console.log("This is a statement");
console.log("This is also a statement");
</script>
</head>
<body>
This is a simple example
</body>
</html>
浏览器依次执行每条语句。在这个例子中,我简单地向控制台写出了一对消息。结果如下:
This is a statement
This is also a statement
定义和使用函数
当浏览器到达一个script
元素时,它会立即一个接一个地执行 JavaScript 语句。你也可以将多条语句打包成一个函数,直到浏览器遇到一条调用该函数的语句才会执行,如清单 4-3 所示。
清单 4-3 。定义 JavaScript 函数
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
function myFunc() {
console.log("This is a statement");
};
myFunc();
</script>
</head>
<body>
This is a simple example
</body>
</html>
一个函数包含的语句用大括号({
和}
)括起来,称为代码块。这个清单定义了一个名为myFunc
的函数,它在代码块中包含一条语句。JavaScript 是一种区分大小写的语言,这意味着关键字function
必须是小写的。在浏览器到达另一个调用myFunc
函数 的语句之前,函数中的语句不会被执行,如下:
myFunc();
在函数中执行语句会产生以下输出:
This is a statement
除了演示函数是如何定义的,这个例子没有什么特别的用处,因为函数在定义后会立即被调用。在第二部分中,您将看到一些更有用的函数示例。
用参数定义函数
与大多数编程语言一样,JavaScript 允许你为函数定义参数,如清单 4-4 所示。
清单 4-4 。用参数定义函数
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
function myFunc(name, weather) {
console.log("Hello " + name + ".");
console.log("It is " + weather + " today");
};
myFunc("Adam", "sunny");
</script>
</head>
<body>
This is a simple example
</body>
</html>
我给myFunc
函数添加了两个参数,称为name
和weather
。JavaScript 是一种动态类型语言,这意味着在定义函数时不必声明参数的数据类型。当我在本章后面讲述 JavaScript 变量时,我会回到动态类型。要调用带参数的函数,需要在调用函数时提供值作为参数,如下所示:
...
myFunc("Adam", "sunny");
...
该清单的结果如下:
Hello Adam.
It is sunny today
当你调用一个函数时,参数的数量不需要与函数中的参数数量相匹配。如果您调用的函数的实参数少于它的形参数,那么您没有为其提供值的任何形参的值都是未定义的。如果调用函数时使用的参数多于实际参数,那么多余的参数将被忽略。
这样做的结果是,您不能创建两个具有相同名称和不同参数的函数,并期望 JavaScript 根据您在调用函数时提供的参数来区分它们。这被称为多态性 ,尽管它在 Java 和 C#等语言中受支持,但在 JavaScript 中却不可用。相反,如果您定义了两个同名的函数,那么第二个定义将替换第一个定义。
定义返回结果的函数
您可以使用return
关键字从函数中返回结果。清单 4-5 显示了一个返回结果的函数。
清单 4-5 。从函数返回结果
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
function myFunc(name) {
return ("Hello " + name + ".");
};
console.log(myFunc("Adam"));
</script>
</head>
<body>
This is a simple example
</body>
</html>
这个函数定义了一个参数,并用它来产生一个结果。我调用函数并将结果作为参数传递给console.log
函数,如下所示:
...
console.log(myFunc("Adam"));
...
请注意,您不必声明该函数将返回一个结果或表示结果的数据类型。该清单的结果如下:
Hello Adam.
使用变量和类型
您可以使用var
关键字定义变量,并且可以选择在一条语句中为变量赋值。函数中定义的变量是局部变量,并且只能在该函数中使用。在script
元素中直接定义的变量是全局变量,可以在任何地方访问,包括同一个 HTML 文档中的其他脚本。清单 4-6 展示了局部和全局变量的使用。
清单 4-6 。使用局部和全局变量
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myGlobalVar = "apples";
function myFunc(name) {
var myLocalVar = "sunny";
return ("Hello " + name + ". Today is " + myLocalVar + ".");
};
console.log(myFunc("Adam"));
</script>
<script type="text/javascript">
console.log("I like " + myGlobalVar);
</script>
</head>
<body>
This is a simple example
</body>
</html>
同样,JavaScript 是一种动态类型语言。这并不意味着 JavaScript 没有类型:这只是意味着您不必显式声明变量的类型,并且您可以毫无困难地将不同的类型赋给同一个变量。JavaScript 将根据您分配给变量的值来确定类型,并根据使用它们的上下文在类型之间自由转换。来自清单 4-6 的结果如下:
Hello Adam. Today is sunny.
I like apples
使用原始类型
JavaScript 定义了一组原语类型:string
、number
和boolean
。这似乎是一个很短的列表,但是 JavaScript 设法将很大的灵活性融入到这三种类型中。
使用字符串
使用双引号或单引号字符定义string
值,如清单 4-7 所示。
清单 4-7 。定义字符串变量
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var firstString = "This is a string";
var secondString = 'And so is this';
</script>
</head>
<body>
This is a simple example
</body>
</html>
您使用的引号字符必须匹配。例如,你不能用单引号开始一个字符串,然后用双引号结束。此列表没有控制台输出。
使用布尔值
boolean
类型有两个值:true
和false
。清单 4-8 显示了正在使用的两个值,但是这种类型在条件语句中使用时最有用,比如一个if
语句。该清单中没有控制台输出。
清单 4-8 。定义布尔值
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var firstBool = true;
var secondBool = false;
</script>
</head>
<body>
This is a simple example
</body>
</html>
使用数字
number
类型用于表示整数和浮点数(也称为实数)。清单 4-9 提供了一个演示。
清单 4-9 。定义数值
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var daysInWeek = 7;
var pi = 3.14;
var hexValue = 0xFFFF;
</script>
</head>
<body>
This is a simple example
</body>
</html>
您不必指定使用哪种号码。您只需表达您需要的值,JavaScript 就会相应地执行。在清单中,我定义了一个整数值、一个浮点值,并在一个值前面加上了0x
来表示一个十六进制值。(清单中没有控制台输出。)
创建对象
JavaScript 支持对象的概念,并且有不同的方法来创建它们。清单 4-10 给出了一个简单的例子。
清单 4-10 。创建一个对象
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData = new Object();
myData.name = "Adam";
myData.weather = "sunny";
console.log("Hello " + myData.name + ". ");
console.log("Today is " + myData.weather + ".");
</script>
</head>
<body>
This is a simple example
</body>
</html>
我通过调用new Object()
创建一个对象,并将结果(新创建的对象)赋给一个名为myData
的变量。一旦创建了对象,我就可以通过赋值来定义对象的属性,就像这样:
...
myData.name = "Adam";
...
在这个语句之前,我的对象没有名为name
的属性。在语句执行之后,属性确实存在,并且它被赋予了值Adam
。您可以通过将变量名和属性名与句点组合来读取属性值,如下所示:
...
console.log("Hello " +myData.name+ ". ");
...
清单的结果如下:
Hello Adam.
Today is sunny.
使用对象文字
您可以使用对象文字格式在一个步骤中定义一个对象及其属性。清单 4-11 展示了这是如何做到的。
清单 4-11 。使用对象文字格式
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData = {
name: "Adam",
weather: "sunny"
};
console.log("Hello " + myData.name + ". ");
console.log("Today is " + myData.weather + ".");
</script>
</head>
<body>
This is a simple example
</body>
</html>
使用冒号(:
)将您要定义的每个属性与其值分开,使用逗号(,
)将属性分开。效果与前面的示例相同,清单的结果如下:
Hello Adam.
Today is sunny.
使用函数作为方法
我最喜欢 JavaScript 的一个特性是可以向对象添加函数。定义在对象上的函数被称为方法。不知道为什么,我觉得这很优雅,让人赏心悦目。清单 4-12 展示了如何以这种方式添加方法。
清单 4-12 。向对象添加方法
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData = {
name: "Adam",
weather: "sunny",
printMessages: function() {
console.log("Hello " + this.name + ". ");
console.log("Today is " + this.weather + ".");
}
};
myData.printMessages();
</script>
</head>
<body>
This is a simple example
</body>
</html>
在这个例子中,我用一个函数创建了一个名为printMessages
的方法。注意,为了引用对象定义的属性,我必须使用this
关键字。当一个函数作为一个方法使用时,该函数通过特殊变量this
被隐式传递给调用该方法的对象作为参数。清单的输出如下所示:
Hello Adam.
Today is sunny.
使用对象
一旦你创建了对象,你可以用它们做很多事情。在接下来的部分,我将描述在本书后面会有用的活动。
读取和修改属性值
对对象做的最明显的事情是读取或修改分配给对象定义的属性的值。您可以使用两种不同的语法风格,这两种风格都显示在清单 4-13 中。
清单 4-13 。读取和修改对象属性
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData = {
name: "Adam",
weather: "sunny",
};
myData.name = "Joe";
myData["weather"] = "raining";
console.log("Hello " + myData.name+ ".");
console.log("It is " + myData["weather"]);
</script>
</head>
<body>
This is a simple example
</body>
</html>
第一种风格是大多数程序员熟悉的,也是我在前面的例子中使用的。用句点将对象名和属性名连接在一起,如下所示:
...
myData.name = "Joe";
...
您可以使用等号(=
)为属性指定一个新值,或者忽略当前值来读取当前值。第二种样式是数组样式的索引,如下所示:
...
myData["weather"] = "raining";
...
在这种样式中,您可以在方括号([
和]
)之间指定您想要的属性的名称。这是访问属性的一种便捷方式,因为您可以将感兴趣的属性的名称作为变量传递,如下所示:
...
var myData = {
name: "Adam",
weather: "sunny",
};
var propName = "weather";
myData[propName] = "raining";
...
这是如何枚举一个对象的属性的基础,我将在下面描述。下面是清单中的控制台输出:
Hello Joe.
It is raining
枚举对象的属性
使用for...in
语句枚举一个对象拥有的属性。清单 4-14 展示了如何使用这个语句。
清单 4-14 。枚举对象的属性
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData = {
name: "Adam",
weather: "sunny",
printMessages: function() {
console.log("Hello " + this.name + ". ");
console.log("Today is " + this.weather + ".");
}
};
for (var prop in myData) {
console.log("Name: " + prop + " Value: " + myData[prop]);
}
</script>
</head>
<body>
This is a simple example
</body>
</html>
for...in
循环在代码块中为myData
对象中的每个属性执行语句。在每次迭代中,prop
变量被赋予被处理的属性的名称。我使用数组索引样式从对象中检索属性值。该清单的输出如下所示(为了便于阅读,我对结果进行了格式化):
Name: name Value: Adam
Name: weather Value: sunny
Name: printMessages Value: function () {
console.log("Hello " + this.name + ". ");
console.log("Today is " + this.weather + ".");
}
从结果可以看出,我定义为方法的函数也被枚举了。这是 JavaScript 灵活处理函数的结果。
添加和删除属性和方法
即使使用了 object literal 样式,您仍然可以为对象定义新的属性。清单 4-15 给出了一个演示。(本节中的清单不产生任何控制台输出。)
清单 4-15 。向对象添加新属性
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData = {
name: "Adam",
weather: "sunny",
};
myData.dayOfWeek = "Monday";
</script>
</head>
<body>
This is a simple example
</body>
</html>
在这个清单中,我向名为dayOfWeek
的对象添加了一个新属性。我使用了点符号(用句点连接对象和属性名),但是我也可以使用索引样式的符号。正如你现在所期望的,你也可以通过将一个属性的值设置为一个函数来给一个对象添加新的方法,如清单 4-16 所示。
清单 4-16 。向对象添加新方法
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData = {
name: "Adam",
weather: "sunny",
};
myData.SayHello = function() {
console.write("Hello");
};
</script>
</head>
<body>
This is a simple example
</body>
</html>
你可以使用delete
关键字从一个对象中删除一个属性或方法,如清单 4-17 所示。
清单 4-17 。从对象中删除属性
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData = {
name: "Adam",
weather: "sunny",
};
delete myData.name;
delete myData["weather"];
delete myData.SayHello;
</script>
</head>
<body>
This is a simple example
</body>
</html>
确定对象是否具有属性
你可以使用in
表达式检查一个对象是否有属性,如清单 4-18 所示。
清单 4-18 。检查对象是否具有属性
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData = {
name: "Adam",
weather: "sunny",
};
var hasName = "name" in myData;
var hasDate = "date" in myData;
console.log("HasName: " + hasName);
console.log("HasDate: " + hasDate);
</script>
</head>
<body>
This is a simple example
</body>
</html>
在这个例子中,我测试了一个存在的属性和一个不存在的属性。变量hasName
的值将是true
,属性hasDate
的值将是false
,如下所示:
HasName: true
HasDate: false
使用 JavaScript 运算符
JavaScript 定义了一组非常标准的操作符。我在表 4-1 中总结了最有用的。
表 4-1 。有用的 JavaScript 操作符
操作员 | 描述 |
---|---|
++, -- | 前或后递增和递减 |
+, -, *, /, % | 加法、减法、乘法、除法、余数 |
<, <=, >, >= | 小于,小于等于,大于,大于等于 |
==, != | 平等和不平等测试 |
===, !== | 同一性和非同一性测试 |
&&, || | 逻辑 AND 和 OR |
= | 分配 |
+ | 串并置 |
?: | 三操作数条件语句 |
使用条件语句
许多 JavaScript 操作符与条件语句一起使用。在本书中,我倾向于使用if/else
和switch
语句。清单 4-19 展示了两者的用法(如果你使用过几乎任何一种编程语言,你都会很熟悉)。
清单 4-19 。使用 if/else 和 switch 条件语句
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var name = "Adam";
if (name == "Adam") {
console.log("Name is Adam");
} else if (name == "Jacqui") {
console.log("Name is Jacqui");
} else {
console.log("Name is neither Adam or Jacqui");
}
switch (name) {
case "Adam":
console.log("Name is Adam");
break;
case "Jacqui":
console.log("Name is Jacqui");
break;
default:
console.log("Name is neither Adam or Jacqui");
break;
}
</script>
</head>
<body>
This is a simple example
</body>
</html>
清单中的结果如下:
Name is Adam
Name is Adam
相等运算符与相同运算符
等式和等式操作符特别值得注意。相等运算符将尝试将操作数强制为同一类型,以便评估相等性。这是一个方便的特性,只要你意识到它正在发生。清单 4-20 展示了等式操作符的作用。
清单 4-20 。使用相等运算符
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var firstVal = 5;
var secondVal = "5";
if (firstVal == secondVal) {
console.log("They are the same");
} else {
console.log("They are NOT the same");
}
</script>
</head>
<body>
This is a simple example
</body>
</html>
该脚本的输出如下:
They are the same
JavaScript 将两个操作数转换成相同的类型,并对它们进行比较。本质上,相等运算符测试值是否相同,而不管它们的类型如何。如果你想测试确保值和的类型是相同的,那么你需要使用恒等运算符(===
,三个等号,而不是两个等号),如清单 4- 21 所示。
清单 4-21 。使用标识运算符
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var firstVal = 5;
var secondVal = "5";
if (firstVal === secondVal) {
console.log("They are the same");
} else {
console.log("They are NOT the same");
}
</script>
</head>
<body>
This is a simple example
</body>
</html>
在本例中,identity 运算符将认为这两个变量是不同的。该运算符不强制类型。该脚本的结果如下:
They are NOT the same
JavaScript 原语通过值进行比较,但是 JavaScript 对象通过引用进行比较。清单 4-22 展示了 JavaScript 如何处理对象的相等和相同测试。
清单 4-22 。对对象执行相等和相同测试
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData1 = {
name: "Adam",
weather: "sunny",
};
var myData2 = {
name: "Adam",
weather: "sunny",
};
var myData3 = myData2;
var test1 = myData1 == myData2;
var test2 = myData2 == myData3;
var test3 = myData1 === myData2;
var test4 = myData2 === myData3;
console.log("Test 1: " + test1 + " Test 2: " + test2);
console.log("Test 3: " + test3 + " Test 4: " + test4);
</script>
</head>
<body>
This is a simple example
</body>
</html>
该脚本的结果如下:
Test 1: false Test 2: true
Test 3: false Test 4: true
清单 4-23 显示了对原语执行的相同测试。
清单 4-23 。对对象执行相等和相同测试
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData1 = 5;
var myData2 = "5";
var myData3 = myData2;
var test1 = myData1 == myData2;
var test2 = myData2 == myData3;
var test3 = myData1 === myData2;
var test4 = myData2 === myData3;
console.log("Test 1: " + test1 + " Test 2: " + test2);
console.log("Test 3: " + test3 + " Test 4: " + test4);
</script>
</head>
<body>
This is a simple example
</body>
</html>
该脚本的结果如下:
Test 1: true Test 2: true
Test 3: false Test 4: true
显式转换类型
字符串连接操作符 ( +
)的优先级高于加法操作符(还有+
),这意味着 JavaScript 将优先于加法操作连接变量。这可能会造成混乱,因为 JavaScript 也会自由地转换类型来产生结果——而不总是预期的结果,如清单 4-24 所示。
清单 4-24 。字符串连接运算符优先级
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData1 = 5 + 5;
var myData2 = 5 + "5";
console.log("Result 1: " + myData1);
console.log("Result 2: " + myData2);
</script>
</head>
<body>
This is a simple example
</body>
</html>
该脚本的结果如下:
Result 1: 10
Result 2: 55
第二种结果是引起混乱的那种。通过运算符优先级和过急类型转换的组合,原本应该是加法运算的操作被解释为字符串串联。为了避免这种情况,可以显式转换值的类型,以确保执行正确的操作,如以下部分所述。
将数字转换为字符串
如果你正在处理多个数字变量,并想把它们连接成字符串,那么你可以用toString
方法 把数字转换成字符串,如清单 4-25 所示。
清单 4-25 。使用 Number.toString 方法
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData1 = (5).toString() + String(5);
console.log("Result: " + myData1);
</script>
</head>
<body>
This is a simple example
</body>
</html>
请注意,我将数值放在了括号中,然后调用了toString
方法。这是因为在调用number
类型定义的方法之前,您必须允许 JavaScript 将文字值转换成number
。我还展示了实现相同效果的另一种方法,即调用String
函数,并将数值作为参数传入。这两种技术具有相同的效果,都是将一个number
转换成一个string
,这意味着+
操作符用于字符串连接而不是加法。该脚本的输出如下:
Result: 55
还有一些其他的方法可以让你更好地控制一个数字如何被表示成一个字符串。我在表 4-2 中简要描述了这些。表格中显示的所有方法都由number
类型定义。
表 4-2 。有用的 Number.toString 方法
方法 | 描述 | 返回 |
---|---|---|
toString() | 代表基数为 10 的数字 | string |
toString(2)``toString(8) | 用二进制、八进制或十六进制表示法表示一个数 | string |
toFixed(n) | 表示小数点后有 n 位的实数 | string |
toExponential(n) | 使用指数表示法表示一个数字,小数点前有一位,小数点后有 n 位 | string |
toPrecision(n) | 代表一个有 n 个有效数字的数字,如果需要,使用指数符号 | string |
将字符串转换为数字
补充技术是将字符串转换成数字,这样您就可以执行加法而不是连接。你可以用Number
函数来完成,如清单 4-26 所示。
清单 4-26 。将字符串转换为数字
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var firstVal = "5";
var secondVal = "5";
var 结果=数量(firstVal) +数量(second val);
console.log("Result: " + result);
</script>
</head>
<body>
This is a simple example
</body>
</html>
该脚本的输出如下:
Result: 10
Number
方法在解析字符串值的方式上非常严格,但是你可以使用另外两个更灵活的函数,它们会忽略后面的非数字字符。这些功能是parseInt
和parseFloat
。我已经在表 4-3 中描述了所有三种方法。
表 4-3 。对数字方法有用的字符串
方法 | 描述 |
---|---|
Number(str) | 分析指定的字符串以创建整数值或实数值 |
parseInt(str) | 分析指定的字符串以创建整数值 |
parseFloat(str) | 分析指定的字符串以创建整数值或实数值 |
使用数组
JavaScript 数组的工作方式很像大多数其他编程语言中的数组。清单 4-27 展示了如何创建和填充一个数组。
清单 4-27 。创建并填充数组
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myArray = new Array();
myArray[0] = 100;
myArray[1] = "Adam";
myArray[2] = true;
</script>
</head>
<body>
This is a simple example
</body>
</html>
我通过调用new Array()
创建了一个新数组。这创建了一个空数组,我将它赋给了变量myArray
。在随后的语句中,我为数组中的不同索引位置赋值。(这个清单中没有控制台输出。)()
。
在这个例子中有一些事情需要注意。首先,在创建数组时,我不需要声明数组中的项数。JavaScript 数组会自动调整大小以容纳任意数量的项目。第二点是,我不必声明数组将保存的数据类型。任何 JavaScript 数组都可以包含任何混合的数据类型。在这个例子中,我给数组分配了三个项目:一个number
、一个string
和一个boolean
。
使用数组文本
数组字面样式让你在一条语句中创建并填充一个数组,如清单 4-28 所示。
清单 4-28 。使用数组文字样式
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myArray = [100, "Adam", true];
</script>
</head>
<body>
This is a simple example
</body>
</html>
在这个例子中,我通过在方括号([
和]
)之间指定我想要的数组中的项目,指定了应该给myArray
变量分配一个新的数组。(这个清单中没有控制台输出。)
读取和修改数组的内容
使用方括号([
和]
)读取给定索引处的值,将所需的索引放在括号之间,如清单 4-29 所示。
清单 4-29 。从数组索引中读取数据
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myArray = [100, "Adam", true];
console.log("Index 0: " +myArray[0]);
</script>
</head>
<body>
This is a simple example
</body>
</html>
只需给索引赋值,就可以修改 JavaScript 数组中任何位置的数据。就像常规变量一样,您可以在索引处切换数据类型,不会有任何问题。清单的输出如下所示:
Index 0: 100
清单 4-30 展示了如何修改一个数组的内容。
清单 4-30 。修改数组的内容
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myArray = [100, "Adam", true];
myArray[0] = "Tuesday";
console.log("Index 0: " + myArray[0]);
</script>
</head>
<body>
This is a simple example
</body>
</html>
在这个例子中,我将一个string
赋值给数组中的位置0
,这个位置以前是由一个number
持有的,并产生以下输出:
Index 0: Tuesday
枚举数组的内容
使用循环枚举数组的内容。清单 4-31 展示了如何应用循环来显示一个简单数组的内容。
清单 4-31 。枚举数组的内容
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myArray = [100, "Adam", true];
for (var i = 0; i < myArray.length; i++) {
console.log("Index " + i + ": " + myArray[i]);
}
</script>
</head>
<body>
This is a simple example
</body>
</html>
JavaScript 循环的工作方式与许多其他语言中的循环一样。使用length
属性确定数组中有多少个元素。清单的输出如下所示:
Index 0: 100
Index 1: Adam
Index 2: true
使用内置数组方法
JavaScript Array
对象定义了许多可以用来处理数组的方法。表 4-4 描述了这些方法中最有用的。
表 4-4 。有用的数组方法
方法 | 描述 | 返回 |
---|---|---|
concat(otherArray) | 将数组的内容与参数指定的数组连接起来。可以指定多个数组。 | Array |
join(separator) | 连接数组中的所有元素,形成一个字符串。该参数指定用于分隔各项的字符。 | string |
pop() | 将数组视为堆栈,移除并返回数组中的最后一项。 | object |
push(item) | 将数组视为堆栈,并将指定项追加到数组中。 | void |
reverse() | 反转数组中项目的顺序。 | Array |
shift() | 类似于 pop,但是对数组中的第一个元素进行操作。 | object |
slice(start,end) | 返回数组的一部分。 | Array |
sort() | 对数组中的项目进行排序。 | Array |
splice(index, count) | 从指定的索引开始,从数组中删除 count 个项目。 | Array |
unshift(item) | 类似于 push,但是在数组的开头插入新元素。 | void |
处理错误
JavaScript 使用try...catch
语句来处理错误。在很大程度上,我不会担心本书中的错误,因为我的重点是解释 jQuery 的特性,而不是一般的编程技术。清单 4-32 展示了如何使用这种语句。
清单 4-32 。处理异常
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
try {
var myArray;
for (var i = 0; i < myArray.length; i++) {
console.log("Index " + i + ": " + myArray[i]);
}
} catch (e) {
console.log("Error: " + e);
}
</script>
</head>
<body>
This is a simple example
</body>
</html>
这个脚本中的问题很常见。我正在尝试使用一个没有正确初始化的变量。我已经包装了我怀疑会导致语句的try
子句出错的代码。如果没有出现问题,那么语句会正常执行,并且会忽略catch
子句。
但是,由于该代码中有一个错误,因此try
子句中语句的执行会立即停止,控制权会传递给catch
子句,并在控制台上产生以下输出:
Error: TypeError: Cannot read property 'length' of undefined
您遇到的错误由一个Error
对象描述,该对象被传递给catch
子句。表 4-5 显示了由Error
对象定义的属性。
表 4-5 。错误对象
财产 | 描述 | 返回 |
---|---|---|
message | 错误情况的描述。 | string |
name | 错误的名称。默认情况下,这是错误。 | string |
number | 这种错误的错误号(如果有)。 | number |
catch
条款是你从错误中恢复或清理的机会。如果有需要执行的语句,不管是否有错误,你可以把它们放在可选的finally
子句中,如清单 4-33 所示。
清单 4-33 。使用 finally 子句
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
try {
var myArray;
for (var i = 0; i < myArray.length; i++) {
console.log("Index " + i + ": " + myArray[i]);
}
} catch (e) {
console.log("Error: " + e);
} finally {
console.log("Statements here are always executed");
}
</script>
</head>
<body>
This is a simple example
</body>
</html>
该清单产生以下控制台输出:
Error: TypeError: Cannot read property 'length' of undefined
Statements here are always executed
比较未定义值和空值
JavaScript 定义了几个特殊值,在比较它们时需要小心:undefined
和null
。当你读取一个没有赋值的变量或者试图读取一个不存在的对象属性时,就会返回undefined
值。清单 4-34 展示了undefined
在 JavaScript 中的用法。
清单 4-34 。未定义的特殊值
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData = {
name: "Adam",
weather: "sunny",
};
console.log("Prop: " +myData.doesntexist);
</script>
</head>
<body>
This is a simple example
</body>
</html>
该清单的输出如下:
Prop: undefined
JavaScript 的不同寻常之处在于它还定义了另一个特殊值null
。null
值与undefined
值略有不同。当没有定义值时,返回undefined
值,当你想表示你已经赋值,但该值不是有效的object
、string
、number
或boolean
时,使用null
;也就是说,你定义了一个值没有值。为了帮助澄清这一点,清单 4-35 显示了从undefined
到null
的过渡。
清单 4-35 。使用 undefined 和 null
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData = {
name: "Adam",
};
console.log("Var: " + myData.weather);
console.log("Prop: " + ("weather" in myData));
myData.weather = "sunny";
console.log("Var: " + myData.weather);
console.log("Prop: " + ("weather" in myData));
myData.weather = null;
console.log("Var: " + myData.weather);
console.log("Prop: " + ("weather" in myData));
</script>
</head>
<body>
This is a simple example
</body>
</html>
我创建了一个对象,然后尝试读取未定义的属性weather
的值:
...
console.log("Var: " + myData.weather);
console.log("Prop: " + ("weather" in myData));
...
没有weather
属性,所以调用myData.weather
返回的值是undefined
,使用in
关键字判断对象是否包含属性返回false
。这两条语句的输出如下:
Var: undefined
Prop: false
接下来,我给weather
属性赋值,这样做的效果是将属性添加到对象中:
...
myData.weather = "sunny";
console.log("Var: " + myData.weather);
console.log("Prop: " + ("weather" in myData));
...
我读取属性的值,并再次检查对象中是否存在该属性。如您所料,对象定义了属性,其值为sunny
:
Var: sunny
Prop: true
现在我将属性的值设置为null
,如下所示:
...
myData.weather = null;
...
这有特定的效果。属性仍然由对象定义,但是我已经指出它不包含值。当我再次执行检查时,我得到以下结果:
Var: null
Prop: true
在比较undefined
和null
值时,这种区别很重要,因为null
是一个object
,而undefined
本身就是一个类型。
检查是否为空或未定义
如果你想检查一个属性是null
还是undefined
(你不在乎哪个),那么你可以简单地使用一个if
语句和一个否定运算符(!
,如清单 4-36 所示。
清单 4-36 。检查属性是否为空或未定义
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var myData = {
name: "Adam",
city: null
};
if (!myData.name) {
console.log("name IS null or undefined");
} else {
console.log("name is NOT null or undefined");
}
if (!myData.city) {
console.log("city IS null or undefined");
} else {
console.log("city is NOT null or undefined");
}
</script>
</head>
<body>
This is a simple example
</body>
</html>
这种技术依赖于 JavaScript 执行的类型强制,因此您检查的值被视为boolean
值。如果一个变量或属性是null
或undefined
,那么被强制的boolean
值就是false
。清单产生以下输出:
name is NOT null or undefined
city IS null or undefined
区分空值和未定义值
如果你想比较两个值,你可以选择。如果您想将一个undefined
值视为与一个null
值相同,那么您可以使用等号运算符(==
)并依靠 JavaScript 来转换类型。例如,undefined
变量将被视为等于null
变量。如果你想区分null
和undefined
,那么你需要使用恒等运算符(===
)。清单 4-37 显示了两种比较。
清单 4-37 。空值和未定义值的相等和相同比较
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<script type="text/javascript">
var firstVal = null;
var secondVal;
var equality = firstVal == secondVal;
var identity = firstVal === secondVal;
console.log("Equality: " + equality);
console.log("Identity: " + identity);
</script>
</head>
<body>
This is a simple example
</body>
</html>
该脚本的输出如下:
Equality: true
Identity: false
摘要
在这一章中,我向您展示了将在本书中使用的核心 JavaScript 特性。理解基本的 JavaScript 是使用 jQuery 的基础,您将在前面的章节中看到。在本书的第二部分,我将正确地介绍 jQuery,并向您展示如何使用它。