jQuery Cookbook中文版

978-7-115-25590-7
作者: 【美】jQuery社区专家组
译者: 姚军孙博
编辑: 汪振

图书目录:

详情

本书介绍如何为你的Web站点和Web应用从jQuery库中添加控件,包含了针对常见Web开发问题的实际的解决方案以及使用jQuery的最佳实践。如果你已经开始使用jQuery,本书将帮你回头思考现有的jQuery代码,以确保它能高效地完成你的任务。

图书摘要

版权信息

书名:jQuery Cookbook中文版

ISBN:978-7-115-25590-7

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

• 著    [美] jQuery社区专家组

  译    姚 军  孙 博

  责任编辑 汪 振

• 人民邮电出版社出版发行  北京市丰台区成寿寺路11号

  邮编 100061  电子邮件 315@ptpress.com.cn

  网址 http://www.ptpress.com.cn

• 读者服务热线:(010)67132692

  反盗版热线:(010)67171154


Copyright © 2011 by O’Reilly Media. Inc.

Simplified Chinese Edition, jointly published by O’Reilly Media, Inc. and Posts & Telecom Press, 2013. Authorized translation of the English edition, 2011 O’Reilly Media, Inc., the owner of all rights to publish and sell the same.

All rights reserved including the rights of reproduction in whole or in part in any form.

本书中文简体字版由O’Reilly Media, Inc.授权人民邮电出版社出版。未经出版者书面许可,对本书的任何部分不得以任何方式复制或抄袭。

版权所有,侵权必究。


内容提要

本书旨在向读者展示业界领先的前端开发人员在日常项目中使用jQuery的方式和方法。全书共分18章,分别由不同的作者撰写。这些业界精英将带领读者经历由简到繁的各种问题的解决过程,不管是jQuery新手还是老练的JavaScript开发人员,都能通过本书对jQuery的能力有全新的认识。

本书从基础知识和通用最佳实践的介绍开始,内容包括在页面中包含jQuery、做出选择、遍历和操纵;接着转向实际用例,带领读者寻找常见问题的解决方案,包括事件、特效、尺寸、表单和用户界面元素等;最后研究jQuery应用程序的测试以及将jQuery集成到复杂网站的方法。

无论是为jQuery前端开发人员,还是编写客户端代码的服务器端开发人员,都可以从本书中找到自己感兴趣的内容,并提高自己的开发本领。


Jonathan Sharp从1986年起开始热心于互联网和Web开发,在以后的岁月中,他曾为多家创业公司和财富500强公司工作过。Jonathan在内布拉斯加州的大奥马哈(Omaha)市创立了Out West Media有限责任公司,提供以定制XHTML、CSS和jQuery开发为中心的前端工程和架构服务。Jonathan是jQuery核心团队成员,在编码之余也是一位作家和演说家。Jonathan非常感激他的妻子Erin、女儿Noel、两只狗和两匹马。

Rob Burns供职于A Mountain Top有限责任公司,从事交互式Web应用程序开发。在过去的12年中,他采用多种工具和技术探索网站开发。在业余时间,他喜欢自然语言处理和开放源码软件项目中带来的众多机会。

Rebecca Murphey是一位独立前端架构顾问,开发充当服务器端和浏览器端之间胶水的定制前端解决方案。她还提供以jQuery程序库为重点的前端开发的培训。她和她的伙伴——两只狗和两只猫一起生活在北卡罗来纳州的达勒姆(Durham)。

Ariel Flesler是一位Web开发人员和视频游戏程序员。他从2007年1月起开始投入jQuery的开发,并在2008年5月加入核心团队。他出生于阿根廷布利诺斯艾利斯,曾就学于国家科技大学(阿根廷)。他最初的工作是ASP.NET(C#)程序员,后转向XHTML网站和Ajax应用的客户端开发。他目前在QB9工作,负责基于AS3的休闲游戏和MMO。

Cody Lindley是一位基督徒、丈夫、儿子、父亲、户外活动爱好者和专业的客户端工程师。从1997年起,他热衷于HTML、CSS、JavaScript、Flash、界面设计和HCI。他因创建模态/对话框解决方案ThickBox而享誉于jQuery社区。2008年,他正式加入jQuery团队,成为一位倡导者。他目前关注的方向是客户端优化技术,以及有关jQuery的写作和演讲。Cody的网站是http://www.codylindley.com

Remy Sharp是一位开发人员、作家、演说家和博主。Remy于1999年开始了他的Web开发生涯,当时他是一个财经网站的唯一开发人员,在“网络繁荣”之中和之后的很长一段时间,他经历了网站运营各个方面的工作。现在,他在英国布莱顿(Brighton)运营自己的开发公司Left Logic,编写JavaScript、jQuery、HTML 5、CSS、PHP、Perl和其他自己熟悉的程序。

Mike Hostetler是一位发明家、企业家、程序员和自豪的父亲。从20世纪90年代中期,Mike就开始使用Web技术,在PHP和JavaScript Web应用程序开发方面有着丰富的经验。目前,Mike掌管位于科罗拉多州费城的Web技术咨询公司A Mountain Top有限责任公司。Mike频繁参与开源项目,是jQuery核心团队成员,负责QCubed PHP5 Framework项目并参与Drupal项目。当他不在计算机前时,喜欢徒步旅行、飞钓、滑雪以及和家人共享时光。

Ralph Whitbeck毕业于罗彻斯特(Rochester)理工学院,目前是位于纽约罗彻斯特的BrandLogic公司的高级开发人员。他在BrandLogic的工作包括界面设计、可用性测试、Web和应用程序开发。Ralph能够用ASP.NET、C#和 SQL Server开发复杂的Web应用系统,也能使用XHTML、CSS和JavaScript/jQuery等客户端技术实现客户认可的设计。2009年10月,Ralph加入jQuery团队,成为一位倡导者。Ralph喜欢和妻子Hope及三个儿子Brandon、Jordan和 Ralphie共度时光。你可以在他的个人博客(http://ralphwhitbeck.com)上了解更多有关他的情况。

Nathan Smith是从20世纪末就开始构建网站的一个古怪的家伙。他喜欢手动编写HTML、CSS和JavaScript,对设计和信息架构也有涉猎。他曾为Adobe Developer Center、Digital Web和.NET Magazine等在线及纸质出版物撰稿,在Adobe MAX、BibleTech、Drupal Camp、Echo Conference、Ministry 2.0、Refresh Dallas和Webmaster Jam Session等会议上发表过演讲。Nathan在FellowshipTech.com任UX开发人员,拥有阿斯伯里(Asbury)神学院的神学硕士学位。他启动了Godbit.com,这是一个旨在帮助教堂和神职人员更好使用Web的公共资源。他还创建了960 Grid System(http://www.960.gs)——一个页面布局草拟、设计和编码的框架。

Brian Cherne是一位软件开发人员,在规划和构建基于Web的应用程序、信息站和高流量电子商务网站方面有超过10年的经验。他也是hoverIntent jQuery插件的作者。在不摆弄代码的时候,Brian会跳交谊舞、练习武术或者学习俄罗斯语言文化。

Jörn Zaefferer是来自德国科隆的专业软件开发人员。他创建用于Web和桌面应用程序的应用编程接口(API)、图形用户界面(GUI)、软件架构和数据库。他的工作以Java平台为中心,同时围绕jQuery开发客户端脚本。2006年中期,他开始为jQuery做出贡献,目前已经共同创建和维护jQuery的单元测试框架QUnit;发布和维护了6个非常流行的jQuery插件,并且以作者和技术审核者身份参与了jQuery书籍的创作,还是jQuery UI的首席开发人员。

James Padolsey是一位热心的Web开发人员和博主,来自英国伦敦。自从第一次看到jQuery,他就为之疯狂;他编写了jQuery的教程、讨论文章和博客,并为社区贡献了丰富的插件。Jame将来的计划包括获得肯特(Kent)大学的计算机科学学位,以及不断开拓新领域的职业生涯。他的网站是http://james.padolsey.com

Scott González是生活在北卡罗来纳罗利(Raleigh)的一位Web应用开发人员,他喜欢构建高动态性的系统和灵活的可伸缩框架。他从2007年开始为jQuery做出贡献,目前是jQuery的官方用户界面库jQuery UI的开发主力。Scott还在nemikor.com上编写了关于jQuery和jQuery UI的教程,并在许多会议上发表有关jQuery的演讲。

Michael Geary从电传打字机穿孔纸带的时代就开始了软件开发,当时“兼容标准”的含义只不过是遵循穿孔纸带数据交换的ECMA-10标准。现在,Mike是一位Web和Android开发人员,对编写快速、清晰和简洁的代码有着特别的兴趣,还喜欢在jQuery邮件列表上帮助其他开发人员。他的网站是http://mg.to

Maggie Wachs、Scott Jehl、Todd Parker和 Patty Toland是Filament小组成员。他们一起为面向消费者和公司的网站、无线设备、安装的和基于Web的应用程序设计和开发实用的用户界面,他们的宗旨是提供直观易用的体验同时兼具广泛的可访问性。他们是jQuery UI团队的发起人和设计主力,设计和开发了ThemeRoller.com,并积极地投身于正式的jQuery UI程序库和CSS框架的持续开发。

Richard D. Worth是一位Web UI开发人员,jQuery UI的发布经理和服务时间最长的开发人员之一。他是Dialog、Progressbar、Selectable和Slider插件的作者或者共同作者。Richard还喜欢在全球进行有关jQuery和jQuery UI的演讲和咨询工作。他和他可爱的妻子Nancy在弗吉尼亚州北部(华盛顿郊区)一起抚养儿女。他们已经有了三个漂亮的孩子:Naomi、Asher和Isaiah。Richard的网站是http://rdworth.org/


Karl Swedberg,在4年前开始Web开发人员职业生涯之前,他曾经在中学教过英语,在广告公司担任文稿编辑并且拥有一间咖啡屋。现在,Karl为密歇根州大急流城(Grand Rapids)的Fusionary Media公司工作,专攻客户端脚本和交互设计。Karl是jQuery项目团队成员,《Learning jQuery 1.3》和《jQuery Reference Guide》(均由Packt出版)的合著者。你可以在http://www.learningjquery.com找到他编写的提示和教程。

Dave Methvin是PCPitstop.com首席技术官和该公司的创始股东之一。他从2006年开始使用jQuery,活跃于jQuery帮助小组,并且贡献了包括Corner和Splitter在内的多个流行jQuery插件。在加入PC Pitstop之前,Dave曾在《PC Tech Journal》和《Windows Magazine》担任执行编辑,是JavaScript方面的专栏作者。他持续地为多家PC相关网站(包括InformationWeek)撰稿。Dave持有弗吉尼亚大学计算机科学学士和硕士学位。

David Serduke是一位前端程序员,最近在服务器端投入了许多时间。在多年的编程工作之后,他于2007年底开始使用jQuery并很快加入了jQuery核心团队。David目前为金融机构创建网站,并将jQuery的优点带入ASP.NET企业应用程序。David住在加州北部,拥有加州大学伯克利分校电子工程学士学位和圣玛丽(St. Mary)学院的MBA学位。

Scott Mark是Medtronic公司的企业应用架构师。他致力于开发基于Web的个性化信息门户和事务型应用程序,关注可控环境中高可用性的维护。目前,他最感兴趣的领域是富互联网应用程序和多点触摸用户界面技术。Scott和他可爱的妻子、两个儿子和一条黑色的拉布拉多犬一起住在明尼苏达州。他的技术博客参见http://scottmark.wordpress.com


当我在2005年开始构建jQuery的时候,心中有一个简单的目标:我希望能够编写一个Web应用程序,使其能在所有主流浏览器上正常工作——不需要进一步的修补和bug修复。在我建立一组足以完成个人目标的实用程序前几个月,我认为自己已经接近目标了,完全没有意识到我的工作才刚刚开始。

从这些简单的成果开始,随着新用户将这些程序库用于自己的项目,jQuery已经逐渐成长和发展起来。已经证明它是JavaScript程序库开发中最具挑战性的部分;虽然为个人或者具体的应用程序构建一个程序库相当简单,但是开发用于尽可能多环境(旧的浏览器、遗留网页和大量陌生的标记)的程序库却非常困难。令人惊讶的是,尽管jQuery已经为处理更多用例而做了修改,但是大部分原始API却完好无损地保留了下来。

我感到特别有趣的一件事情是了解开发人员如何使用jQuery达到自己的目的。作为具有计算机科技背景的人,我对有这么多设计人员和非程序员感受到jQuery的吸引力而吃惊。看到他们使用这个程序库的方式,使我对简洁的API设计有了更好的理解。此外,许多高级程序员采用jQuery开发复杂的大型程序,对我也有很大的启发。不过,最令我感觉良好的是能够从使用程序库的每一个人那里学到知识。

使用jQuery的另一个好处是可扩展的插件结构。在刚刚开发jQuery的时候,我确实为开发人员提供了扩展API的一些简单方法。这些扩展已经发展成了许多形形色色的插件社区,这些插件组成了应用程序、开发人员和用例这一完整的生态系统。这些插件社区加速了jQuery的成长——没有它们,这个程序库就没有今天的成就,所以我很高兴在本书中加入一些专门的章节,讲解一些最有趣的插件以及它们的用途。扩展对jQuery用途的感性认识的最佳途径之一,就是学习和使用来自jQuery插件社区的代码。

上述原因使这本“食谱”变得如此有趣:它为你带来了开发人员在日复一日的编码中完成的杰作和学习到的技巧,并加以提炼和总结,供以后使用。从个人的角度,我认为“食谱”类型的书籍是挑战我对语言或者程序库感性认识的最佳途径之一。我很乐意看到我所熟知的API被人们以新颖而有趣的方式利用。希望本书能够很好地为读者服务,将这些新颖而有趣的jQuery使用方法传授给大家。

——John Resig

jQuery创始人、首席开发者


jQuery程序库给前端开发带来了一场风暴。它极其简单的语法使曾经很复杂的任务变得轻松愉快。许多开发人员很快就为它的优雅和清晰而着迷。如果你已经开始使用这个程序库,你就已经将丰富而具有交互性的体验加入到你的项目中。

jQuery的入门非常容易,但是和许多用于开发网站的工具一样,完全体会到它的广度和深度需要花费几个月甚至几年的时间。这个程序库充满了你从未想象过的特性。一旦你了解了这些特性,这些特性就能够戏剧性地改变你解决问题的方法。

本书旨在向亲爱的读者展示业界领先的前端开发人员在日常项目中使用jQuery的方式和方法。在18章中,这些业界精英将带你经历由简到繁的各种问题的解决过程。不管你是jQuery新手还是老练的JavaScript开发人员,都能够对jQuery创建引人注目、健壮和高性能的用户界面的能力有全新的认识。

你可能是为jQuery提供的交互性而着迷的设计人员,也可能是希望了解其他人如何完成常见任务的jQuery前端开发人员。你还可能是常常应要求编写客户端代码的服务器端开发人员。

坦白说,这本“食谱”对于任何使用jQuery的人(或者希望使用jQuery的人)都有价值。如果你刚刚开始使用这一程序库,可以考虑配套阅读Packt出版的《Learning jQuery 1.3》或者Manning出版的《jQuery in Action》。如果你已经在项目中使用jQuery,本书能够增强你对jQuery的功能、隐藏的精华和特色的了解。

我们从基础知识和通用最佳实践的介绍开始——在页面中包含jQuery、做出选择、遍历和操纵。即使常用jQuery的用户也能从中学到一两个技巧。由此,我们转向实际的用例,带你经历对常见问题的可靠(并且经过测试)的解决方案,这些问题包括事件、特效、尺寸、表单和用户界面元素(可能需要或者不需要jQuery UI的帮助)。最后,我们将研究jQuery应用程序的测试以及将jQuery集成到复杂网站的方法。

在学习的过程中,你将学习到利用jQuery解决高级问题的策略。我们将研究如何最大限度地利用jQuery的事件管理系统,包括自定义事件和自定义事件数据,如何渐进增强表单,如何在页面上定位和重定位元素,如何从头开始创建选项卡、折叠控件和模态等用户界面元素,如何制作具备易读性和可维护性的代码,如何优化代码以简化测试、消除瓶颈和确保最高性能等。

因为这是一本“食谱”而非手册,你当然可以选择阅读最适合自己的“菜谱”[1];书中的每一个单独的秘诀都物有所值。但是,本书自始自终提供的都是jQuery社区中一些难得的绝妙解题方法。因此,我们希望你能至少从头到尾浏览一遍——你永远不会知道,哪一行代码能够让你茅塞顿开,使你的技巧更上一层楼。

jQuery非常强调链式(chaining)语法——依次调用选择元素的方法,确信每个方法都能返回继续工作所用的选择元素。这种模式将在第1章中深入说明——如果你还不熟悉这个程序库,就应该理解这个概念,因为在后续的章节中将会频繁地用到它。

对jQuery的功能做了一些简单的分类:核心功能、选择、操纵、遍历、CSS、属性、事件、特效、Ajax和工具。对这些分类和对应方法的学习,将极大地加强对书中内容的理解。

本书介绍的最佳实践之一是在变量中存储元素,而不是重复地进行相同的选择。当选择的元素存储在变量中时,该变量一般以$字符开头,表明它是一个 jQuery对象。这样的语法使代码更容易阅读和维护,但是应该理解,以$字符开头的变量名称并不是惯例,和PHP之类的语言不同,它在jQuery中没有特殊的意义。

一般来说,本书中的代码示例重视清晰性和易读性而不是简洁性,所以示例比起绝对必需的代码来说稍嫌冗长。如果你发现可以优化的地方,可以毫不犹豫地进行。同时,你也可以在自己的代码中坚持清晰性和易读性,然后使用代码精简工具准备用于生产环境的代码。

如果你想寻找其他jQuery资源,下面是我推荐的一些书籍:

在检查其他问题之前,确保页面上加载了jQuery程序库——你将会很惊奇地发现,很多时候这就是“代码不工作”问题的解决方案。如果你同时使用jQuery和另一个JavaScript程序库,可能需要使用jQuery.noConflict()来确保和其他程序库的协同工作。如果有的脚本需要jQuery,一定要在已经加载jQuery程序库之后再加载这些脚本。

本书中的许多代码都要求文档在JavaScript与之交互之前处于“就绪”状态。如果你在文档的头部包含了代码,确保这些代码包含在$(document).ready(function() { ... })之内,这样它就能知道,要等到文档就绪才开始交互。本书中讨论的一些功能只存在于jQuery 1.3和更高版本中。

如果你从旧版本的jQuery升级,确保升级使用的所有插件——过时的插件可能导致不可预知的表现。如果你发现示例在现有的应用程序中难以正常运行,在将其集成到现有代码之前先确保它能够正常运行。如果可以,Firefox浏览器的Firebug等工具能帮助你找出错误的根源。

如果你包含了jQuery的精简版本而问题出现在jQuery程序库本身,可以考虑在调试时切换到完整版本的jQuery。这样,你就更容易定位导致问题的代码行,这常常能将你引向解决问题的正确方向。

如果仍然不能解决问题,可以考虑将问题张贴到Google上的jQuery用户组。本书的多位作者都是该用户组的常客,该用户组的成员往往能提供有用的建议。Freenode上的#jquery IRC频道是解决问题的另一个有价值的资源。

如果上述方法都无效,可能是我们的错误。我们认真地测试和审查了书中的所有代码,但是仍然有可能出错。检查勘误表(在下一小节中说明)并下载更新后的样板代码,其中可能已经改正了我们发现的问题。

如果你喜欢——或者不喜欢——这本书,无论如何要让大家知道。Amazon reviews(亚马逊书评)是分享你的快乐(或者不快乐)的流行方法,你也可以在本书的网站上留下你的意见:

http://oreilly.com/catalog/9780596159771/

网站上也有指向勘误表的链接。读者可以通过勘误表让我们知道本书中出现的印刷问题、错误和其他问题。勘误在网站上立刻可以看到,我们将进行检查和确认。O’Reilly也会在本书未来的印刷中以及Safari网站上改正这些错误,尽快地为读者带来更好的体验。我们希望在未来版本的jQuery发行后更新本书,在以后的版本中采纳读者的建议和批评。

本书使用下列排版约定:

斜体

表示互联网地址,例如,域名和URL,以及新术语的定义。

等宽字体

表示应该逐字输入的命令行和选项;程序中的名称和关键字,包括方法名称、变量名称和类名;HTML元素标记、开关、属性(attribute)、键值、函数、类型、命名空间、模块、属性(property)、参数、值、对象、事件、事件处理程序、宏、文件内容或者命令输出。

加粗等宽字体

表示程序代码行中需要强调的部分。

斜体等宽字体

表示文本应该由用户提供的值代替。

注意


这个图标用来表示一个提示、建议或一般的说明。

警告


这个图标用来说明一个警告或注意事项。

本书的目的是帮助你完成自己的工作,一般来说,你可以将本书的代码用在自己的程序和文档中。除非复制大部分代码,否则你没有必要得到我们的许可。例如,编写一个使用本书中多处代码的程序不需要许可,销售或者分发O’Reilly书籍中示例的CD-ROM则需要许可。引用本书中的文字和示例代码不需要许可,但是将本书中的大量示例代码用于你的产品文档需要许可。

我们重视但并不要求归属权。归属权通常包括书名、作者、出版社和ISBN编码。例如“jQuery Cookbook, by Cody Lindley. Copyright 2010 Cody Lindley, 978-0-596-15977-1”。如果你感觉代码示例的使用超出了正当使用或者上述授权的范围,可以与我们联系(permissions@oreilly.com)。

Safari联机丛书是一个按需的数字图书馆,你可以搜索超过7500种技术和创意参考书以及视频,快速地查找你所需要的答案。

订阅之后,你可以在线阅读图书馆中的任意页面,观看任何视频,在你的手机和移动设备上阅读书籍;在新书付印之前先睹为快,独家查阅编写中的手稿以及作者的反馈。你还可以复制和粘贴代码样例、组织收藏夹、下载章节、将关键部分记入书签、评论、打印页面,另外还能从许多省时的特性中获益。

O’Reilly Media已经将本书上传到Safari联机丛书服务。在http://my.safaribooksonline.com上免费注册,就可以访问本书及其O’Reilly和其他出版社类似主题书籍的数码版本。

读者可以信件形式向出版商提出有关本书的评论和问题,地址及电话如下:

O’Reilly Media, Inc.

1005 Gravenstein Highway North

Sebastopol, CA 95472

800-998-9938 (in the United States or Canada)

707-829-0515 (international or local)

707-829-0104 (fax)

关于本书的评论或者技术问题,可以发送电子邮件到如下邮箱:

bookquestions@oreilly.com

有关我们的书籍、课程、会议和新闻的更多信息可以参见我们的网站(http://www.oreilly.com)。

——Rebecca Murphey和Cody Lindley

[1] 译注:recipe在英文中既有“菜谱”之意(与书名相符),又有“秘诀”之意。


Cody Lindley

既然你已经选择了一本有关jQuery的“食谱”,本书作者基本就可以假定你对jQuery的定义和功能有了大致的认识。坦白说,“食谱”通常是为寻求加强已有知识基础的读者所编写的。因此,本书使用了问题-解决方案-讨论的编排方式,快速地介绍常见问题的解决方案。但是,如果你是一位jQuery新手,不要把本书抛诸脑后,认为第1章是老生常谈,这一章就是专为新手所写的。

如果你需要复习,或者只有很少或者完全没有jQuery的知识,第1章将帮助你学习jQuery的概要知识(其他章节假定你已经了解了这些基础知识)。现在,从实际出发,如果你对JavaScript和DOM完全没有了解,可能应该退后一步,问问自己:在对JavaScript核心语言及其与DOM之间的关系没有基本理解的情况下,学习jQuery是否可行。我的建议是在接触jQuery之前,先认真学习DOM和JavaScript的核心知识。我强烈建议将David Flanagan编著的《JavaScript: The Definitive Guide》(http://oreilly.com/catalog/9780596000486,O’Reilly出版)一书作为阅读本书之前的入门读物。但是,如果你试图在学习DOM和JavaScript之前就开始jQuery的学习,也不要让我的一家之言阻挡了脚步。许多人都通过jQuery学到了这些技术的有用知识。虽然这样做不理想,但是只要我们勇敢面对,仍然可以实现学习的目的。

说了这么多,现在我们来看看jQuery的正式定义和功能的简单描述:

jQuery是一个开放源码的JavaScript程序库,简化了HTML文档(更准确地说是文档对象模型(Document Object Model,DOM))与JavaScript之间的交互。

用通俗的话说,也为了让守旧的JavaScript黑客明白,jQuery将动态HTML(DHTML)变得极其简单。具体地说,jQuery简化了HTML文档遍历和操纵、浏览器事件处理、DOM动画、Ajax交互和跨浏览器JavaScript开发。

理解了jQuery的正式含义之后,我们接下来研究选择使用jQuery的原因。

在“食谱”中谈论jQuery的优点似乎有点傻,尤其是在你已选择阅读这本“食谱”,很可能已经意识到这些优点的情况下。

所以,虽然这么做就像在唱诗班面前传道,但是我们仍然要简单地看看开发人员选择使用jQuery的原因。通过在研究“怎么做”之前先解释“为什么”,能够促进你对jQuery基础知识的掌握。

在jQuery案例的构造中,我不打算将jQuery与其竞争者作比较来提高jQuery的重要性。这是因为,我相信这方面还没有真正的直接竞争者。而且,我相信jQuery是当今唯一同时满足设计师和程序员需求的程序库。从这一方面说,jQuery是独一无二的。

市场上充斥着声名狼藉的JavaScript程序库和框架,但是我绝对相信,每个产品都有自己合适的用途和价值。进行广泛的比较很愚蠢,但是人们总是这么做,连我自己也不能免俗。所有的程序库都有价值,哪一个更胜一筹取决于谁使用它以及如何使用它,而不是它实际上能做什么。而且,根据我的观察,考虑到JavaScript开发的目标广泛,各种JavaScript程序库之间的微小差别根本不值一提。所以,我们不再进一步进行哲学方面的探讨了,而是列出能够支持选择jQuery的一组特性:

我认为,使jQuery不同于其他解决方案的是上述特性的结合,而不是单一特性。作为JavaScript工具,整个jQuery程序包是无以匹敌的。

jQuery的原则是“用更少的代码做更多的事”。这一原则可以进一步分为三个概念:

详细了解这三个概念是编写你自己的jQuery代码和扩展本书中学到的秘诀的基础。下面详细地解释这些概念。

1.寻找一些元素并对其进行某些处理

更具体地讲,这条原则是指在DOM中找到一组元素,然后对这组元素进行某种处理。例如,研究一下这样的场景:你想要对用户隐藏一个<div>元素,在隐含的<div>中加载一些新的文本内容,修改<div>的属性,最后让隐藏的<div>再次可见。

上面的最后一句话转换成的jQuery代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
</head>
<body>
<div>old content</div>
<script>
//隐藏页面上的所有div
jQuery('div').hide();

//更新所有div中包含的文本
jQuery('div').text('new content');

//为所有div添加值为updatedContent的class属性
jQuery('div').addClass("updatedContent");

//显示页面上的所有div
jQuery('div').show();

</script>
</body>
</html>

我们逐条查看这4条jQuery语句:

如果现在这些jQuery代码还让你觉得深奥,也没有关系。我们将在本章的第一个秘诀中介绍这些基础知识。另外,从这个代码示例中,你需要了解的是jQuery“找到一些元素并对其进行某些处理”的概念。在读例子中,用jQuery函数(jQuery())找出HTML页面中所有的<div>元素,然后用jQuery方法对它们进行了一些处理(例如,hide()text()addClass()show())。

2.链

jQuery的构造方式允许jQuery方法链。例如,为什么不在找到元素之后,将该元素上的操作链接起来呢?上一个代码示例阐述了“找到一些元素并对其进行某些处理”的概念,它可以用链改写为一条JavaScript命令。

利用链,下面的代码原来如下:

//隐藏页面上的所有div
jQuery('div').hide();

//更新所有div中包含的文本
jQuery('div').text('new content');

//为所有div添加值为updatedContent的class属性
jQuery('div').addClass("updatedContent");

//显示页面上的所有div
jQuery('div').show();

更改后的代码如下:

jQuery('div').hide().text('new content').addClass("updatedContent").show();

或者加上缩进和换行,如下所示:

jQuery('div')
   .hide()
   .text('new content')
   .addClass("updatedContent")
   .show();

简而言之,链允许你在目前用jQuery函数选择(当前用jQuery功能包装起来)的元素上应用无限的jQuery方法链。在后台,每当应用jQuery方法之前,总是返回以前选择的元素,使链能够继续下去。在未来的秘诀中你将会看到,因为插件也以这种方式构造(返回包装的元素),所以使用插件也不会破坏这一链条。

虽然并非显而易见,但是根据对代码的研究,通过一次性选择一组DOM元素,由jQuery方法以链的方式进行多次操作,能够减少处理开销。避免不必要的DOM遍历是网页性能改进的关键部分,一定要尽可能重用或者缓存选中的DOM元素集。

3.jQuery包装器集

大部分时候,如果jQuery很复杂,你会使用所谓的“包装器”。换句话说,你会从一个HTML页面上选择一组用jQuery功能包装的DOM元素。我个人常常将其称为“包装器集”或者“包装集”,因为它是一组由jQuery功能包装的元素。有时候这种包装器集包含单个DOM元素,其他时候则包含多个元素,甚至还有包装器集没有包含任何元素的情况。在这种情况下,jQuery提供的方法/属性在空包装器集中将会“无提示”地失败,这就可以避免不必要的if语句。

现在,以我们用于解释“寻找一些元素并对其进行某些处理”的代码为基础,如果在网页上添加几个<div>元素,你认为会发生什么情况呢?在下面这段更新过的代码示例中,添加了三个<div>元素,这样网页上一共有4个<div>元素:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<script type="text/JavaScript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js"></script> </head>
<body>
<div>old content</div>
<div>old content</div>
<div>old content</div>
<div>old content</div>
<script>
//隐藏页面上的所有div
jQuery('div').hide().text('new content').addClass("updatedContent").show();

</script>
</body>
</html>

你在这里没有显式编写任何循环代码,但是猜猜看会怎么样?jQuery扫描网页,将所有<div>元素放在包装器集中,这样我所使用的jQuery方法在集合中的每个DOM元素上执行(亦称隐式迭代)。例如,.hide()方法实际上应用到集合中的每个元素。所以,如果再次查看代码,就会发现每个方法都应用到页面上的每个<div>元素,就像你编写了一个循环在每个DOM元素上调用各个jQuery方法一样。更新后的代码示例将导致页面中的所有<div>被隐藏,更新文本内容,指定一个新的类值,然后再次显示。

对包装器集和默认的循环系统(隐式迭代)的理解对于围绕循环的高级概念是至关重要的。你只要记住,在真正进行更多的循环(例如,jQuery('div').each(function(){})之前,已经发生了简单的循环。你也可以这样看:包装器中的每个元素一般都会被所调用的jQuery方法所改变。

还要记住一点,在以后的章节中你将会学习到,某些情况下只有第一个元素(而不是包装器集中的所有元素)受到jQuery方法(例如,attr())的影响。

毫无疑问,在我开始接触jQuery时,选择它作为我的JavaSript程序库的主要原因只是因为它的文档很好(以及大量的插件)。后来,我意识到自己爱上jQuery的另一个原因是:它的API按照合乎逻辑的分类进行组织。只要查看API的组织方式,我就能缩小所需功能的范围。

在你真正开始使用jQuery之前,我建议你访问在线文档(http://docs.jquery.com/Main-Page),简单地了解一下API的组织方式。理解了API的组织方式,你就能更快地在文档中找到你所需要的信息,考虑到编写一个jQuery解决方案有许多不同的方法,这实在是一个巨大的优势。由于一个问题有许多解决方案,因此健全的API组织方式能帮助你更全心全意地投入实现之中。这里将重申API的组织方式,建议你记住API的大纲,至少记住第一级分类。

在我们开始学习一系列基本的jQuery秘诀之前,我想提醒一下:本章介绍的秘诀是相互依赖的。也就是说,从第一个秘诀到最后一个的顺序遵循合乎逻辑的知识结构,对于首次接触这些秘诀的读者,我建议从1.1节到1.17节顺序阅读。

你打算在一个网页上使用jQuery JavaScript程序库。

目前,在网页中嵌入jQuery程序库有两种理想的解决方案:

包含jQuery JavaScript程序库和包含其他外部JavaScript文件没有什么不同。你只要使用HTML <script>元素并提供src=""属性的值(URL或者目录路径),你所链接的外部文件就将包含在网页中。例如,下面的模板包含了jQuery程序库,可以用后者启动任何jQuery项目:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
</head>
<body>
<script type="text/JavaScript">
   alert('jQuery ' + jQuery.fn.jquery);
</script>
</body>
</html>

注意,我将使用Google托管的jQuery精简版,并强烈建议公开网页使用这一方法。但是,精简代码中JavaScript错误的调试不理想。在代码开发期间,或者在生产网站上,使用来自Google的非精简版本进行调试可能更容易发现JavaScript错误。关于Google托管的jQuery版本的更多信息,可以访问Ajax程序库API网站:http://code.google.com/apis/ajaxlibs/

你当然也可以自己安装一个jQuery代码副本。但是,在大部分情况下这很愚蠢,因为Google已经为你托管了一个很好的版本。使用Google托管的jQuery,你可以得益于一个可靠、高速且在全球都能访问的jQuery版本。而且,你还能够受益于降低的延迟、获得更高的并行性和更好的缓存。当然,没有Google的解决方案,你也能实现这一点,但是很可能要支付一点钱。

现在,不管出于什么原因,你可能不愿意使用Google托管的jQuery版本,而想要jQuery的自定义版本,也可能你的使用方式不需要(或者没有)互联网连接。或者,你可能认为Google是“统治者”,因为自己的控制欲和阴谋论而不愿意听命于它。对于不需要或者不愿意使用Google托管的jQuery代码的人们,可以从jQuery.com(http://docs.jquery.com/Downloading-jQuery)下载jQuery,将其安装到你自己的服务器或者本地文件系统上。按照我在本秘诀中提供的模板,你只要用指向你下载的jQuery JavaScript文件位置的URL或者目录路径替换src属性值就可以了。

采用无干扰式JavaScript方法论的现代JavaScript应用程序通常只在DOM完全加载之后才执行JavaScript。实际情况是,任何DOM遍历和操纵都要求在操作之前必须加载DOM。需要一种手段来确定客户端(最常见的是Web浏览器)何时完成DOM的加载(这时图片和SWF文件等资源可能还没有完全加载)。如果在这种情况下使用window.onload事件,包括所有资源的整个文档完全加载之后才能触发onload事件,这对大部分Web冲浪者来说太费时间。需要一个事件,告诉我们何时可以遍历和操纵DOM。

jQuery提供ready()方法,这是一个定制的事件处理程序,通常与DOM的文档对象绑定。ready()方法的参数是一个函数,后者包含在DOM可以遍历和操纵时执行的JavaScript代码。下面是一个简单的例子,在DOM就绪而页面还未完全加载时打开一个alert()窗口:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
  jQuery(document).ready(function(){//DOM not loaded, must use ready event
    alert(jQuery('p').text());
  });
</script>
</head>
<body>
<p>The DOM is ready!</p>
</body>
</html>

jQuery用ready()事件处理程序方法来代替JavaScript核心的window.onload事件。可以根据需要多次使用它。使用这个定制事件时,建议将它放在样式表声明和包含文件之后,这样能够确保ready()事件执行任何jQuery或JavaScript代码之前,所有元素属性都已经正确定义。

此外,jQuery函数本身提供使用jQuery定制的ready事件的快捷方式。使用这个快捷方式,下面的alert()示例可以改写为:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
  jQuery(function(){ //DOM未加载,必须使用就绪事件
    alert(jQuery('p').text());
  });
</script>
</head>
<body>
<p>The DOM is ready!</p>
</body>
</html>

这个定制的jQuery事件只有在JavaScript必须嵌入到页面顶端的文档流并封装在<head>元素里时才有必要。我只需将所有JavaScript文件包含和内联代码放在<body>结束元素之前,就能避免使用ready()事件,这么做有两个原因。

首先,现代优化技术已经断言,当JavaScript放在页面解析的最后由浏览器加载时,页面的加载就会变得更快。换句话说,如果你将JavaScript放在网页的最后,浏览器将先加载之前的所有内容,然后才加载JavaScript,这是一件好事,因为大部分浏览器通常会暂停其他加载活动,等待JavaScipt引擎编译网页中包含的JavaScipt。从某种程度上说,将JavaScript放在网页文档的开头会形成瓶颈。我知道某些情况下将JavaScript放在<head>元素中更加简单,但坦诚说,我从未发现绝对必须这么做的情况。我在开发中因为将JavaScript放在页面最后而造成的所有困难都很容易克服,比起得到的优化效果,这些努力也都是值得的。

其次,如果提高网页的速度是我们的目标,为什么要为简单地将代码放到页面最后就能解决的问题而加入更多的功能呢?如果让我在较多代码和较少代码之间做出选择,我选择使用较少的代码。不使用ready()事件减少了代码量,而代码越少,网页运行得总是越快。

基于这些理由,在下面这个例子中,alert()代码没有使用ready()事件:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>The DOM is ready!</p>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
   alert(jQuery('p').text());//提示DOM已经加载
</script>
</body>
</html>

注意,我已经将所有的JavaScript放在<body>结束元素之前。HTML文档中的任何其他标记应该都在JavaScript之前。

你需要选择一个DOM元素或者一组DOM元素,以便用jQuery方法作用于这些元素。

当你需要从DOM中选择元素时,jQuery提供两种备选方案。这两种选项都要求使用jQuery函数(jQuery()或其别名$())。第一种选项使用CSS选择器和自定义选择器,这是最常用和最清晰的解决方案。通过向jQuery函数传递一个包含选择器表达式的字符串参数,该函数将遍历DOM并查找表达式定义的DOM节点。下面的代码是一个例子,选择HTML文档中的所有<a>元素:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
   //用警告框显示页面上有6个元素
   alert('Page contains ' + jQuery('a').length + ' <a> elements!');
</script>
</body>
</html>

如果你在Web浏览器中运行这个HTML页面,就会看到这段代码执行一个浏览器alert()方法,告诉我们该页面包含6个<a>元素。我首先选择所有的<a>元素,然后用length属性返回jQuery包装器集中元素的数量,并将其传递给alert()方法。

你应该知道,这里使用的jQuery函数的第一个参数能够接受多个表达式,只要在传递给jQuery函数的第一个字符串参数中用逗号分隔多个选择器就行了。下面是一个例子:

jQuery('selector1, selector2, selector3').length;

选择DOM元素的第二种选项是向jQuery函数传递DOM元素的实际JavaScript引用,这种选项不如第一种常用。举个例子,下面的代码将选择HTML文档中的所有<a>元素。注意,我传递给jQuery函数的是一个用getElementsByTagName DOM方法收集到的<a>元素数组。这个例子的结果和前一个代码示例完全相同:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body bgcolor="yellow"> <!-- yes the attribute is depreciated, I know, roll
with it -->
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
   //用警告框提示页面上有6个元素
   alert('Page contains ' + jQuery(document.getElementsByTagName('a')).length +
' <a> Elements, And has a '
   + jQuery(document.body).attr('bgcolor') + ' background');
</script>
</body>
</html>

众所周知,jQuery能够胜任繁重的工作,这在某种程度上是因为选择器引擎Sizzle(http://sizzlejs.com/),该引擎能够从HTML文档中选择DOM元素。虽然向jQuery函数传递DOM引用在必要的时候是个很好的选择,当它并不是jQuery进入众人视野的原因。选择器拥有的许多强大的选项才是jQuery与众不同之处。

在本书余下的部分中,你将会学习到各种强大和健壮的选择器,对这些选择器的功能都要彻底地理解。这些知识在未来的jQuery编程工作中将使你获益匪浅。

你需要引用在另一个DOM元素或者文档上下文中的单个DOM元素或者一组DOM元素,以便用jQuery方法操作这些元素。

当传递CSS表达式时,jQuery函数还有第二个参数,这个参数告诉jQuery函数应该在那个上下文中根据表达式搜索DOM元素。在这种情况下,第二个参数可以是一个DOM引用、jQuery包装器或者文档。在下面的代码中有12个<input>元素。注意我是如何根据<form>元素确定具体的上下文,仅选择特定的<input>元素的:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>

<form>
<input name="" type="checkbox" />
<input name="" type="radio" />
<input name="" type="text" />
<input name="" type="button" />
</form>

<form>
<input name="" type="checkbox" />
<input name="" type="radio" />
<input name="" type="text" />
<input name="" type="button" />
</form>

<input name="" type="checkbox" />
<input name="" type="radio" />
<input name="" type="text" />
<input name="" type="button" />

<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">

//使用上下文包装器在所有表单元素中搜索,警告框中显示"selected 8 inputs"
alert('selected ' + jQuery('input',$('form')).length + ' inputs');

//用DOM引用作为上下文,在第一个表单元素中搜索,警告框中显示"selected 4 inputs"
alert('selected ' + jQuery('input',document.forms[0]).length + ' inputs');
//用表达式搜索body元素中的所有输入元素,警告框中显示"selected 12 inputs"
alert('selected ' + jQuery('input','body').length + ' inputs');
</script>
</body>
</html>

正如1.4.2节所提到的,也可以将文档作为搜索的上下文。例如,可以在一个XHR请求(Ajax)发回的XML文档的上下文中搜索。你可以在第16章中看到更多相关的细节。

在jQuery包装器集中有一组选中的DOM元素,但是打算从集合中删除不匹配新指定表达式的元素,以创建一个新的操作元素集合。

jQuery过滤器方法用于DOM元素的jQuery包装器集,可以排除不符合指定表达式的元素。简言之,可以用filter()方法过滤当前元素集,这是过滤器方法与jQuery查找方法的重要区别,查找方法通过寻找(使用新的选择器变量)新元素(包括当前包装器集的子元素)来缩小DOM元素的包装器集。

为了理解过滤器方法,我们来看看下面的代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<a href="#" class="external">link</a>
<a href="#" class="external">link</a>
<a href="#"></a>
<a href="#" class="external">link</a>
<a href="#" class="external">link</a>
<a href="#"></a></li>
<a href="#">link</a>
<a href="#">link</a>
<a href="#">link</a>
<a href="#">link</a>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
   //在警告框中显示集合中还有4个元素
     alert(jQuery('a').filter('.external').length + ' external links');
</script>
</body>
</html>

上述代码示例中的HTML页面包含一个有10个<a>元素的网页,其中的外部链接指定了类名external。使用jQuery函数选择页面上的所有<a>元素。然后,利用过滤器方法删除原始集合中所有class属性值不为external的元素。在filter()方法修改初始DOM元素集之后,调用length属性,该属性会告诉我在应用过滤器之后,新的集合中有多少个元素。

filter()方法传递一个用于过滤包装器集的函数也是可行的。前一个代码示例中filter()方法的参数是一个字符串表达式,现在用一个函数来代替它:

alert(
  jQuery('a')
    .filter(function(index){ return $(this).hasClass('external');})
    .length + ' external links'
);

注意,现在传递给filter()方法的是一个匿名函数。调用这个函数的上下文与当前元素相同,也就是说当在函数中使用$(this)时,实际应用的是包装器集中的每个DOM元素。在函数中,我将检查包装器集中每个<a>元素的类值(hasClass())是否为external。如果是,返回逻辑真值,该元素保留在集合中;否则(返回逻辑假值),从集合中删除元素。也可以这么理解:如果函数返回假值,则删除该元素。如果函数返回其他值,该元素就会留在包装器集中。

你可能已经注意到:这里向函数传递了一个名为index的参数,但是并不打算使用它。在必要的时候,这个参数可用来以数字形式指出jQuery包装器集中元素的索引。

你选择了一组(或者一个)DOM元素,希望在当前选中元素的上下文中找到后代(子)元素。

使用.find()方法,根据当前集合及其后代的上下文创建一个新的元素包装器集。例如,假设你有一个包含多个段落的网页,这些段落中封装的是需要强调(以斜体显示)的单词。如果你只想选择<p>元素中包含的<em>元素,可以使用如下代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>Ut ad videntur facilisis <em>elit</em> cum. Nibh insitam erat facit
<em>saepius</em> magna. Nam ex liber iriure et imperdiet. Et mirum eros
iis te habent. </p>
<p>Claram claritatem eu amet dignissim magna. Dignissim quam elit facer eros
illum. Et qui ex esse <em>tincidunt</em> anteposuerit. Nulla nam odio ii
vulputate feugait.</p>
<p>In quis <em>laoreet</em> te legunt euismod. Claritatem <em>consuetudium</em>
wisi sit velit facilisi.</p>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
 //在警告框中显示<p>元素中找到的斜体单词总数
    alert('The three paragraphs in all contain ' +
    jQuery('p').find('em').length + '
italic elements');
</script>
</body>
</html>

记住,也可以改写上述代码,将上下文引用作为jQuery函数的第二个参数:

alert('The three paragraphs in all contain ' + jQuery('em',$('p')).length +
' italic elements');

此外,值得一提的是,最后这两个代码示例只是为了说明的目的而编写的。使用CSS选择器表达式选择包含在<p>元素(祖先)中的斜体元素(后代)即使不实用,也是更符合逻辑的。

alert('The three paragraphs in all contain ' + jQuery('p em').length +
' italic elements');

jQuery .find()方法可以用于根据当前DOM元素集及其子元素的上下文创建新的元素集。人们往往混淆filter().find()方法的用法。记住两者差异的最简手段是记住.find()将操作/选择当前集合的子元素,而.filter()只操作当前元素集。换句话说,如果你想将当前包装器集当作上下文,进一步选择集合中元素的子元素,从而改变当前的包装器集,就应该使用.find()。如果你只想过滤当前包装集,获得集合中当前DOM元素的一个新子集,则使用.filter()。归纳起来就是:find()返回子元素,而filter()只过滤当前包装集里的元素。

需要删除用于一组元素的破坏性jQuery方法(例如,filter()find()),以便将集合恢复到破坏性方法使用之前的状态,就像破坏性方法从来没有调用过一样。

jQuery提供end()方法,可以用它返回使用破坏性方法之前选择的一组DOM元素。为了理解end()方法,我们来看看下面的HTML。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>text</p>
<p class="middle">Middle <span>text</span></p>
<p>text</p>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
   alert(jQuery('p').filter('.middle').length); //alerts 1
   alert(jQuery('p').filter('.middle').end().length); //alerts 3
   alert(jQuery('p').filter('.middle').find('span')
.end().end().length); //alerts 3
</script>
</body>
</html>

代码中的第一条alert()语句包含的jQuery语句搜索文档中所有<p>元素,然后对选中的<p>元素应用filter()方法,仅选择类为middle的元素。length属性报告了集合中剩下元素的数量:

alert(jQuery('p').filter('.middle').length); //提示1

下一条alert()语句使用了end()方法。这里所做的操作和前一条语句相同,唯一例外的是撤消了filter()方法,返回filter()方法使用前包装器集包含的元素:

alert(jQuery('p').filter('.middle').end().length); //提示3

最后一条alert()语句示范了如何两次使用end()方法移除filter()find()破坏性修改,使包装器集返回其原始构成的方法:

alert(jQuery('p').filter('.middle').find('span').end().end().length); //提示3

如果使用end()方法之前没有执行破坏性操作,将会返回一个空集。破坏性操作指的是任何改变匹配jQuery元素集合的操作,也就是返回jQuery对象的任何遍历或者操纵方法,包括add()andSelf()children()closes()filter()find()map()next()
nextAll()not()parent()parents()prev()prevAll()siblings()slice()
clone()appendTo()prependTo()insertBefore()insertAfter()replaceAll()

你刚刚对一组元素进行操纵,获得新的元素集。但是,你想同时操作前一个元素集和当前元素集。

可以用andSelf()方法合并前一个DOM元素选择集和当前选择集。例如,在下面的代码中,首先选择页面上的所有<div>元素。接下来,操纵这组元素,寻找<div>元素中的所有<p>元素。现在,为了同时操作<div><div>中找到的<p>元素,可以用andSelf()方法将<div>包含到当前集合。如果省略andSelf(),边框颜色将只应用到<p>元素:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<div>
<p>Paragraph</p>
<p>Paragraph</p>
</div>
<script type="text/JavaScript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
   jQuery('div').find('p').andSelf().css('border','1px solid #993300');
</script>
</body>
</html>

记住,当使用andSelf()方法时,它只向当前操作集合中添加前一个集合,而不是以前选择的所有集合。

你已经选择了一组DOM元素,根据选择集在DOM结构树中的位置,你打算遍历DOM获得一个新的元素集以供操作。

jQuery提供一组方法,可以根据当前选择的DOM元素的上下文遍历DOM。

例如,查看如下的HTML片段:

<div>
<ul>
<li><a href="#">link</a></li>
<li><a href="#">link</a></li>
<li><a href="#">link</a></li>
<li><a href="#">link</a></li>
</ul>
</div>

现在,用:eq()索引自定义选择器选择第2个<li>元素:

//根据索引选择<li>集合中的第2个元素,索引从0开始
jQuery('li:eq(1)');

现在有一个上下文——HTML结构中的一个出发点。出发点是第2个<li>元素。从这里开始,可以到达任何位置——对,几乎任何位置。

让我们来看看,使用几个jQuery提供的DOM遍历方法能够到达哪里。代码中的注释就能说明问题:

jQuery('li:eq(1)').next() //选择第三个<li>
jQuery('li:eq(1)').prev() //选择第一个<li>
jQuery('li:eq(1)').parent() //选择<ul>
jQuery('li:eq(1)').parent().children() //选择所有<li>
jQuery('li:eq(1)').nextAll() //选择第二个<li>之后的所有<li>
jQuery('li:eq(1)').prevAll() //选择第二个<li>之前的所有<li>

记住,这些遍历方法产生新的包装器集,使用end()可以返回前一个包装器集。

目前为止介绍的遍历方法展示了简单遍历。要了解遍历,还必须知道另外两个重要的概念。

第一个概念可能显而易见——遍历方法可以链接。我们再来看看前面出现过的jQuery语句:

jQuery('li:eq(1)').parent().children() //选择所有<li>

注意,我已经从第二个<li>元素遍历到父元素<ui>,然后再从父元素选择<ui>的所有子元素。jQuery包装器集现在包含的是<ui>中的所有<li>元素。当然,这只是为了说明遍历方法而设计的例子。如果我们想要的是一个只有<li>元素的包装器集,从一开始就选择所有<li>元素要简单得多(例如,jQuery('li'))。

处理遍历方法时需要牢记的第二个概念是许多方法都接受一个可选的参数,用于过滤选择集。我们仍然用链接的示例来说明这一点,看看如何修改代码,以便只选择最后一个<li>元素。别忘了,这个例子仅仅用来说明遍历方法如何传递用于选择特定元素的表达式:

jQuery('li:eq(1)').parent().children(':last') //选择最后一个 <li>

jQuery还提供了其他遍历方法,在这里不作介绍。完整的列表和文档可以参阅http://docs.jquery.com/Traversing。在本书里你将会看到这些遍历方法。

你打算创建一个或者多个新的DOM元素,立刻选中这些元素加以操作,然后把它们注入到DOM中。

你可能还不清楚,jQuery函数是多功能的,根据你发送的不同参数结构,一个函数能以不同的方式运行。如果以原始HTML文本字符串为参数调用函数,它将立刻创建这些元素。例如,下列语句将创建一个包装在<p>元素中的<a>元素,在<p><a>元素中还封装了一个文本节点:

jQuery('<p><a>jQuery</a></p>');

创建了元素之后,还可以使用jQuery方法对它进行进一步的操作,就像一开始就从现有的HTML文档中选择了<p>元素似的。例如,可以用.find()方法选择<a>元素,并设置它的一个属性。在下面的代码中,将其href属性设置为http://www.jquery.com

jQuery('<p><a>jQuery</a></p>').find('a').attr('href','http://www.jquery.com');

这很棒,对吗?目前为止,所做的只不过是在运行中创建元素并在代码中进行操纵,实际上还可以做得更好。可以说,实际上还没有真正改变当前加载的DOM。想做到这一点,就必须使用jQuery提供的操纵方法。下面是在HTML文档上下文中的代码。在这段代码中将创建元素、在这些元素上进行操作,然后用操纵方法appendTo()将它们插入DOM中:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
jQuery('<p><a>jQuery</a></p>').find('a').attr('href','http://www.jquery.com')
 .end().appendTo('body');
</script>
</body>
</html>

请注意这里是如何使用end()方法撤消find()方法的,这样当调用appendTo()方法时,它将在DOM中附加包含在初始包装器集中的元素。

在本秘诀中,向jQuery函数传递原始HTML字符串,这一参数被方法用来在运行中创建DOM元素。 还可以简单地向jQuery函数传递一个由DOM方法createElement()创建的DOM对象:

jQuery(document.createElement('p')).appendTo('body'); //在页面中添加一个空白的p元素

当然,如果用一个包含多个元素的HTML字符串就能正常工作,这么做可能就显得麻烦了,如何选择取决于具体的用法。

值得一提的是,这里只是用appendTo()方法简单地介绍了操纵方法的基础。除了appendTo()方法之外,还有如下操纵方法:

你想从DOM中删除元素。

remove()方法可以用于从DOM中删除选中的元素集及其子元素。请看如下代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h3>Anchors</h3>
<a href='#'>Anchor Element</a>
<a href='#'>Anchor Element</a>
<a href='#'>Anchor Element</a>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
 jQuery('a').remove();
</script>
</body>
</html>

当把上述代码加载到浏览器中时,锚元素将留在页面中,直到JavaScript执行。一旦使用remove()方法从DOM中删除所有锚元素,该页面在外观上只包含一个<h3>元素。也可以向方法传递一个表达式,过滤需要删除的元素集。例如,代码可以进行如下改写,只删除具有特殊类的锚:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h3>Anchors</h3>
<a href='#' class='remove'>Anchor Element</a>
<a href='#'>Anchor Element</a>
<a href='#' class="remove">Anchor Element</a>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
 jQuery('a').remove('.remove');
</script>
</body>
</html>

当使用jQuery方法时,必须记住两点:

你需要用新的DOM节点代替DOM中的现有节点。

使用replaceWith()方法,可以选择一组DOM元素进行替换。在下面的代码示例中,使用replaceWith()方法,将class属性为remove的所有<li>元素替换为新的DOM结构:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<ul>
<li class='remove'>name</li>
<li>name</li>
<li class='remove'>name</li>
<li class='remove'>name</li>
<li>name</li>
<li class='remove'>name</li>
<li>name</li>
<li class='remove'>name</li>
</ul>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
 jQuery('li.remove').replaceWith('<li>removed</li>');
</script>
</body>
</html>

添加到DOM中的新DOM结构作为一个字符串参数传递给relaceWith()方法。在例子中,所有<li>元素(包括子元素)都被新的结构<li>remove</li>替代。

jQuery提供一个方向相反的方法replaceAll(),该方法的功能与relaceWith()方法相同,但是参数位置颠倒。例如,可以将本秘诀中的代码改写成:

jQuery('<li>removed</li>').replaceAll('li.remove');

这里将HTML字符串传递给jQuery函数,然后使用replaceAll()方法选择想要删除和替换的DOM节点及其子节点。

你需要克隆/复制DOM的一部分。

jQuery提供clone()方法复制DOM元素。它的用法很简单,只要用jQuery函数选择DOM元素,然后在选择的元素集上调用clone()方法就可以了。结果是返回用于链接的DOM结构的一个副本,而不是原来选中的DOM元素。在下面的代码中,将克隆一个<ul>元素,然后用插入方法appendTo()将这个副本附加到DOM中。实际上,在页面上插入了与现有的<ul>完全相同的一个结构:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<ul>
<li>list</li>
<li>list</li>
<li>list</li>
<li>list</li>
</ul>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
 jQuery('ul').clone().appendTo('body');
</script>
</body>
</html>

克隆方法对在DOM中移动DOM片段非常方便,尤其是在你打算复制和移动的不仅是DOM元素而且包括附加到克隆的DOM元素中的事件时。认真看看下面的HTML和jQuery:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<ul id="a">
<li>list</li>
<li>list</li>
<li>list</li>
<li>list</li>
</ul>
<ul id="b"></ul>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
 jQuery('ul#a li')
   .click(function(){alert('List Item Clicked')})
   .parent()
     .clone(true)
        .find('li')
        .appendTo('#b')
     .end()
   .end()
   .remove();
</script>
</body>
</html>

如果在浏览器中运行这段代码,它将克隆页面上附加了单击事件的<li>元素,将新克隆的元素(包括时间)插入空的<ul>中,然后删除克隆的<ul>元素。

这对于新的jQuery开发人员来说可能有点不可思议,所以我们一起来逐步观察这段代码,以便解释这个链式方法:

1.jQuery('ul#a li')=选择id属性为a<ui>元素,然后选择该<ui>元素里的所有<li>元素。

2..click(function(){alert('List Item Clicked')})=为每个<li>添加一个单击事件。

3..parent()=将选择集改为<ul>元素,遍历DOM。

4..clone(true)=克隆<ui>元素和所有子元素,包括附加到克隆元素中的任何事件。这通过传递给clone()方法一个布尔值true完成。

5..find('li')=现在,在克隆元素中,将元素集改为仅包含在克隆<ui>元素中的<li>元素。

6..appendTo('#b')=获取选中的克隆<li>元素,并将它们放置在id属性为b<ui>元素中。

7..end()=返回前一个元素选择集,该集即克隆的<ui>元素。

8..end()= 返回前一个元素选择集——克隆的原始<ul>元素。

9..remove() =删除原始的<ul>元素。

对于复杂的jQuery语句来说,理解如何操纵选中的元素集或者返回前一个选择集都是至关重要的。

你已经用jQuery函数选择了一个DOM元素,需要获取或者设置该元素的属性值。

jQuery提供attr()方法以获取和设置属性值。在下面的代码中,将设置<a>元素的href属性值,然后获取该值:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<a>jquery.com</a>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
</script>
<script type="text/JavaScript">
//提示jQuery主页URL
alert(
   jQuery('a').attr('href','http://www.jquery.com').attr('href')
);
</script>
</body>
</html>

在上述代码示例中你可以看到,选择HTML元素中仅有的<a>元素,设置它的href属性,然后用单一的属性名作为参数调用相同的attr()方法获取属性值。如果文档中有多个<a>元素, attr()方法将访问第一个匹配的元素。当代码加载到浏览器时,将用alert()方法显示设置的href属性值。

现在,因为大部分元素都有多个属性,所以也可以用单个attr()方法设置多个属性。例如,可以用一个对象代替两个字符串参数作为attr()方法的参数,设置前一个例子中的title属性:

jQuery('a').attr({'href':'http://www.jquery.com','title':'jquery.com'}).attr('href')

和添加属性功能相伴的是删除属性及其值的功能。removeAttr()方法可以用来从HTML元素中删除属性。要使用这个方法,只要传递代表要删除的属性值的字符串即可(例如,jQuery('a').removeAttr('title'))。

除了attr()方法之外,jQuery为使用HTML元素class属性提供了一组很特殊的方法。因为class属性可能包含多个值(例如,class="class1 class2 class3"),所以可以使用这些独特的属性方法管理这些类值。

下面列出的就是这些jQuery方法:

addClass()

用新的类/值更新class属性值,包括任何已经设置的类。

hasClass()

检查特定类的class属性值。

removeClass()

class属性中删除特定的类,同时保持已经设置的任何值。

toggleClass()

如果特定类不存在则添加,如果存在则删除该类。

你需要获取或者设置当前网页中的一块HTML内容。

jQuery提供html()方法,用于获取和设置HTML元素块(或者DOM结构)。在下面的代码中,使用这个方法设置HTML元素中找到的<p>元素的HTML值,然后获取该值:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p></p>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
</script>
<script type="text/JavaScript">
jQuery('p').html('<strong>Hello World</strong>, I am a <em>&lt;p&gt;</em> element.');
alert(jQuery('p').html());
</script>
</body>
</html>

在浏览器中运行这段代码将造成浏览器修改<p>元素中包含的HTML内容,这些内容是使用html()方法设置的,然后用html()方法获取相同内容。

这个方法使用DOM的innerHTML属性获取和设置HTML块。你还应该知道,html()在XML文档中不可用(但是可用于XHTML文档)。

你需要获取或者设置包含在一个或多个HTML元素中的文本。

jQuery提供text()方法,用于获取和设置元素的文本内容。在下面的代码中,使用这个方法设置HTML文档中<p>元素的文本值,然后获取该值:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p></p>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
</script>
<script type="text/JavaScript">
   jQuery('p').text('Hello World, I am a <p> element.');
   alert(jQuery('p').text());
</script>
</body>
</html>

在浏览器中运行上述代码将造成浏览器修改<p>元素的内容,用text()方法设置这些内容,然后用text()方法读取。

重要的一点是,要记住text()方法与html()方法没有什么不同,唯一的例外是text()方法将对HTML进行转义(将<>替换为HTML实体)。这意味着,如果在text()方法的字符串参数中放入标记,该方法会将这些标记转换为HTML实体(&lt;&gt;)。

你希望使用快捷方式$别名代替全局命名空间名称(jQuery)的输入,而又不用担心全局冲突。

这里提供的解决方案是创建一个匿名的自调用函数,将jQuery对象传递给这个函数,然后将$字符当作指向jQuery对象的一个参数。

例如,所有jQuery代码可以封装在如下的自调用函数中:

(function($){ //用$参数创建私有作用域的函数
   //私有作用域和$的使用无须担心冲突
})(jQuery); //调用无名函数并将其传递给jQuery对象

实际上,这里所做的就是将对jQuery的全局引用传递给一个创建私有作用域的函数。如果没有这么做,而是直接在全局作用域中使用简写的$别名,就必须假定包含在HTML文档中的其他脚本(或者未来包含的脚本)都没有使用$字符,这是有一定风险的。当你能够创建自己的私有作用域时,何必去冒险呢?

这样做的另一个好处是包含在匿名的自调用函数中的代码将运行于自己的私有作用域中。可以确信,在该函数中放置的任何内容都决不会和全局作用域中编写的任何其他JavaScript代码发生冲突。同样,为什么要冒编程冲突的风险?你要做的只不过是创建自己的私有作用域。


相关图书

深入浅出Spring Boot 3.x
深入浅出Spring Boot 3.x
JavaScript核心原理:规范、逻辑与设计
JavaScript核心原理:规范、逻辑与设计
JavaScript入门经典(第7版)
JavaScript入门经典(第7版)
JavaScript函数式编程指南
JavaScript函数式编程指南
PHP、MySQL和JavaScript入门经典(第6版)
PHP、MySQL和JavaScript入门经典(第6版)
JavaScript学习指南(第3版)
JavaScript学习指南(第3版)

相关文章

相关课程