jQuery2-开发秘籍-全-

jQuery2 开发秘籍(全)

原文:zh.annas-archive.org/md5/44BEA83CD04274AA076F60D831F59B04

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

jQuery 2.0 开发手册 将为您提供许多可重用的代码示例,以使用最流行的客户端框架 jQuery 创建常见和独特的网站和网络应用程序元素、插件和界面。按照每个示例的逐步说明不仅会为您提供可用的代码,还会提供扩展和改进代码所需的理解。

本书涵盖内容

第一章,文档对象模型操作,讲述如何使用 jQuery 在客户端操作网页的 HTML 代码,从而创建丰富的视觉用户体验。

第二章,利用 jQuery 事件与用户交互,利用 jQuery 的力量来检测和响应用户交互,从而创建直观的用户界面。

第三章,使用 AJAX 和 JSON 加载和操作动态内容,利用 jQuery 的 AJAX 功能与 JSON 格式的数据,通过更新内容而无需刷新页面,为页面注入生机。

第四章,用 jQuery 特效添加吸引人的视觉效果,解释如何使用 jQuery 的特效和基本动画为网站或网络应用添加光泽,创建难忘的设计。

第五章,表单处理,讲述如何利用 jQuery 构建健壮的客户端验证和直观的网页表单用户体验。

第六章,用户界面,讲述如何打破常规,从零开始创建强大直观的界面,并通过高水平的互动吸引用户。

第七章,用户界面动画,讲述如何扩展 jQuery 的内置动画,并将 CSS 与 jQuery 结合起来创建可与任何网站一起使用的精彩网站模块。

第八章,理解插件开发,解释如何创建可重用的代码,为一系列常见的网站和网络应用程序问题提供解决方案。

第九章,jQuery UI,讲述如何利用 jQuery 的用户界面库来为网站或网络应用程序增添引人注目且用户友好的页面元素和界面。

第十章,使用 jQuery Mobile,讲述如何使用 jQuery 强大的移动框架创建移动和跨平台的网站。

本书所需条件

在本书中的所有配方中,您将需要一个 IDE 来编写 JavaScript、HTML 和 CSS 代码,以及一个 Web 浏览器来执行您的代码。对于本书中一些更高级的配方,您将需要一个运行 MySQL 和 PHP 的 Web 服务器。

本书适合谁

这本书适用于那些对 jQuery 还很新,并希望学习一些基础知识的人,或者熟悉 jQuery 并希望扩展他们的知识,并为他们的网站或 Web 应用创建一些高级组件的人。这本书是所有技能和经验水平的 Web 开发人员的绝佳资源。

习惯用法

在这本书中,您会发现一些区分不同信息类型的文本样式。这里有一些这些样式的示例,以及它们的含义解释。

文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄显示如下:"任何 $(function(){ }); 中的代码将在页面加载时由 jQuery 自动执行。"

代码块设置如下:

<!DOCTYPE html>
<html>
<head>
  <title>Creating DOM elements</title>
  <script src="img/jquery.min.js"></script>
  <script></script>
</head>
<body>
<div id="container">
  <ul id="myList">
    <li>List Item 1</li>
    <li>List Item 2</li>
    <li>List Item 3</li>
  </ul>
</div>
</body>
</html>

新术语重要词汇以粗体显示。屏幕上显示的文字,如菜单或对话框中的文字,都会以这种方式出现在文本中:"这将向用户显示一个弹出窗口,其中包含消息您确定要删除此用户吗?"

注意

警告或重要说明将显示在这样的框中。

提示

提示和技巧会以这种方式出现。

第一章:文档对象模型操作

在本章中,我们将涵盖:

  • 选择元素

  • 查找和选择兄弟元素

  • 创建 DOM 元素

  • 将内容插入元素中

  • 修改 DOM 元素属性

  • 添加和删除 CSS 类以动态更改其样式

  • 通过更改其属性来启用和禁用按钮

  • 在页面中更新图像

  • 填充列表元素

  • 了解分页

  • 删除 DOM 元素

  • 重复使用 DOM 元素

介绍

本章介绍了 jQuery 的基本原理—查找、选择和操作 DOM 元素。jQuery 让 JavaScript 开发人员可以使用各种方法轻松选择单个或多个 HTML 页面元素。

一旦开发人员选择了这些元素,jQuery 提供了操作每个元素的能力,以通过属性修改(如样式、禁用和类)创建更丰富的用户体验。

选择元素

有许多种方法可以使用 jQuery 来选择 DOM 元素。我们将在这里探讨主要方法。对于熟悉 CSS 的开发人员,可以在使用 jQuery 选择元素时使用相同的语法(即 #content.content 等)。

准备工作

在您选择的文本编辑器或 IDE 中打开一个空白的 HTML 文档。确保您已经下载了最新版本的 jQuery,并且可以轻松地包含到此 HTML 文档中。在本章中创建新的 HTML 文件时,请确保它们都位于与 jQuery 库文件相同的目录中,这样就可以轻松地包含到 HTML 文档中。

如何做…

要了解如何使用 jQuery 选择各种 DOM 元素,请执行以下每个配方步骤:

  1. 使用以下 HTML 和 JavaScript 代码创建一个网页:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Selecting Elements with jQuery</title>
       <script src="img/jquery.min.js"></script>
       <script>
          $(function(){
             var content = $("#content"); //Select the content div
             var span = $(".span-element"); //Select the span element
             var listelements = $("li"); //Select all the list elements
          });
       </script>
    </head>
    <body>
    <div class="division-container">Some text within a div which has a class</div>
    <div id="content">Some text within a div which has an ID attribute</div>
    <a href="#">A link</a>
    <a href="#" rel="dofollow">A second link</a>
    <ul class="info-list">
       <li>List Item 1</li>
       <li>List Item 2</li>
       <li>List Item 3</li>
    </ul>
    <button>Button 1</button>
    <span class="span-element">Span 1</span>
    </body>
    </html>
    
  2. 要选择其中任何元素,请使用 jQuery 的 $() 函数。我们可以将此函数与要选择的元素的标识符或 CSS 选择器结合使用;例如,其 HTML 标签 li 和 ID #content 或类 .content

提示

下载示例代码

您可以从您在 www.packtpub.com 购买的所有 Packt 图书中下载示例代码文件。如果您在其他地方购买了本书,您可以访问 www.packtpub.com/support 并注册,将文件直接通过电子邮件发送给您。

工作原理…

选择 DOM 元素的最简单方法是通过其 ID。我们知道 HTML 文档中的所有 ID 应该是唯一的;因此,通过使用其 ID 选择元素,您将选择一个单独的元素。

关于前面的 HTML 文档,如果您想要选择具有 ID content<div>,则可以使用以下 jQuery 代码来选择它:

$(function(){
   var content = $('#content');
});

这将使 DOM 元素在 content 变量中可用。关于这意味着什么的更多内容在本章后面进行讨论。

注意

$(function(){ });中的任何代码将在页面加载时由 jQuery 自动执行。

我们也可以以相同的方式通过它们的类选择元素。 代码与前面的示例非常相似,唯一不同的是我们使用类前缀(.)而不是 ID 前缀(),如下所示:

$(function(){
   var span = $('.span-element');
});

我们不仅可以根据我们指定的标识符(如类或 ID)选择元素,还可以根据它们的标签名称选择元素。 如果您想选择页面中的所有li元素,您将使用$('li'),如下所示:

$(function(){
   var listelements = $('li');
   var i = 1;
   listelements.each(function(){
      console.log("Loop: " + i);
      i++;
   });
});

前面的示例使用 jQuery 选择器来选择页面中的所有列表元素。 为了证明listelements现在包含多个元素,我们遍历这些元素,并在控制台输出一些信息。

注意

.each() 是一个 jQuery 函数。 在第三章 使用 AJAX 和 JSON 加载和操作动态内容中学习更多关于它的用法。

前面示例的控制台输出如下:

Loop: 1
Loop: 2
Loop: 3

注意

您可以根据所选浏览器的不同方式来访问 JavaScript 控制台:

  • ChromeCtrl + Shift + JMaccommand + option + J

  • 互联网浏览器F12

  • FirefoxCtrl + Shift + K

更多内容…

还可以根据其他属性(如reldisabled属性)选择元素。

以下代码向我们展示了如何选择具有rel属性为nofollow的锚元素:

$(function(){
   var nofollow = $('a[rel="nofollow"]');
});

另请参阅

  • 查找和选择兄弟元素

查找和选择兄弟元素

您可能并不总是知道需要选择的具体元素。 您可能只知道其父级,因此,您将需要搜索父级中的元素,以找到您要查找的特定元素。 本示例将向您展示不同的方式通过它们的父级查找元素。

准备工作

打开您的文本编辑器或 IDE,其中包含最新版本的 jQuery,并准备被包含在您将作为本示例的一部分创建的 HTML 页面中。

如何操作…

要了解 jQuery 可以帮助您根据父元素搜索 DOM 元素的各种方式,请执行以下每个步骤:

  1. 创建包含以下 HTML 和 JavaScript 代码的网页:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Finding and selecting sibling elements</title>
       <script src="img/jquery.min.js"></script>
       <script>
          $(function(){
             var element1 = $('#content .top .top-left'); //Select the top left division element
             var element2 = $('.parent').find('a'); //Select the anchor element
             var element3 = $('.parent').find('.grandchild'); //Select the grandchild element
          });
       </script>
    </head>
    <body>
    <div class="division-container">Some text <span>within</span> a div <span>which</span> has a many <span>span</span> elements.</div>
    <div id="content">
       <div class="top">
          <div class="top-left">Left</div>
          <div class="top-right">Right</div>
       </div>
    </div>
    <ul class="info-list">
       <li>List Item 1</li>
       <li>List Item 2</li>
       <li>List Item 3</li>
    </ul>
    <ul class="second-info-list">
       <li>Second List Item 1</li>
       <li>Second List Item 2</li>
       <li>Second List Item 3</li>
    </ul>
    <div class="parent">
       <div class="child">
          <div class="grandchild">
             <a href="#">A Link</a>
          </div>
       </div>
    </div>
    </body>
    </html>
    
  2. 这段代码使用了多个类名,就像在 CSS 中选择 HTML 子元素一样。 或者,您可以在父元素上使用 jQuery 的find()函数进行搜索。

工作原理…

选择子元素最简单的方法是使用与 CSS 中相同的选择器(即 .classname .anotherclass)。 需要注意的是,你不总是知道要查找的同级元素的确切位置。 如果是这种情况,我们可以使用有用的 jQuery 的 find() 函数。 jQuery 的 find() 函数将在指定的父元素内查找你要查找的同级元素。

基于“如何做”部分内的 HTML,以下 JavaScript 演示了如何直接访问子元素,方法就像在 CSS 中那样:

$(function(){
   var element1 = $('#content .top .top-left');
});

这将使 DOM 元素在 content 变量内可用。 更多关于这个意思的内容将在本章后面讨论。

要查找不知道确切位置的子元素,我们可以使用以下 JavaScript 来定位 <div class="grandchild"> 元素内的锚点:

$(function(){
   var element2 = $('.parent').find('a');
});

请注意,你只需指定父选择器和要查找的元素。find() 方法简单地基于指定的父元素遍历 DOM,直到找到你要查找的元素或没有元素可以检查为止。 你也可以在 find() 方法中使用 ID 和类名以及 HTML 标记。

还有更多...

你还可以在 $() 内使用 CSS3 选择器,如 :first-child:last-child 来帮助你选择所需的 DOM 元素。

另请参阅

  • 选择元素

创建 DOM 元素

为了创建丰富且交互式的用户界面,我们需要能够动态向网页添加 DOM 元素。 元素可能需要基于用户交互或其他事件(如页面加载)而添加到网页。

准备工作

对于这个步骤,你需要另一个空白的 HTML 文件。 在与前一个食谱文件相同的目录内创建一个名为 recipe-3.html 的新 HTML 文件。

如何做…

学习如何通过以下步骤使用 jQuery 创建 DOM 元素:

  1. 将以下 HTML 代码添加到你的 recipe-3.html 文件中,以创建一个带有无序列表并包含 jQuery 库的基本 HTML 页面:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Creating DOM elements</title>
       <script src="img/jquery.min.js"></script>
       <script></script>
    </head>
    <body>
    <div id="container">
       <ul id="myList">
          <li>List Item 1</li>
          <li>List Item 2</li>
          <li>List Item 3</li>
       </ul>
    </div>
    </body>
    </html>
    
  2. 将以下 JavaScript 添加到 HTML 文档头部的脚本标签内。 以下 JavaScript 代码将使用 jQuery 的 after()insertAfter() 函数在 #myList 元素之后向 DOM 添加两个按钮:

    $(function(){
       $('#myList').after("<button>Button 1</button>");
       $('<button>Button 2</button>').insertAfter("#myList");
    });
    

工作原理…

要动态向文档的任何部分添加 DOM 元素,我们可以使用 jQuery 的 append()addAfter()after()addBefore()before() 函数。after()insertAfter() 函数本质上执行相同的操作;不同之处在于指定表达式的顺序。 insertBefore()before() 也是一样。

基于“如何做”部分的 HTML 文件,以下 JavaScript 将在无序列表元素之后添加两个按钮元素:

$(function(){
   $('#myList').after("<button>Button 1</button>");
   $('<button>Button 2</button>').insertAfter("#myList");
});

一旦执行了前面的 JavaScript,浏览器中呈现的 HTML 将被修改如下:

<!DOCTYPE html>
<html>
<head>
   <title> Creating DOM elements</title>
   </head>
<body>
<div id="container">
   <ul id="myList">
      <li>List Item 1</li>
      <li>List Item 2</li>
      <li>List Item 3</li>
   </ul>
      <button>Button 2</button>
      <button>Button 1</button>
</div>
</body>
</html>

请注意,即使第二个按钮是最后添加的,它也是 HTML 中的第一个。这是因为我们已经指定了按钮应该在无序列表元素之后插入。.before().insertBefore() 方法的工作原理完全相同,唯一的区别是按钮元素会位于无序列表元素之上。

动态网页和 Web 应用程序的一个常见需求是能够向列表中添加新项目。最佳方法是使用 .append() 函数:

$(function(){
   $('#myList').append("<li>List Item 4</li>");
});

此 JavaScript 将向 #myList 无序列表元素底部添加带有文本 List Item 4 的新列表项。或者,也可以使用 prepend() 函数将列表项插入列表顶部。

还有更多...

jQuery 为开发者提供了许多向 DOM 中添加、追加、插入和更新元素的方式,这在单个示例中无法演示完全。通过阅读 jQuery 文档,确保你了解了替代方法。

另请参阅

  • 向元素插入内容

  • 移除 DOM 元素

  • 重用 DOM 元素

向元素插入内容

交互式和动态的 Web 应用程序和网站不仅要求 Web 开发者能够创建 DOM 元素,还要求开发者能够添加动态内容。这可以通过另一组 jQuery 函数轻松实现。

准备工作

创建一个名为 recipe-4.html 的空白 HTML 文档,并确保你可以在该 HTML 文档中包含最新版本的 jQuery。

如何做到…

通过执行以下每个步骤学习如何将内容动态添加到 DOM 中:

  1. 将以下代码添加到你新创建的 HTML 文档中,这将创建一个简单的 HTML 网页:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Insert content into an element</title>
       <script src="img/jquery.min.js"></script>
       <script>
    
       </script>
    </head>
    <body>
    <div id="container">
       <p>Here is some current HTML content</p>
    </div>
    <textarea id="myTextarea"></textarea>
    </body>
    </html>
    
  2. 在文档头部的脚本标签中插入以下 JavaScript 代码。此代码将在各个点将不同的 HTML 内容和元素注入到 DOM 中。

    $(function(){
       //Remove the container elements current HTML
       $('#container').html("<p>I have replaced the all the HTML within the #container element</p>");
    
       //Add some more HTML to the beginning of the container element
       $('#container').prepend("<p>Another paragraph that has been prepended.</p>");
    
       //Add a button to the end of the container element after all other HTML content
       $('#container').append("<button>A Button Appended</button>");
    
       //Add some text into the text area element
       $('#myTextarea').val("Added some text using .text()");
    });
    

工作原理...

向元素添加内容的最快方法是使用 html() 函数。通过将字符串作为参数提供给该函数,它将用提供的字符串替换所选元素的当前 DOM 内容。如果没有提供字符串,则该函数将返回元素的 DOM 内容格式化为 HTML 字符串。

除了替换元素的内容之外,我们还可以使用 append()prepend() 分别在当前内容的末尾和开头添加附加内容。此外,我们还有其他可用的函数,例如 text(),它将在插入元素之前解码任何 HTML。出于这个原因,text() 函数通常用于文本区域。

基于前一节提供的 HTML,我们可以使用之前讨论过的 jQuery 函数来修改 #container 元素的内容,如下所示:

$(function(){
$('#container').html("<p>I have replaced the all the HTML within the #container element</p>");

$('#container').prepend("<p>Another paragraph that has been prepended.</p>");

$('#container').append("<button>A Button Appended</button>");

$('#myTextarea').val("Added some text using .text()");
});

在执行了这些函数之后,浏览器渲染的 HTML 文件将会被转换,如下所示:

<!DOCTYPE html>
<html>
<head>
   <title>Insert content into an element</title>
</head>
<body>
<div id="container">
   <p>Another paragraph that has been prepended.</p><p>I have replaced the all the HTML within the #container element</p>
   <button>A Button Appended</button>
</div>
<textarea id="myTextarea">Added some text using .text()</textarea>
</body>
</html>

另请参阅

  • 创建 DOM 元素

修改 DOM 元素属性

我们可以使用 jQuery 动态修改元素属性,如类、样式和禁用,这意味着可以视觉上改变和改变一系列 HTML 元素的功能。

准备工作

再次说明,此配方需要额外的空白 HTML 文档。创建一个名为 recipe-5.html 的文件,并准备好打开并进行编辑。

如何实现…

学习如何通过执行以下每个步骤来更改 DOM 元素的属性:

  1. 将以下 HTML 代码添加到你的空白 recipe-5.html 文件中,以创建一个带有两种类型输入的基本 HTML 页面:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Modifying DOM element attributes and properties</title>
       <script src="img/jquery.min.js"></script>
       <script>
    
       </script>
    </head>
    <body>
    <input type="checkbox" />
    <input type="text" />
    </body>
    </html>
    
  2. 在上述 HTML 代码中,将以下 JavaScript 代码添加到 script 标签内,以禁用输入、修改其值并选中复选框:

    $(function(){
       //Set the checkbox to be checked
       $('input[type="checkbox"]').prop('checked', true);
       //Disable any text inputs
       $('input[type="text"]').prop('disabled', true);
       //Change the value of any text inputs
       $('input[type="text"]').val("This is a new Value!");
    });
    

工作原理…

jQuery 提供了一个 prop() 函数,如果没有指定值,则会检索指定的属性,如果提供了值,则会修改所选元素上的指定属性。这可以用来更改诸如复选框上的 checked 或文本输入上的 disabled 属性值。我们可以使用 prop() 函数来修改文本输入的值;但是,最好使用专门用于此任务的 val() 函数。

通常,这将根据用户触发的事件来完成,但为了尽可能简单地说明这一点,以下 JavaScript 在页面加载时执行此操作:

$(function(){
   $('input[type="checkbox"]').prop('checked', true);
});

此 JavaScript 将检查页面中的每个类型为 checkbox 的输入。类似地,我们可以仅通过少量修改来更改文本输入的禁用状态:

$(function(){
   $('input[type="text"]').prop('disabled', true);
});

我们还可以使用 val() 函数来使用以下 JavaScript 向每个文本输入添加一些文本:

$(function(){
    $('input[type="text"]').val("This is a new Value!");
});

通常,你可以使用 jQuery 来链式调用函数。你可以通过内联使用这两个函数(即,$('input[type="text"]').prop('disabled', true).val("This is a new Value!");)来实现前面两个操作,并且它们会依次执行。

另请参阅

  • 通过更改它们的属性启用和禁用按钮

  • 添加和删除 CSS 类以动态更改它们的样式

添加和删除 CSS 类以动态更改它们的样式

jQuery 随附了类操作函数,以便允许开发人员轻松更改任何 HTML 元素的样式。

准备工作

要使元素样式更改有用,我们首先需要在 HTML 文档中声明一些样式。以下 HTML 代码具有一系列我们可以使用的样式和元素,以说明 jQuery 的此功能:

<!DOCTYPE html>
<html>
<head>
   <title>Add and remove CSS classes to dynamically change their style</title>
   <script src="img/jquery.min.js"></script>
   <script></script>
   <style type="text/css">
      .green {
         background-color: #008000;
         color: #FFFFFF;
      }
      .red {
         background-color: #FF0000;
         color: #FFFFFF;
      }
      .yellow {
         background-color: #FFFF00;
         color: #000000;
      }
   </style>
</head>
<body>
   <p id="sometext">
      Here is some text that can have different styles applied to it dynamically</p>
   <button id="green-btn">Green</button>
   <button id="red-btn">Red</button>
   <button id="yellow-btn">Yellow</button>
</body>
</html>

在此 HTML 代码中,我们有三个具有各自唯一 ID 的按钮。我们还有一个具有 ID 的段落。定义了三个 CSS 类:greenredyellow。通过 jQuery,我们可以监听其中任一按钮的点击,然后动态地将其中一个类应用到段落元素上。

如果您保存此 HTML 文件并在浏览器中打开它,您应该会看到以下网页:

准备工作

如何做…

  1. 在您刚创建的 HTML 页面的脚本标签中添加以下 JavaScript 代码:

    $(function(){
       //Listen for a click event on the green button
    $('#green-btn').click(function(){
       //When the green button has been clicked
       //Remove all classes current on the #sometext paragraph
       $('#sometext').removeClass();
       //Add the .green class to the #sometext paragraph
       $('#sometext').addClass('green');
    });
       //Listen for a click on the red button
    $('#red-btn').click(function(){
       //When the red button has been clicked
       //Remove all classes from the #sometext paragraph
       $('#sometext').removeClass(); 
       //Add the .red class to the #sometext paragraph 
       $('#sometext').addClass('red');
       });
       //Listen for a click on the yellow button
       $('#yellow-btn').click(function(){
          //When the yellow button has been clicked
          //Remove all classes from the #sometext paragraph
       $('#sometext').removeClass();
       //Add the .yellow class to the #sometext paragraph 
       $('#sometext').addClass('yellow');
       });
    });
    
  2. 在浏览器中打开 HTML 文档现在将允许您通过选择三个可用按钮中的任意一个来更改 #sometext 段落的样式。

工作原理…

jQuery 允许我们通过使用 click() 函数将点击事件处理程序附加到任何元素。然后,我们可以通过将函数作为参数传递给 click() 方法来执行我们选择的一组代码。要向元素添加类,我们可以使用 addClass() 函数,并将类名作为字符串参数提供。此函数将指定的类名添加到所选元素中。

jQuery 还为我们提供了 removeClass() 函数。这使我们可以通过向 removeClass() 提供一个字符串来从元素中删除特定的类,或者当没有提供字符串时,它将从所选元素中删除所有类。我们将需要使用此功能,以防止当任一按钮被多次点击时多个类被添加到段落元素中。

下面的截图展示了点击黄色按钮后此网页的情况:

工作原理…

另请参阅

  • 修改 DOM 元素属性

  • 通过更改其属性来启用和禁用按钮

通过更改其属性来启用和禁用按钮

动态启用和禁用按钮的能力在诸如将数据保存到 Web 服务器之类的情况下特别有用。为了防止用户在请求正在进行并且客户端正在等待响应时进行多次保存请求,您可以动态禁用保存按钮。一旦客户端从 Web 服务器接收到响应,您可以重新启用保存按钮。

在简单情况下,例如在用户输入搜索词之后启用搜索按钮,此功能也可能非常有效。这使用户清楚地知道,除非已输入搜索词,否则他们无法搜索。

准备工作

创建一个名为 recipe-7.html 的空白 HTML 文档,并准备好进行编辑。

如何做…

  1. 以下 HTML 代码创建了一个带有搜索输入和搜索按钮的网页,默认情况下搜索按钮被禁用。将以下代码添加到 recipe-7.html 中:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Enable and disable buttons by changing their properties </title>
       <script src="img/jquery.min.js"></script>
       <script>
    
       </script>
    </head>
    <body>
       <input type="text" id="search-input" />
       <button id="search-btn" disabled>Search</button>
    </body>
    </html>
    
  2. 保存并在浏览器中打开此 HTML 将为您提供一个非常简单的网页,其中只有一个输入和一个已禁用的按钮,如下截图所示:如何做…

  3. 在先前创建的 HTML 文档的 head 部分的 script 标签中添加以下 JavaScript:

    $(function(){
       //Listen for a key up event on the search input
    $('#search-input').keyup(function(){
         //When a user presses and releases a key
         //Check to see if the length of the inputted 
         //data is greater than 2 
         if ($(this).val().length > 2) {
            //If the input length is greater than 
            //two then we enable the search button
            $('#search-btn').prop("disabled", false);
       } else {
          //If the input length is equal to 2 or less we disable the search button
          $('#search-btn').prop("disabled", true);
       }
    });
    });
    
  4. 在网络浏览器中打开这个页面将会给你一个输入框和一个禁用的搜索按钮,直到你在搜索输入框中输入一些文本。当文本输入到搜索框中,并且文本长度大于两个字符时,搜索按钮将变为可用状态。

工作原理…

我们的目标是一旦用户在搜索输入框中输入了一些文本,就启用搜索按钮。为此,我们需要将 .keyup() 事件处理程序附加到搜索输入框上。这将允许我们在用户输入文本时执行一些代码。通过将一个函数作为keyup()函数的参数提供,我们可以检查输入的数据。如果输入的数据长度为两个或更多字符(因为少于三个字符的搜索可能会有些模糊),我们可以启用搜索按钮。

使用以下 JavaScript,我们能够监听数据输入,检查输入长度,并根据此来启用或禁用搜索按钮:

$(function(){
$('#search-input').keyup(function(){
   if ($(this).val().length > 2) {
      $('#search-btn').prop("disabled", false);
   } else {
   $('#search-btn').prop("disabled", true);
   }
});
});

首先,我们使用 $('#search-input').keyup();keyup事件附加到搜索输入框上,引用其 ID。然后,在回调函数中,我们能够使用 $(this) 来检查当前输入文本的长度,它指的是我们附加keyup事件的元素。val() 函数然后获取输入的文本,我们可以使用 length 属性来获取其长度。使用 if/else 语句,我们可以决定搜索按钮是否需要启用或禁用。

要启用或禁用搜索按钮,我们使用 jQuery 的 prop() 函数,并将 disabled 属性设置为 truefalse

另请参见

  • 修改 DOM 元素属性

  • 添加和删除 CSS 类以动态更改它们的样式

更新页面内的图片

jQuery 允许开发者在网页上动态更改图片。这个配方将向你展示如何做到这一点,并且还会向你展示如何使用时间戳来防止浏览器使用缓存的图片,这在动态交换图片时经常会遇到问题。

准备工作

对于这个配方,你需要四张不同的图片。确保你有四张小图片,分别命名为black.pngred.pngblue.pnggreen.png

如何操作…

要理解如何使用 jQuery 来更改图片,完成以下每个步骤:

  1. 在一个易于访问的目录中创建一个名为recipe-8.html的文件,并在其中添加以下 HTML 代码:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Change an image source and tackle browser caching to ensure it is always updated</title>
       <script src="img/jquery.min.js"></script>
       <script>
    
       </script>
    </head>
    <body>
       <img src="img/black.png" id="square" />
       <div>
          <button id="red-btn">Red</button>
          <button id="green-btn">Green</button>
          <button id="blue-btn">Blue</button>
       </div>
    </body>
    </html>
    
  2. 在创建recipe-8.html文件的目录中,创建另一个名为images的目录,在其中添加以下四个图片:

    • black.png

    • red.png

    • blue.png

    • green.png

  3. recipe-8.html<script></script> 标签中添加以下 JavaScript:

    $(function(){
       //Listen for a click on the red button
    $('#red-btn').click(function(){
       //When the red button has been clicked, change the source of the #square image to be the red PNG
       $('#square').prop("src", "images/red.png");
    });
       //Listen for a click on the green button
    $('#green-btn').click(function(){
       //When the green button has been clicked, change the source of the #square image to be the green PNG
       $('#square').prop("src", "images/green.png");
    });
    //Listen for a click on the blue button
    $('#blue-btn').click(function(){
       //When the blue button has been clicked, change the source of the #square image to be the blue PNG
       $('#square').prop("src", "images/blue.png");
    });
    });
    
  4. 在浏览器中打开此网页将允许您根据点击的按钮来更改显示图像的源,从默认的 black.png 更改为另一个源。

如何运作…

要更改图像的源,我们可以使用 jQuery 的 prop() 函数并为 src 属性指定新的图像名称。为此,当我们使用我们的 HTML 代码创建的按钮之一被点击时,使用 .click() 为每个按钮附加点击事件处理程序,引用按钮的 ID,然后在 click() 回调函数中执行.prop() 并指定适当的图像源,如下所示:

$(function(){
$('#red-btn').click(function(){
   $('#square').prop("src", "images/red.png");
});

$('#green-btn').click(function(){
   $('#square').prop("src", "images/green.png");
});

$('#blue-btn').click(function(){
   $('#square').prop("src", "images/blue.png");
});
});

还有更多…

这个示例说明了 jQuery 开发人员如何使用一个非常简单的例子轻松更改图像源的方式。在这种实现中更有可能被使用的是在 Web 应用程序中,例如当用户选择他们的头像时可以上传图像的情况。

传统上,用户将被呈现其当前头像的预览,然后能够从计算机中选择要上传的图像。使用 AJAX,网页可以将这个新图像发送到服务器;然后服务器可以处理并保存这个图像并响应客户端网页。然后,网页可以使用 jQuery 的 prop() 方法更新当前预览与新上传的图像,并创建一个无需刷新页面就能显示新图像的无缝过渡。

当服务器使用与旧图像相同的文件名时,就会出现问题。这在用户只能拥有一个头像的情况下经常发生;为了简单起见,头像图像会使用用户的唯一 ID 保存(例如,123.png)。

当服务器用新的图像文件名响应客户端时,由于文件名相同,浏览器会认为它是同一图像。这可能会导致浏览器使用头像图像的缓存版本,这将是旧图像。为了防止这种情况发生,我们可以在图像文件名前添加一个时间戳。这将使浏览器将图像视为新图像,并强制它加载新图像。我们可以修改上述 JavaScript 以实现以下内容:

$(function(){
$('#red-btn').click(function(){
     $('#square').prop("src", "images/red.png?t=" + new Date().getTime());
});

$('#green-btn').click(function(){
     $('#square').prop("src", "images/green.png?t=" + new Date().getTime());
});

$('#blue-btn').click(function(){
     $('#square').prop("src", "images/blue.png?t=" + new Date().getTime());
});
});

使用 JavaScript 的 new Date() 方法,我们创建一个新的日期,该日期将等于当前时间并且时间等于当前时间的毫秒数。然后我们使用 .getTime() 返回毫秒级的时间戳。当源被更新时,它将如下所示:

<img src="img/red.png?t=1371992012690" id="square">

此代码将强制浏览器使用新指定的源重新加载图像,前提是用户在同一毫秒内没有更新他们的图像(实际上是不可能的)。

填充列表元素

列表元素在 Web 上经常使用;它们可以用于显示搜索结果、菜单和导航项等。由于 CSS 的存在,它们不再需要单调,可以通过样式化列表元素使您的数据更加美观。

使用 jQuery,可以动态填充列表元素。这可以直接从 JavaScript 数组通过 AJAX 响应、从 Web 服务器或其他来源获取的数据中完成。

准备工作

创建一个名为recipe-9.html的空白 HTML 文档,并确保它保存在可以包含最新版本 jQuery 的位置。

如何做…

通过执行以下每个步骤,学习如何使用 jQuery 动态填充列表:

  1. 为了演示如何使用 jQuery 填充列表元素,我们将创建一个对象的 JavaScript 数组。在刚刚创建的recipe-9.html中添加以下 HTML 和 JavaScript 代码:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Populating list elements</title>
       <script src="img/jquery.min.js"></script>
       <script type="text/javascript">
          var names = [
             {
                id: 1,
                firstname: 'Leon',
                lastname: 'Revill'
             },
             {
                id: 2,
                firstname: 'Allyce',
                lastname: 'Wolverson'
             },
             {
                id: 3,
                firstname: 'Harry',
                lastname: 'Round'
             },
                {
                   id: 4,
                   firstname: 'Chris',
                   lastname: 'Wilshaw'
                }
             ];
             $(function(){
    
          });
       </script>
    </head>
    <body>
        <ul id="namelist"></ul>
    </body>
    </html>
    

    在我们的 JavaScript 代码顶部,我们已经创建了一个包含一组名称的对象数组。我们将使用这个数组来填充 HTML 代码中的列表元素#namelist

  2. $(function(){})中添加以下 JavaScript 代码,就在 JavaScript 数组的下面。此 JavaScript 将使用我们在准备工作部分中创建的 JavaScript 数组中的对象来填充页面上的列表元素。

    $.each(names, function(index, obj){
    $('#namelist').append("<li>#" + obj.id + " " + obj.firstname + " " + obj.lastname + "</li>");
    });
    

工作原理…

我们使用 jQuery 的$.each()函数来循环遍历names数组中的每个 JavaScript 对象。然后,对于这些对象中的每一个,我们可以创建一个<li>元素,并插入idfirstnamelastname变量的值。最后,我们可以使用 jQuery 的append()函数将列表元素追加到无序列表的末尾。

$.each()函数中,第一个参数是我们希望迭代的数组,第二个参数是我们希望对names数组中的每个对象执行的函数。指定的函数也有两个参数:indexobjindex参数将包含 JavaScript 对象的当前数组索引,obj变量将包含实际的 JavaScript 对象。这两个变量在指定的回调函数中都是可用的。

接着,我们可以引用obj.propertyName(用对象的属性替换propertyName)来访问我们希望使用的对象的特定部分。通过这样做,我们构造一个字符串并将其传递给append()函数,然后将其追加到指定的#nameslist无序列表中。

在浏览器中打开 HTML 页面,你应该看到列表中填充了 JavaScript 数组中的名称,如下所示:

工作原理…

参见

  • 创建 DOM 元素

  • 重用 DOM 元素

理解分页

分页是整理大量数据并将其呈现给用户的行为,分成小的、易于阅读的部分或页面。

结合 jQuery、JavaScript 函数和事件处理程序,我们能够轻松地整理并以页面的形式呈现数据给用户。

准备工作

要创建分页数据集,首先我们需要一些要分页的数据,然后是放置分页数据的位置。使用以下代码创建一个 HTML 页面:

<!DOCTYPE html>
<html>
<head>
   <title>Chapter 1 :: DOM Manipulation</title>
   <script src="img/jquery.min.js"></script>
   <script>
      var animals = [
         {
            id: 1,
            name: 'Dog',
            type: 'Mammal'
         },
         {
            id: 2,
            name: 'Cat',
            type: 'Mammal'
         },
         {
            id: 3,
            name: 'Goat',
            type: 'Mammal'
         },
         {
            id: 4,
            name: 'Lizard',
            type: 'Reptile'
         },
         {
            id: 5,
            name: 'Frog',
            type: 'Amphibian'
         },
         {
            id: 6,
            name: 'Spider',
            type: 'Arachnid'
         },
         {
            id: 7,
            name: 'Crocodile',
            type: 'Reptile'
         },
         {
            id: 8,
            name: 'Tortoise',
            type: 'Reptile'
            },
            {
               id: 9,
               name: 'Barracuda',
               type: 'Fish'
            },
            {
               id: 10,
               name: 'Sheep',
               type: 'Mammal'
            },
            {
               id: 11,
               name: 'Lion',
               type: 'Mammal'
            },
            {
               id: 12,
               name: 'Seal',
               type: 'Mammal'
            }
         ];
      var pageSize = 4;
      var currentPage = 1;
      var pagedResults = [];
      var totalResults = animals.length;
      $(function(){
   });       
   </script>
</head>
<body>
   <ul id="list"></ul>
   <button class="previous"><< Previous</button>
   <button class="next">Next >></button>
</body>
</html>

在此页面的 JavaScript 中,我们声明了一个名为 animals 的大数组对象,表示一组动物。在该数组下面,我们声明了四个更多的变量,这些变量是我们分页 animals 数组所需的:

  • pageSize:这表示我们希望在单个页面上保留的结果数量

  • currentPage:这表示正在显示的当前页面

  • pagedResults:这表示一个包含 animals 数组部分的数组,代表页面

  • totalResults:这表示 animals 数组中的对象数量;在这种情况下,为 12

如何操作…

要创建带有分页的动态列表,请执行以下每个步骤:

  1. 就在 $(function(){}); 之后但仍然在 <script></script> 标签内,添加以下 JavaScript 函数:

    function updateList() {
    //Grab the required section of results from the animals list
    var end = (currentPage * pageSize);
    var start = (end - pageSize);
    pagedResults = animals.slice(start, end);
    //Empty the list element before repopulation
    $('#list').empty();
    
    //Disable the previous button if we are on the first page
    if (currentPage <= 1) {
       $('.previous').prop("disabled", true);
    }
    //Enable the previous button if we are not on the first page
    else {
       $('.previous').prop("disabled", false);
    }
    
    //Disable the next button if there are no more pages
    if ((currentPage * pageSize) >= totalResults) {
       $('.next').prop("disabled", true);
    }
    //Enable the next button if there are results left to page
    else {
       $('.next').prop("disabled", false);
    }
    
    //Loop through the pages results and add them to the list
    $.each(pagedResults, function(index, obj){
       $('#list').append("<li><strong>" + obj.name + "</strong> (" + obj.type + ")</li>");
    });
    }
    
  2. 在前述 HTML 页面中的 $(function(){}); 中添加以下 JavaScript:

    //Populate the list on load
    updateList();
    $('.next').click(function(){
    //Only increase the current page if there are enough results
    if ((currentPage * pageSize) <= totalResults) currentPage++;
    updateList();
    });
    
    $('.previous').click(function(){
    //Only decrease the current page if it is currently greater than 1
    if (currentPage > 1) currentPage--;
    updateList();
    });
    

工作原理…

尽管分页可能看起来相当复杂,但原理上很简单。我们需要使用 jQuery 的 click() 函数来监听下一页和上一页按钮的点击事件。当按下这些按钮时,根据点击的按钮,currentPage 变量要么递增要么递减。之后,updateList() 函数获取 currentPage 值,计算需要从 animals 数组中使用哪个数据部分,用这些数据填充 pagedResults 数组,然后将这些结果加载到 HTML 列表元素 #list 中。

另外,我们需要根据用户当前所在的页面禁用下一页或上一页按钮。如果他们当前正在查看第一页,我们可以使用 jQuery 的 prop() 函数将其 disabled 属性设置为 true 来禁用上一页按钮。如果用户正在查看最后一页(我们的函数可以使用 totalResultscurrentPagepageSize 变量来计算出来),我们需要禁用下一页按钮。

//Populate the list on load
updateList();
$('.next').click(function(){
//Only increase the current page if there are enough results
if ((currentPage * pageSize) <= totalResults) currentPage++;
updateList();
});

$('.previous').click(function(){
//Only decrease the current page if it is currently greater than 1
if (currentPage > 1) currentPage--;
updateList();
});

为了扩展这个有详细注释的代码,我们首先调用一个名为 updateList() 的函数,稍后我们会在这个教程中详细介绍它。

注意

请记住,$(function(){}); 中的任何代码都会在页面加载时执行。

接下来,我们通过将回调函数作为参数传递给下一页按钮来附加点击事件处理程序。对于此事件函数,我们能够指定每次点击下一页按钮时要执行的一些代码。我们指定的代码通过 1 递增 currentPage 变量。如果还有其他页面的数据可用,它会通过形成 ((currentPage * pageSize) <= totalResults) 条件作为 if 语句的一部分来计算这一点。

最后,在此点击函数的一部分中,我们调用先前提到的 updateList() 函数。

我们也对上一页按钮应用相同的逻辑,只是如果当前页面大于一,我们会递减 currentPage 值;因此,有一页可以返回。

$(function(){}); 下面但仍在 <script></script> 标签内,向您的 HTML 页面添加以下 JavaScript 函数:

function updateList() {
//Grab the required section of results from the animals list
var end = (currentPage * pageSize);
var start = (end - pageSize);
pagedResults = animals.slice(start, end);
//Empty the list element before repopulation
$('#list').empty();

//Disable the previous button if we are on the first page
if (currentPage <= 1) {
   $('.previous').prop("disabled", true);
}
//Enable the previous button if we are not on the first page
else {
   $('.previous').prop("disabled", false);
}

//Disable the next button if there are no more pages
if ((currentPage * pageSize) >= totalResults) {
   $('.next').prop("disabled", true);
}
//Enable the next button if there are results left to page
else {
   $('.next').prop("disabled", false);
}

//Loop through the pages results and add them to the list
$.each(pagedResults, function(index, obj){
   $('#list').append("<li><strong>" + obj.name + "</strong> (" + obj.type + ")</li>");
});
}

为了保持良好的实践,再次对代码进行了充分注释。此函数执行的第一个操作是计算它需要使用 animals 数组的哪个部分。一旦计算出起始和结束值(例如,页面一的索引值为 04),它就会使用 JavaScript 的 slice() 函数将此数据从 animals 数组复制到 pagedResults 数组中。

注意

要小心不要使用类似的 JavaScript 的 .splice() 函数,因为这实际上会从 animals 数组中删除数据,并将其复制到 pagedResults 数组中。另外,slice() 接受两个参数:第一个是从数组开始位置开始的零索引数(即,0 表示开始),第二个参数不是数组中的位置,而是从起始点开始的元素数量。

使用所需结果存储在 pagedResults 数组中,它使用 jQuery 的 empty() 函数来清空无序列表 #list 中的任何数据。这是为了准备重新填充列表。否则,当单击下一个或上一个按钮并运行 updateList() 函数时,结果将仅附加到当前列表的末尾而不是替换。

代码的下一部分是确定下一个和上一个按钮是否需要禁用或启用。我们可以通过放置条件 (currentPage <= 1) 来计算是否需要禁用上一页按钮,该条件简单地检查当前页面是否小于或等于一;如果是,则需要禁用上一页按钮;否则,需要启用。这是使用 jQuery 的 prop() 函数完成的,该函数允许我们操作所选元素的属性;在这里,我们将 disabled 属性更改为 truefalse。我们可以通过 ((currentPage * pageSize) >= totalResults) 来确定是否需要禁用下一个按钮,该条件计算出 animals 数组中是否有足够的对象来创建下一页;如果没有,我们禁用按钮,但如果有,我们启用它。

最后,我们使用 jQuery 的 $.each() 函数遍历 pagedResults 数组中的每个对象,并将每个对象的数据附加到页面上的无序列表中的列表元素。

如果在浏览器中打开 HTML 页面,您应该看到与以下示例类似的页面:

工作原理...

在页面加载时,列表会填充为第一页的结果,因为 currentPage 设置为 1,并且 updateList() 函数也设置为在页面加载时运行,这会禁用上一页按钮。

删除 DOM 元素

jQuery 使开发人员可以轻松完全删除 DOM 元素,在创建丰富的用户界面时通常很有用。删除元素的能力在您的界面表示来自数据库的一些信息,并为用户提供删除数据库项目的方式时非常有用。如果此 UI 使用 AJAX 将删除请求发送到 Web 服务器,则需要在客户端反映删除操作并删除表示数据库项目的元素。

准备工作

创建一个空白的 HTML 文档,并将其保存为 recipe-11.html,放在您的计算机上易于访问的位置。

如何做…

学习如何使用 jQuery 删除 DOM 元素,执行以下每个步骤:

  1. 将以下 HTML 代码添加到您刚刚创建的 recipe-11.html 页面中:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Removing DOM elements</title>
       <script src="img/jquery.min.js"></script>
       <script>
    
       </script>
    </head>
    <body>
       <ul id="list">
          <li>Item 1 <button class="remove-btn">X</button></li>
          <li>Item 2 <button class="remove-btn">X</button></li>
          <li>Item 3 <button class="remove-btn">X</button></li>
          <li>Item 4 <button class="remove-btn">X</button></li>
       </ul>
    </body>
    </html>
    
  2. 在前一个 HTML 文档的 <script></script> 标记中,添加以下 JavaScript 代码:

    $(function(){
    //Listen for a click on any of the remove buttons
    $('.remove-btn').click(function(){
       //When a remove button has been clicked
       //Select this buttons parent (the li element) and remove it
       $(this).parent().remove();
    });
    });
    
  3. 在浏览器中打开 HTML 文档,并单击删除按钮以删除所选的列表项。

工作原理…

jQuery 为我们提供了一个 remove() 函数,它将从 DOM 中删除所选元素。在前面提到的情况下,您会有一个列表,其中包含表示数据库中记录的项目。每个列表项都会提供一个删除按钮,允许用户删除所选项目。

在实际情况下,此删除按钮将向 Web 服务器发出 AJAX 请求,等待响应,然后在客户端上删除所选元素。为了保持本示例简单,我们将只查看在客户端上删除元素的 JavaScript 代码,而不使用 AJAX。

注意

第三章,《使用 AJAX 和 JSON 加载和操作动态内容》,包含丰富的 AJAX 配方。

我们可以使用 jQuery 的 click() 函数来监听一个删除按钮的点击事件。然后,我们可以使用 $(this).parent() 来选择我们要删除的 <li> 元素,因为删除按钮是这个列表元素的兄弟元素。然后,我们可以使用不带参数的 remove() 方法来删除所选的列表元素。

另请参阅

  • 创建 DOM 元素

  • 重用 DOM 元素

重用 DOM 元素

当使用 jQuery 动态创建诸如列表项、部分和输入等元素时,能够重用这些元素而无需在 JavaScript 中重新编写它们可能非常有用。相反,复制这些元素并仅修改您希望更改的部分可能更有利。

准备工作

使用您选择的文本编辑器,在易于访问最新版本 jQuery 的位置中创建一个名为 recipe-12.html 的空白 HTML 文档。

如何做…

学习如何通过执行以下每个步骤来重用 DOM 元素:

  1. 在你刚创建的recipe-12.html页面中,添加以下 HTML、CSS 和 JavaScript 代码:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Reusing DOM elements</title>
       <style type="text/css">
          .one {
             background-color: #CCC;
             color: #333;
          }
          .two {
             background-color: lawngreen;
             color: white;
          }
          .three {
             background-color: darkgreen;
             color: white;
          }
          .four {
             background-color: black;
             color: #666;
          }
          .dinosaur {
             background-color: darkred;
             color: red;
          }
       </style>
       <script src="img/jquery.min.js"></script>
       <script>
          var animals = [
             {
                id: 1,
                name: 'Dog',
                type: 'Mammal',
                class: 'one'
             },
             {
                id: 2,
                name: 'Cat',
                type: 'Mammal',
                class: 'one'
             },
             {
                id: 3,
                name: 'Goat',
                type: 'Mammal',
                class: 'one'
             },
             {
                id: 4,
                name: 'Lizard',
                type: 'Reptile',
                class: 'two'
             },
             {
                id: 5,
                name: 'Frog',
                type: 'Amphibian',
                class: 'three'
             },
             {
                id: 6,
                name: 'Spider',
                type: 'Arachnid',
                class: 'four'
             }
          ];
          $(function(){
    
          });
       </script>
    </head>
    <body>
    <ul id="animal-list">
       <li class='dinosaur'><strong><span class='name'>T-Rex</span></strong> <span class='type'>Dinosaur</span></li>
    </ul>
    </body>
    </html>
    
  2. 在你从上述代码中创建的 HTML 页面中,在$(function(){});中添加以下 JavaScript:

    $.each(animals, function(index, obj){
    //Clone the first element in the animal list
    var listTemplate = $('#animal-list li').first().clone();
    //Change its name to match this objects name
    listTemplate.find('.name').html(obj.name);
    //Changes its type to match this objects type
    listTemplate.find('.type').html(obj.type);
    //Remove all its current classes
    listTemplate.removeClass();
    //Add the class from this object
    listTemplate.addClass(obj.class);
    //Append the modified element to the end of the list
    $('#animal-list').append(listTemplate);
    });
    
  3. 如果你在浏览器中打开你刚创建的网页,你应该会看到一个已填充的列表元素,它与 JavaScript 数组animals中的对象相匹配。

工作原理...

通过使用 jQuery 的$.each()方法,我们能够遍历 JavaScript 数组animals中的每个对象。然后,对于 JavaScript 对象中的每个对象,我们使用$('#animal-list li').first().clone();克隆无序列表中的第一个元素,并将其存储在listTemplate变量中。现在,该变量包含了无序列表#animal-list中的第一个列表元素的副本。我们现在可以像处理任何其他 DOM 元素一样操作此元素。我们可以使用 jQuery 的find()函数来定位带有.name.type类名的 span 元素。然后,我们可以更改它们的内容以匹配当前对象的名称和类型值。接下来,我们使用removeClass()(不提供参数将删除所有当前类,而不必指定每个类)从克隆的元素中删除先前的样式,并使用 jQuery 提供的addClass()函数添加 JavaScript 对象中指定的样式。最后,我们可以使用append()将修改后的 HTML 元素附加到列表的末尾。

另请参阅

  • 删除 DOM 元素

  • 创建 DOM 元素

第二章:利用 jQuery 事件与用户进行交互

在本章中,我们将涵盖:

  • 检测按钮点击

  • 检测元素点击

  • 检测变化

  • 根据用户输入更新内容

  • 检测输入框中的按键事件

  • 限制输入字符长度

  • 在鼠标悬停时更改页面元素

  • 手动触发事件

  • 阻止事件触发

  • 创建自定义事件

介绍

本章将介绍如何利用 jQuery 的许多事件来允许您的界面响应不同的用户交互,例如按钮点击,以及 jQuery 事件如何帮助您进行表单验证。

检测按钮点击

点击网站元素是主要的用户交互;因此,检测这些点击是创建交互式 Web 应用程序中非常基本的一个方面。jQuery 开发人员可以通过各种方式监听其网页内的某些按钮按下。

准备工作

使用您喜欢的文本编辑器或 IDE,在易于访问的位置创建一个名为recipe-1.html的空白 HTML 页面。

如何实现...

通过执行以下步骤创建带有点击事件处理程序的两个按钮:

  1. recipe-1.html中添加以下 HTML 代码。请确保在 JavaScript 文件中更改 jQuery 库的位置,指向您计算机上下载的 jQuery 最新版本的位置。

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 2 :: jQuery Events</title>
        <script src="img/jquery.min.js"></script>
        <script>
    
        </script>
    </head>
    <body>
        <button class="button1">Button 1</button>
        <button class="button2">Button 2</button>
    </body>
    </html>
    
  2. 在脚本标签中添加以下 JavaScript 代码,为两个按钮元素附加点击事件处理程序:

    $(function() {
        $('.button1').click(function(){
        alert("Button 1 clicked");
        });
        $('body').on("click", ".button2", function(){
        alert("Button 2 clicked");
        });
    });
    
  3. 在 Web 页面中打开recipe-1.html,并单击其中的任一按钮。您将为每个按钮显示不同的 JavaScript 警报,这表明事件处理程序已被执行。

工作原理...

我们可以使用各种选择器来选择按钮元素,然后为这些元素附加事件处理程序。在前面的示例中,我们使用类名.button1选择第一个按钮,使用类名.button2选择第二个按钮。

通过$()方法选择每个按钮后,我们可以选择一种方法将点击事件附加到我们的按钮上。.click()方法,如以下代码片段所示,专门用于此目的。通过将回调函数作为参数传递,我们可以指定一组命令,一旦按钮被点击,这些命令将被执行。

$('.button1').click(function(){
  alert("Button 1 clicked");
});

前面的代码将在第一个按钮被点击后显示指定的警报。以下代码使用另一种函数.on(),也处理其他事件类型:

$('body').on("click", ".button2", function(){
  alert("Button 2 clicked");
});

这种方法有些不同,因为我们首先选择按钮的容器,然后指定按钮标识符(即.button2)。

还有更多...

.on()方法与.click()方法相比具有一些额外的好处,除了之前提到的内存优势外。如果在调用.click()函数后动态地向 DOM 添加任何元素,则它们将不会有点击事件附加。如果使用.on()方法,只要动态添加的元素被添加到指定的容器内,它们将被点击事件处理程序捕获。考虑以下代码作为此情况的示例:

<!DOCTYPE html>
<html>
<head>
    <title>Chapter 2 :: jQuery Events</title>
    <script src="img/jquery.min.js"></script>
    <script>
        $(function(){
            $('.button1').click(function(){
                alert("Button 1 clicked");
            });
            $('body').on("click", ".button2", function(){
                alert("Button 2 clicked");
            });
            setTimeout(function(){
                $('.additional').append("<button class='button1'>Button 1 again</button>");
                $('.additional').append("<button class='button2'>Button 2 again</button>");
            }, 2000);
        });
    </script>
</head>
<body>
<button class="button1">Button 1</button>
<button class="button2">Button 2</button>
<div class="additional"></div>
</body>
</html>

此代码将在页面加载时使用.click().on()方法分别为每个按钮附加事件处理程序。然后,使用setTimeout()函数,它将动态地向 DOM 添加另外两个按钮;一个带有.button1类,另一个带有.button2类。如果你在浏览器中打开这个网页,并等待第二组按钮被创建,然后点击额外的按钮 1按钮,将不会触发点击事件。点击额外的按钮 2按钮,你将看到警告框按预期被触发。

另请参阅

  • 检测元素点击

  • 检测输入框上的按键事件

检测元素点击

具有检测用户是否点击了除按钮以外的元素的能力可以为您的 Web 应用程序提供额外的灵活性。您可以像我们在前面的配方中所做的那样,将点击事件附加到任何 HTML 元素上。

准备工作

要完成本配方,我们首先需要一个名为recipe-2.html的空白 HTML 页面,与其他配方中的相同。请记住,您需要下载最新版本的 jQuery,并将其轻松地放在计算机上,以便将其包含在recipe-2.html中。

如何做…

要了解如何检测用户点击除按钮以外的元素,请执行以下步骤:

  1. 将以下 HTML 添加到您刚创建的recipe-2.html页面中。此 HTML 创建了一个非常基本的 Web 页面,其中包含一个输入框,一个锚点和一个分隔元素。

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 2 :: jQuery Events</title>
        <script src="img/jquery.min.js"></script>
        <script>
    
        </script>
    </head>
    <body>
    <a href="#">Link 1</a>
    <input type="text" name="input1" />
    <div class="clickme">Click Me!</div>
    </body>
    </html>
    
  2. 在我们刚创建的 HTML 页面的头部标签中的脚本标签内,添加以下 JavaScript 代码。该 JavaScript 代码使用了两种不同的方法将点击事件处理程序附加到三个 DOM 元素上。

    $(function() {
        $('a').click(function(){
        alert("You have clicked a link!");
        });
        $('body').on('click', 'input[type="text"]', function(){
        alert("You have clicked a text input!");
        });
        $('.clickme').click(function(){
        alert("You have clicked a division element");
        });
    });
    
  3. 确保所有更改都已保存,然后在浏览器中打开recipe-2.html。当你点击任何元素时,你将看到不同的 JavaScript 警告,演示了我们在配方中早些时候创建的每个点击事件都被事件处理程序捕获。

工作原理…

我们可以使用它们的标签名称选择 DOM 元素,比如a选择一个链接,然后使用.click().on()函数附加一个点击事件处理程序,如下面的代码片段所示。我们也可以使用 CSS 选择器input[type="text"]来选择页面上的所有文本输入。

$('.clickme').click(function(){
  alert("You have clicked a division element");
});

上述 jQuery 代码将点击事件附加到每个具有 .clickme 类的 DOM 元素。这些元素可以是任何 DOM 元素,例如 div、按钮、链接、输入和文本区域。这使得 jQuery 开发人员能够灵活地解释用户与所有页面元素的交互。

注意

参见本章的 检测按钮点击 配方,了解 .click().on() 之间的区别以及为什么 .on() 是首选实现方式。

另请参阅

  • 检测按钮点击

  • 检测输入框上的按键按下事件

检测更改

在创建动态和交互式网站和 Web 应用程序时,了解用户何时更改了页面上的某些内容(例如所选输入的值、文本输入或任何具有可修改值的其他元素)是很有用的。

准备工作

再次创建一个名为 recipe-3.html 的空白 HTML 文档。确保已下载最新版本的 jQuery,并将其包含到此 HTML 文件中。

如何操作…

要学习如何将更改事件处理程序附加到各种元素类型,请执行以下步骤:

  1. 将以下 HTML 代码添加到您刚创建的 HTML 文档中,并更新对 jQuery 库的引用,以确保页面中包含的是最新版本的 jQuery:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 2 :: jQuery Events</title>
        <script src="img/jquery.min.js"></script>
        <script>
    
        </script>
    </head>
    <body>
    <select id="names">
        <option value="Leon">Leon</option>
        <option value="Allyce">Allyce</option>
        <option value="Jane">Jane</option>
    </select>
    <input type="text" value="The large cat sat on the mat" id="cat" />
    </body>
    </html>
    
  2. 在脚本标签中,添加以下 JavaScript 代码来附加不同元素上的更改事件处理程序:

    $(function(){
        $('#names').change(function(){
         var newValue = $(this).val();
         alert("Input value changed to: " + newValue);
        });
        $('#cat').change(function(){
         var newValue = $(this).val();
         alert("Input value changed to: " + newValue);
        });
    });
    
  3. 确保所有更改都已保存。现在,在 Web 浏览器中打开 recipe-3.html;如果更改页面上某个元素的值,将显示一个提醒框通知您更改了。

工作原理…

使用 $() 选择每个输入元素,然后使用 .change() 函数附加更改事件处理程序,允许我们指定一旦用户更改每个输入的值后要执行的代码。

在回调函数中(作为参数提供给 .change() 函数),我们可以获取新值。使用 this,它引用所选元素,我们可以使用 $(this).val() 来检索新选择的值,并在警报框内显示它。

如果在浏览器中打开 Web 页面并将选定的输入值更改为 Allyce,将显示与以下截图类似的警报:

工作原理…

使用 .val() 来返回在下拉输入中所选选项上附加了更改事件处理程序的 value="Allyce" 属性。

当在文本输入上使用 .change() 事件处理程序时,该更改事件直到输入框失去焦点(即,用户单击 Web 页面的其他部分)才会触发。由于通常希望检测到即时更改,因此应考虑使用按键按下事件来捕获这些更改。

还有更多…

检测按钮点击配方讨论了使用.on()方法而不是使用.click()的好处。这些好处在这种情况下同样适用,因为.on()方法也可以与 change 事件一起使用。考虑以下代码:

$('body').on("change", "#names", function(){
  var newValue = $(this).val();
  alert("Input value changed to: " + newValue);
});

另请参阅

  • 检测按钮点击

  • 检测输入框的按键事件

  • 根据用户输入更新内容

根据用户输入更新内容

jQuery 允许开发人员轻松处理用户输入,然后更新页面以反映此输入。本章的先前配方已经介绍了检测输入值的更改和点击各种页面元素的操作。本配方将帮助您创建一个网页,根据从下拉菜单中选择的标题来更新标题元素。

准备工作

创建一个名为recipe-4.html的空 HTML 文档,其中包含最新版本的 jQuery 库,已下载并准备就绪。

如何做…

使用类似于您在先前配方中学到的技术,执行以下步骤根据用户交互来改变 DOM:

  1. 将以下 HTML 代码添加到您刚刚创建的recipe-4.html中;不要忘记更新到 jQuery 库的引用。这个 HTML 创建了一个基本的 HTML 网页,其中包含一个下拉菜单元素,允许用户选择一些标题。还有一个头部元素,我们可以根据用户的选择来使用 jQuery 进行操作。

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 2 :: jQuery Events</title>
        <script src="img/jquery.min.js"></script>
        <script>
    
        </script>
    </head>
    <body>
    <select id="title">
    <option value="#">Select your title...</option>
        <option value="1">Title 1</option>
        <option value="2">Title 2</option>
        <option value="3">Title 3</option>
    </select>
    <h1 id="main-title">No Title</h1>
    </body>
    </html>
    
  2. 将以下 JavaScript 代码添加到#title的选择输入中的脚本标记内,以附加 change 事件处理程序:

    $(function(){
        $('#title').change(function(){
        var titleText = "";
        switch ($(this).val()) {
            case "1":
                   titleText = "This is the text for title 1";
                break;
            case "2":
                titleText = "This is the text for title 2";
                   break;
               case "3":
                   titleText = "This is the text for title 3";
                   break;
           default:
              titleText = "No Title";
         }
            $('#main-title').html(titleText);
        });
    });
    
  3. 在浏览器中运行此网页,并从下拉菜单中选择一个新选项,将相应地更新标题的文本。

运作原理…

首先,我们指示 jQuery 使用以下代码将 change 事件处理程序附加到#title选择输入:

$(function() {
  $('#title').change(function(){

  });
}

当用户更改下拉输入中的选定选项时,change 事件处理程序就会执行。

function参数中,我们可以使用$(this)来引用#title选择输入,然后使用$(this).val();来获取其选定的值。一旦我们有了这个值,我们可以使用 JavaScript 执行所需的任何操作。在这个例子中,我们使用 JavaScript 的switch语句来确定选择了哪个标题,如下面的代码片段所示:

var titleText = "";
switch ($(this).val()) {
    case "1":
      titleText = "This is the text for title 1";
      break;
    case "2":
      titleText = "This is the text for title 2";
      break;
    case "3":
      titleText = "This is the text for title 3";
      break;
    default:
      titleText = "No Title";
}

根据所选的标题值,我们创建一些文本,然后将其提供给$('#main-title').html();。这将更新#main-title标题元素的 HTML 为提供的文本。

这展示了一个 jQuery 开发人员如何处理用户输入并执行操作以改变页面的一个非常简单的任务。

另请参阅

  • 检测更改

  • 鼠标悬停时更改页面元素

在输入框上检测按键事件

jQuery 提供了三个事件函数,允许 jQuery 开发者确定用户按下了哪个键,以及用户何时以何种方式按下了它。.keyup()函数是一个事件处理程序,可以附加到一个输入框上,并在按下的键完全释放后触发;同样,.keydown()将在按下键后完全释放时触发。第三个可用的事件处理程序是.keypress(),它在按下键时立即触发。

这些方法允许开发者提供强大的客户端验证,或者提供用户简单功能,比如在按下Enter键时触发表单提交。

准备工作

创建一个名为recipe-5.html的空白 HTML 文件,我们可以在这个配方中使用。

如何实现…

使用各种事件处理程序来检测用户按键事件,执行以下步骤:

  1. 将以下 HTML 代码添加到您刚创建的网页中。更新对 jQuery 库的引用,以确保引用了最新版本到网页中。这个 HTML 创建了一个简单的页面,其中包含一个输入框和一个无序列表元素,我们可以使用它来输出一些事件信息,以说明我们的 jQuery 代码的每个部分都在实现什么。

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 2 :: jQuery Events</title>
        <script src="img/jquery.min.js"></script>
        <script>
    
        </script>
    </head>
    <body>
    <input type="text" class="myInput" />
    <ul id="myList"></ul>
    </body>
    </html>
    
  2. 在脚本标签中,添加以下 JavaScript 代码来附加keyupkeydown事件处理程序:

    $(function(){
        $('.myInput').keyup(function(){
          $('#myList').append("<li>Key up!</li>");
        });
        $('.myInput').keydown(function(event){
          $('#myList').append("<li>Key down!</li>");
          if (event.which == 13) {
            $('#myList').append("<li>Enter key pressed!</li>");
          }
        });
    });
    

如何运作…

我们可以通过首先选择我们的.myInput元素,然后指定一个事件处理程序函数来附加keyupkeydown事件处理程序,如下面的代码所示:

$('.myInput').keydown();

我们已经在keydown事件的回调函数中添加了一个event变量作为参数。通过这个event变量,我们可以使用event.which来检测按下了哪个键。这通常很有用,因为我们可以确定用户刚刚按下的键是否是Enter键,我们可能希望对其执行特定操作,比如表单提交或当我们想要触发 AJAX 调用时。在这个例子中,我们简单地将一个列表项附加到我们的#myList无序列表中,以说明这个概念。

我们在keyup事件处理程序中复制此过程,并使用.append()函数将新的 DOM 元素附加到列表中。

一旦您在浏览器中加载了这个网页并在输入框中输入文本,您就能看到事件被触发,因为每次按键时列表元素都会更新。您将能够看到类似以下截图的内容:

如何运作…

还有更多…

该配方提供了两个使用keydownkeyup的示例。尝试用代码进行实验,并以同样的方式使用替代keypress()函数来看看它是如何工作的。

另请参阅

  • 检测按钮点击

  • 检测元素点击

  • 限制输入字符长度

  • 检测变化

限制输入字符长度

可以使用 jQuery 的 keypress 事件限制用户能够输入到文本字段中的字符。在某些情况下,这可以是一个强大的用户体验功能,因为用户可以直观地了解到他们不能提供的字符,而不必等待服务器的响应通知他们发生了错误。

准备工作

再次,我们将需要一个带有最新版本 jQuery 的空白 HTML 文档来完成本教程。创建 recipe-6.html 并确保您已下载并准备好 jQuery。

如何做…

通过执行以下步骤学习如何使用 jQuery 限制用户输入到文本输入中的某些字符:

  1. 将以下 HTML 代码添加到您新创建的 recipe-6.html 文件中,以创建一个带有单个输入元素的基本 HTML 网页:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 2 :: jQuery Events</title>
        <script src="img/jquery.min.js"></script>
        <script>
    
        </script>
    </head>
    <body>
    <input type="text" class="myInput" />
    </body>
    </html>
    
  2. 在 HTML 页面的脚本标签中,添加以下 JavaScript 代码,将一个 keypress 事件处理程序绑定到输入,并阻止选定文本输入中的任何非字母数字字符输入:

    $(function() {
        $('.myInput').keypress(function (event) {
          var regex = new RegExp("^[a-zA-Z0-9]+$");
          var key = String.fromCharCode(event.which);
          if (!regex.test(key)) {
            return false;
          }
        });
    });
    
  3. 在浏览器中打开 recipe-6.html 并尝试在输入文本框中输入非字母数字字符;您会发现无法这样做。

工作原理…

我们将 keypress 事件处理程序附加到 .myInput 元素,并将 event 变量指定为参数,如下面的代码片段所示:

$('.myInput').keypress(function (event) {

});

这允许我们在 .myInput 字段获得焦点时在 keypress 上指定要执行的命令。

我们声明一个正则表达式变量,可以使用它来评估输入的字符是否是字母数字字符。

var regex = new RegExp("^[a-zA-Z0-9]+$");

键盘上的每个键都有一个独特的数字代码,可以使用 event.which 访问。然后,要确定按下的键是否是字母数字字符,我们需要检索其字符串值(例如,f 的字母数字值为 102 ),可以使用以下代码完成:

var key = String.fromCharCode(event.which);

这现在使我们能够应用正则表达式并确定是否符合我们的字母数字要求。如果不符合,我们通过返回 false 来阻止该键值被输入,如下所示:

if (!regex.test(key)) {
  return false;
}

如果按下的键是有效的字母数字字符,则允许字符显示在文本框中。

还有更多...

理解客户端验证的重要性很重要,例如这样的验证是一个强大的用户体验功能,但绝不能仅仅依赖于此。在客户端执行的任何验证都应始终在服务器端进行镜像。这是因为用户很容易绕过客户端验证。通常情况下,只需在浏览器设置中关闭 JavaScript 就可以绕过验证。请记住,任何客户端语言,如 JavaScript,都完全可以被最终用户操纵。因此,客户端验证应仅用作用户体验增强,而永远不是数据输入的明确验证形式。

另请参阅

  • 检测输入框上的按键事件

鼠标悬停时更改页面元素

jQuery 提供了许多绑定鼠标事件处理程序的方法,这些方法可以比 CSS 伪类如 :hover 给 jQuery 开发人员更多的控制和灵活性。这些事件处理程序使得基于用户操作创建丰富和交互式的用户体验成为可能。

注意

随着 jQuery 2.0 的发布,jQuery 不再正式支持较早的浏览器,如 IE6、IE7 和 IE8。然而,诸如 .hover() 之类的方法仍然可以提供利益,使您能够支持较早版本的浏览器。但是,请注意,jQuery 库的某些部分可能已不再起作用。

准备工作

为了演示鼠标悬停事件,我们首先需要创建一个空白的 HTML 文档。在计算机上的一个易于访问的位置创建 recipe-7.html

如何操作…

了解 jQuery 如何检测用户执行悬停操作的步骤如下:

  1. 使用您新创建的 HTML 文档,添加以下 HTML 和 CSS 代码来创建一个带有一些基本表单元素的网页:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 2 :: jQuery Events</title>
        <style type="text/css">
            .info {
                width: 530px;
                border: solid 2px yellow;
                padding: 10px;
                text-align: center;
                margin-top: 10px;
                display: none;
            }
        </style>
        <script src="img/jquery.min.js"></script>
        <script>
    
        </script>
    </head>
    <body>
    <label>Your Name:</label>
    <input type="text" name="name" class="hoverinfo" rel="Please provide us with your name." />
    <label>Your Email:</label>
    <input type="text" name="email" class="hoverinfo" rel="Please provide us with your email address" />
    <button class="hoverinfo" rel="Click here to submit your information to us">Submit</button>
    <div class="info"></div>
    </body>
    </html>
    
  2. 现在我们有了一个带有三个简单表单元素和一个 div 标签的网页,在其中我们可以显示有关悬停项的信息。使用以下 JavaScript 代码,并将其放置在 script 标记中,以将 mouseovermouseleave 事件处理程序附加到具有 .hoverinfo 类的每个元素:

    $(function(){
        $('.hoverinfo').mouseover(function(){
          $('.info').html($(this).attr("rel"));
          $('.info').fadeIn();
        }).mouseleave(function(){
          $('.info').hide();
        });
    });
    
  3. 在浏览器中打开网页,悬停在不同的表单元素上;您将看到适当的消息显示。

工作原理…

我们使用以下 CSS 代码为我们的 .info div 元素添加一些基本样式,以便在显示后在页面上突出显示:

.info {
  width: 530px;
  border: solid 2px yellow;
  padding: 10px;
  text-align: center;
  margin-top: 10px;
  display: none;
}

我们添加了 display: none; 以防止 .info 元素显示在屏幕上,将其留给 jQuery 代码。

我们将 .hoverinfo 类添加到包含额外信息的每个 HTML 元素中,以便在我们的 jQuery 代码中识别它们。然后,我们使用以下代码将 mouseovermouseleave 事件处理程序附加到每个 .hoverinfo 元素:

$('.hoverinfo').mouseover(function(){

}).mouseleave(function(){

});

当用户将鼠标移动到任何 .hoverinfo 元素上时,将执行 mouseover 事件处理程序。类似地,一旦用户的鼠标指针离开任何具有 .hoverinfo 类的 HTML 元素,mouseleave 事件将被执行。

mouseover 事件处理程序中,我们可以使用 $(this).attr("rel"); 来获取我们添加到每个 .hoverinfo 元素上的 rel 属性的文本(或任何 HTML 属性的值)。然后,可以与以下代码一起使用:

$('.info').html($(this).attr("rel"));
$('.info').fadeIn();

我们将 rel 属性的文本传递给 .html() 函数,该函数将替换 .info div 元素中的现有 HTML 代码。然后,我们使用 jQuery 的 .fadeIn() 函数提供动画,并显示具有 rel 属性值的 .info 元素。

最后,mouseleave 事件处理程序使用 $('.info').hide(); 再次将元素隐藏起来,使得可以在另一个 .hoverinfo 元素的 mouseover 事件被触发后重复该过程。

更多内容…

jQuery 包含许多其他鼠标事件处理程序,可用于各种用户交互。确保选择最适合您情况的事件处理程序。访问 jQuery 文档 (api.jquery.com/category/events/mouse-events/) 了解更多信息。

另请参阅

  • 基于用户输入更新内容

手动触发事件

在您的 web 应用程序中可能会有部分需要对用户交互触发的事件做出反应是不够的。jQuery 允许我们从代码内部手动触发事件。

准备工作

在创建 web 应用程序时,可能会有时候需要一个仅由您的 jQuery 代码处理并且不作为典型 HTML 表单提交的表单,也许是为了执行 AJAX 请求。这就是我们将在这个示例中演示的内容。首先,再次创建一个名为 recipe-8.html 的空白 HTML 文档。确保它被放置在您计算机上易于访问的位置。

如何做…

通过执行以下步骤学习如何从 JavaScript 内部手动触发事件:

  1. 将以下 HTML 代码添加到 recipe-8.html 中,以创建一个非常基本的网页,其中包含一组表单元素和一个提交按钮:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 2 :: jQuery Events</title>
        <script src="img/jquery.min.js"></script>
        <script>
    
        </script>
    </head>
    <body>
    <label>First Name:</label>
    <input type="text" name="firstname" />
    <label>Last Name:</label>
    <input type="text" name="lastname" />
    <label>Your Email:</label>
    <input type="text" name="email" />
    <button class="submit-btn">Submit</button>
    </body>
    </html>
    
  2. 将以下 jQuery 代码添加到脚本标签中,以创建一个提交按钮的事件处理程序,并在用户在任何文本输入框内按下 Enter 键时手动触发提交按钮的点击事件:

    $(function() {
        $('.submit-btn').on("click", function(){
          alert("Submit the form!");
        });
        $('input[type="text"]').keypress(function(event){
          if (event.which == 13) {
            $('.submit-btn').trigger("click");
          }
        });
    });
    

如何运作…

我们经常希望模仿典型行为,比如当在我们的表单输入框中按下 Enter 键时进行表单提交。我们可以使用以下代码监听所有文本输入框的按键事件:

$('input[type="text"]').keypress(function(event){
  if (event.which == 13) {
    $('.submit-btn').trigger("click");
  }
});

一旦用户在文本输入框内按下键盘,此代码将被执行。当他们这样做时,我们使用 event.which == 13 来检查是否按下了 Enter 键(即 Enter 的字符代码为 13)。如果按下了 Enter 键,我们就使用 jQuery 函数 .trigger() 并传递字符串 click 来手动触发所选元素上的点击事件,这里选定的元素是 .submit-btn

使用以下代码,可以将点击事件处理程序附加到 .submit-btn

$('.submit-btn').on("click", function(){
  alert("Submit the form!");
});

function 参数中的代码将被执行,并显示警报。

还有更多内容...

还有许多其他的 jQuery 事件处理程序函数,可以在没有提供回调函数作为参数时手动触发事件。例如,请考虑以下代码:

$('input[type="text"]').keypress(function(event){
  if (event.which == 13) {
    $('.submit-btn').click();
  }
});

此代码使用 .click() 函数来手动触发点击事件,而不是使用 .trigger() 函数。两种方法之间没有明显的区别,但请注意两者都是可用的。

防止事件触发

有许多情况下,jQuery 开发人员将希望阻止正常 HTML 元素(例如表单、按钮甚至是他们自己的事件处理程序)的默认浏览器操作。jQuery 提供了停止这些事件的能力。这使开发人员可以防止诸如多次按钮点击、多次表单提交和意外提交等情况,或者通常允许开发人员更改典型事件的正常行为。

准备工作

创建一个名为 recipe-9.html 的空白 HTML 文件,并确保最新版本的 jQuery 库可用。

如何操作…

了解如何通过执行以下步骤阻止默认浏览器操作:

  1. 将以下 HTML 代码添加到 recipe-9.html 中;确保您更新对 jQuery 库的引用以指向计算机上的正确位置:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 2 :: jQuery Events</title>
        <script src="img/jquery.min.js"></script>
        <script>
    
        </script>
    </head>
    <body>
    <form method="POST" id="myForm">
        <label>First Name:</label>
        <input type="text" name="firstname" />
        <label>Last Name:</label>
        <input type="text" name="lastname" />
        <label>Your Email:</label>
        <input type="text" name="email" />
        <button class="submit-btn">Submit</button>
    </form>
    </body>
    </html>
    
  2. 使用以下 jQuery 代码并将其放置在脚本标签中以捕获 提交 按钮的点击并阻止表单被提交:

    $(function() {
      $('.submit-btn').on("click", function(event){
        event.preventDefault();
        event.stopPropagation();
        var response = confirm("Are you sure you want to submit this form?");
        if (response) {
          $('#myForm').submit();
        }
      });
    });
    
  3. 在浏览器中打开 recipe-9.html 并单击 提交 按钮将向您显示一个 JavaScript 确认消息,该消息将捕获您的响应,然后根据您的选择提交 HTML 表单。感谢 event.preventDefault();event.stopPropagation(); 方法,直到您对此消息框做出响应,表单才会被提交。

工作原理…

以下 jQuery 代码允许我们点击 提交 按钮并使用 .on() 函数创建一个点击事件处理程序。我们将 click 作为第一个参数提供,以指定我们需要点击事件处理程序,而 .on() 函数提供了许多其他类型事件的接口。

$('.submit-btn').on("click", function(event){

});

我们在 .on() 回调函数中提供 event 变量作为参数。然后,我们可以使用以下 jQuery 函数来创建我们想要的效果:

event.preventDefault();
event.stopPropagation();

event.preventDefault(); 函数阻止当前事件的默认操作;在这种情况下,即表单提交。这样可以让我们以自己的方式处理事件,例如提供额外功能或导致完全不同的操作。event.stopPropagation(); 函数将阻止事件冒泡通过父级和祖先 DOM 元素。当在元素上触发事件时,事件也会在父元素和 DOM 中的所有祖先元素上触发,因此,我们仍然可以触发最初尝试阻止的事件。

由于我们已经使用了这些方法来防止表单提交,我们可以询问用户是否确定要提交表单。我们使用原生的 JavaScript confirm() 函数来实现这一点,如下所示:

var response = confirm("Are you sure you want to submit this form?");
  if (response) {
    $('#myForm').submit();
}

我们将用户的响应存储在一个变量中,然后对其进行评估。如果他们点击 确定 来确认表单提交,我们可以继续使用 $('#myForm').submit(); 提交表单。否则,我们什么也不做,表单就不会被提交。

另请参阅

  • 手动触发事件

创建自定义事件

jQuery 为开发者提供了处理内置 JavaScript 事件的方法,如 .click().hover() 等。jQuery 还允许开发者创建自己的事件类型以提供额外的功能。通过创建自定义事件,开发者还可以更轻松地在他们的应用程序中传递数据。

准备工作

在一个易于访问的位置创建另一个空白的 HTML 文档,命名为 recipe-10.html

如何做……

学习如何使用 jQuery 创建自定义事件,执行以下步骤:

  1. 将以下 HTML 代码添加到这个新创建的 HTML 文档中。记得更新对 jQuery 库的引用,指向你计算机上的本地位置。

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 2 :: jQuery Events</title>
        <script src="img/jquery.min.js"></script>
        <script>
    
        </script>
    </head>
    <body>
        <button rel="green">Green</button>
        <button rel="blue">Blue</button>
        <p class="colourme"></p>
    </body>
    </html>
    
  2. 现在我们可以绑定一个自定义事件处理程序到我们的段落上,并在其中一个按钮元素被点击时触发它。在脚本标签内添加以下 JavaScript 代码:

    $(function() {
      $('.colourme').on("switchColour", function(event, colour, text){
        $(this).html(text);
        $(this).css("color", colour);
      });
      $("button").click(function(){
        var colour = $(this).attr("rel");
        $('.colourme').trigger("switchColour", colour, colour + ' button pressed... ']);
      });
    });
    
  3. 打开你新创建的网页,并点击两个按钮中的任何一个,你应该看到段落文本随按钮的点击而改变,并且颜色也相应变化。

它是如何工作的……

jQuery 提供了一个 .on() 函数,允许我们指定要绑定到选定元素的事件的名称。我们可以指定内置的 jQuery 事件,或者我们可以提供我们自己事件的名称。我们使用以下 JavaScript 代码来做到这一点:

$('.colourme').bind("switchColour", function(event, colour, text){
  $(this).html(text);
  $(this).css("color", colour);
});

此代码将事件处理程序绑定到具有 colourme 类的段落元素的自定义 switchColour 事件上。我们向 .on() 函数提供的第二个参数是一个回调方法,该方法有三个参数:Event,保存事件信息,然后是 colourtext,它们是我们自己的自定义属性,我们稍后可以使用它们。

在函数内部,我们使用 $(this).html(text); 来改变当前选择的 .colourme 段落元素的内容为 text 变量提供的文本。我们还使用 $(this).css("color", colour); 应用一些 CSS,将文本的颜色更改为提供的 colour 变量的值。(使用拼写 color 而不是 colour)。

现在我们已经创建了自定义事件,我们需要能够触发此事件,可以使用以下代码完成:

$("button").click(function(){
  var colour = $(this).attr("rel");
  $('.colourme').trigger("switchColour", [colour, colour + ' button pressed... ']);
});

在前面的 JavaScript 代码中,我们使用 jQuery 提供的 .click() 函数来执行一组代码,一旦点击了其中一个按钮元素。在点击事件处理程序中,我们首先检索元素的 rel 属性,我们在 HTML 中指定为变量 colour

然后我们使用 .trigger() 函数并指定要触发的自定义事件。我们提供第二个参数作为一个数组,包含我们在使用 .on() 指定的自定义事件中的变量,colourtext

.trigger() 函数将触发我们自定义的事件,并为任何绑定的元素提供我们提供的信息。绑定到此事件的 .colourme 段落将其内部 HTML 更改,并修改其 CSS 颜色属性以成为指定的颜色。

第三章:使用 AJAX 和 JSON 加载和操作动态内容

在本章中,我们将涵盖:

  • 将 HTML 从 Web 服务器加载到页面中

  • 使用 AJAX 并处理服务器错误

  • 处理 JSON 数据

  • 搜索 JavaScript 对象

  • 排序 JavaScript 对象

  • 缓存 JSON 和 AJAX 请求

  • 创建搜索功能

  • 创建自动建议功能

  • 等待 AJAX 响应

简介

jQuery 允许开发人员进行 AJAX 调用,这将更新网站内容,而无需刷新完整的网页。 jQuery 的 AJAX 功能为网站增加了一个额外的维度,使其更像一个 Web 应用程序。 本章讨论了开发人员如何进行这些 AJAX 请求,接收数据并对其进行处理。 除了处理和利用从 AJAX 请求接收到的数据之外,本章还介绍了 AJAX 的一些其他主要功能,包括搜索和建议。

对于本章中的大多数示例,您要么需要在本地计算机上运行一个 Web 服务器,要么需要访问在线 Web 服务器。 一些关于 PHP 和 MySQL 的基本知识将会很有用,因为所需的 Web 服务器将使用这些技术。 要了解有关这些技术的更多信息,您可以参考以下资源:

  • 要了解有关 PHP 的更多信息,请参阅www.php.net

  • 要了解有关 MySQL 的更多信息,请参阅www.mysql.com

将 HTML 从 Web 服务器加载到页面中

在最基本的级别上,AJAX 允许我们使用来自 Web 服务器的新内容更新单个页面元素。 这个示例展示了如何设置一些数据以从一个使用 PHP 的 Web 服务器接收,以及如何接收此数据并将其应用到我们的网页中。

准备工作

确保您的 Web 服务器正在运行并且可以访问其 Web 根目录。

如何做…

执行以下步骤以创建所需的 PHP、MySQL 和 HTML,以便了解如何使用 jQuery 进行 AJAX:

  1. 在我们能够从 Web 服务器请求任何数据以在我们的网页中显示之前,我们需要能够从 Web 服务器提供此数据。 创建一个名为 request-1.php 的 PHP 文件。 添加以下 PHP 代码,并将其保存在 Web 服务器的 Web 根目录中:

    <?php
      $num = rand(1, 5);
      switch ($num) {
        case 1:
          $quote = "Learn from yesterday, live for today, hope for tomorrow. The important thing is not to stop questioning.";
          break;
        case 2:
          $quote = "Only two things are infinite, the universe and human stupidity, and I'm not sure about the former.";
          break;
        case 3:
          $quote = "The difference between stupidity and genius is that genius has its limits.";
          break;
        case 4:
          $quote = "Try not to become a man of success, but rather try to become a man of value.";
          break;
        case 5:
          $quote = "Any man who can drive safely while kissing a pretty girl is simply not giving the kiss the attention it deserves.";
          break;
      }
      echo $quote;
    
  2. 第二步是创建一个使用 jQuery 的 HTML 页面,该页面可以从我们的 PHP 脚本请求数据。 在 Web 服务器的 Web 根目录中,创建一个名为 recipe-1.html 的 HTML 文件,并添加以下 HTML 代码:

    <!DOCTYPE html>
    <html>
    <head>
      <title>Chapter 3 :: AJAX & JSON</title>
      <script src="img/jquery.min.js"></script>
      <style type="text/css">
    
      </style>
      <script>
    
      </script>
    </head>
    <body>
      <div class="left">
        Famous <br />Einstein Quotes
      </div>
      <div class="right">
        <p class="quote"></p>
        <button class="refresh">Get Quote</button>
      </div>
    </body>
    </html>
    
  3. 现在我们将使用 CSS 来为我们的 HTML 页面添加样式。 在 recipe-1.html 文件的 <style type="text/css"></style> 标签中添加以下 CSS 代码:

    .left {
      width: 200px;
      background-color: #CCC;
      float: left;
      height: 100px;
      text-align: center;
      font-size: 25px;
      padding: 40px 10px 10px 10px;
    }
    .right {
      width: 300px;
      float: left;
      margin-left: 10px;
      background-color: #333;
      color: #FFF;
      height: 120px;
      font-size: 20px;
      position: relative;
      padding: 20px 10px 10px 10px;
    }
    .refresh {
      position: absolute;
      right: 5px;
      top: 5px;
    
    }
    
  4. 最后一步是添加一些 jQuery 代码,以便从 PHP 脚本请求数据并将其加载到我们的网页中。 在 recipe-1.html 文件的头部的脚本标签中,添加以下 jQuery 代码:

    $(function() {
      $('.refresh').click(function() {
        $.ajax({
          url: '/request-1.php',
          type: 'GET'
        }).done(function(data){
          $('.quote').html(data);
        });
      });
    });
    

它是如何工作的…

现在,让我们详细了解之前执行的步骤。

PHP

使用 PHP 脚本的目的是将阿尔伯特·爱因斯坦的随机引用提供为字符串。要能够随机执行此操作,我们首先需要生成一个随机数。这通过以下方式使用 PHP rand() 函数完成:

$num = rand(1, 5);

这将创建一个随机整数值的变量,范围在 15 之间。然后,我们可以使用此随机数来确定要输出哪个引用。我们使用基于 $num 变量的 switch 语句创建一个具有随机爱因斯坦引用的 $quote 变量:

switch ($num) {
    case 1:
      $quote = "Learn from yesterday, live for today, hope for tomorrow. The important thing is not to stop questioning.";
      break;
    case 2:
      $quote = "Only two things are infinite, the universe and human stupidity, and I'm not sure about the former.";
      break;
    case 3:
      $quote = "The difference between stupidity and genius is that genius has its limits.";
      break;
    case 4:
      $quote = "Try not to become a man of success, but rather try to become a man of value.";
      break;
    case 5:
      $quote = "Any man who can drive safely while kissing a pretty girl is simply not giving the kiss the attention it deserves.";
      break;
  }

最后,我们输出$quote的值:

echo $quote;

如果您在浏览器中访问此文件(即http://localhost/request.php)从 Web 服务器提供的文件,您将每次刷新页面都会看到一个随机引用,如下面的截图所示:

PHP

HTML

我们需要一个 HTML 页面来加载我们的 PHP 生成的引用。在 HTML 中,我们定义一个简单的 HTML 布局。我们创建一个具有 left 类的分区元素。此框仅包含标题著名的爱因斯坦语录。我们定义一个具有 right 类的第二个 div 元素和两个子元素,一个段落和一个按钮。

HTML

在上述截图中,右侧的由带有 quote 类的段落元素组成的框是我们将使用 jQuery 加载动态内容的地方。我们将使用按钮允许用户触发引用的动态加载。请注意,您还可以在页面加载时加载引用,而无需用户交互。

CSS

要创建包含我们动态引用的网页,我们使用一些非常基本的 CSS 来样式化和对齐我们在 HTML 中创建的各种元素,如下所示:

.left {
  width: 200px;
  background-color: #CCC;
  float: left;
  height: 100px;
  text-align: center;
  font-size: 25px;
  padding: 10px;
  padding-top: 40px;
}

我们使具有 left 类的 div 元素具有固定的宽度和高度,然后强制其浮动到浏览器窗口的左侧。设置固定高度以确保左侧和右侧 div 元素具有相等的高度。我们还添加了一些基本的文本格式设置,包括 line-heighttext-alignfont-size,这些都是不言自明的。我们还更改了 div 元素的背景颜色,并添加了一些填充以进一步对齐文本。

.right {
  width: 300px;
  float: left;
  margin-left: 10px;
  background-color: #333;
  color: #FFF;
  height: 120px;
  font-size: 20px;
  position: relative;
  padding: 10px;
  padding-top: 20px;
}

我们向右侧的分区元素添加了非常相似的样式,还添加了 position: relative;,这样可以防止具有绝对位置的兄弟元素漂浮到此 div 元素之外。

.refresh {
  position: absolute;
  right: 5px;
  top: 5px;
}

由于父级 .right 分区元素具有相对位置,我们可以使 .refresh 按钮的位置为绝对,并将顶部和右侧位置值设置为静态,从而强制按钮浮动到我们的 .right 分区框的右上角。

jQuery

使用 jQuery,我们可以向我们的 Web 服务器上早些时候创建的 request.php 页面发出请求。首先,我们创建一个事件处理程序并将其附加到刷新按钮上,以便在用户单击此按钮时进行请求。

$('.refresh').click(function() {

});

当用户点击.refresh按钮时,function(){}内的任何代码都将被执行。在这个回调函数中,我们可以使用 jQuery 提供的$ajax进行 AJAX 请求:

$.ajax({
  url: '/request.php',
  type: 'GET'
}).done(function(data){
  $('.quote').html(data);
});

我们向$.ajax()提供一个对象,该对象允许我们指定进行 AJAX 调用所需的一组参数。在本例中,我们提供了urltype参数,告诉 jQuery 在哪里进行请求以及请求的类型。

注意

阅读$.ajax()的文档,了解可以提供的其他参数。API 文档可以在api.jquery.com/jQuery.ajax/找到。

另外,我们在 AJAX 请求方法后添加.done()函数,并提供一个接受data参数的回调函数。这个data参数将保存来自服务器的响应。在回调函数中,我们使用$('.quote').html(data);来用我们的 PHP 脚本的响应替换.quote段落中的 HTML。如果用户访问这个 HTML 页面并点击获取报价按钮,他们将看到如下截图中的结果:

jQuery

请参见

  • 创建搜索功能

  • 创建自动建议功能

  • 等待 AJAX 响应

使用 AJAX 处理服务器错误

在理想的世界里,你的 Web 应用程序永远不会出错。不幸的是,事实并非如此,Web 开发人员需要优雅地处理错误,并为用户提供有用的反馈。

例如,当服务器无法访问或文件/网页丢失时,会发生系统错误。系统错误通常是不可避免的,超出用户的控制范围。它们与应用程序错误(如无效的数据输入)不同,用户可以进行更正。

准备工作

由于这个示例涉及到 AJAX 错误,并且我们将调用一个不存在的 PHP 脚本,所以我们只需要 HTML 和 JavaScript。创建一个名为recipe-2.html的空白 HTML 文档,并确保你已经下载并准备好了最新版本的 jQuery。

怎样去做…

学习如何通过仔细执行以下步骤来处理 AJAX 错误:

  1. 添加以下 HTML 代码以创建一个简单的网页,其中只有一个按钮,将触发一个 AJAX 请求:

    <!DOCTYPE html>
    <html>
    <head>
      <title>Chapter 3 :: AJAX & JSON</title>
      <script src="img/jquery.min.js"></script>
      <script>
    
      </script>
    </head>
    <body>
      <button id="makeRequest">Make AJAX request</button>
    </body>
    </html>
    
  2. 在脚本标签中,添加以下的 jQuery 代码,当#makeRequest按钮被点击时,将向不存在的文件发出 AJAX 请求:

    $(function() {
      $('#makeRequest').click(function() {
      $.ajax({	
        url: 'i-do-not-exist.html',
        type: 'GET'
      }).done(function(data){
        //Will not succeed as no file exists
      });
      });
    });
    
  3. 在 AJAX 请求之后(但仍在$(function(){});中),添加以下代码,它将创建一个全局的 AJAX 错误事件处理程序,每当 AJAX 请求失败时都会触发:

    $(document).ajaxError(function(event, request, settings) {
      alert("Error trying to reach '" + settings.url + "'. ERROR CODE: " + request.status + " ERROR MESSAGE: " + request.statusText);
    });
    

运作原理…

我们创建的 HTML 页面是不言自明的。我们创建了一个按钮,可以触发 AJAX 请求。这显然是用来说明错误处理概念的最简单的例子,然后可以应用到使用 jQuery 的任何 AJAX 请求情况。

我们为#makeRequest按钮创建了一个事件处理程序,并提供了一个回调函数来在单击时执行:

$('#makeRequest').click(function() {
  $.ajax({
    url: 'i-do-not-exist.html',
    type: 'GET'
  }).done(function(data){
  //Will not succeed as no file exists
  });
});

我们通过 jQuery 提供的$.ajax()函数在回调函数中添加了 AJAX 请求。然后,我们将一个 JavaScript 对象传递给这个方法,在这个方法中,我们指定了一个不存在文件的 URL 和请求的类型;在这种情况下,GET。请注意,如果 AJAX 请求失败,则$.ajax()函数链接到.done()函数的功能将永远不会被执行。

我们创建了一个全局 AJAX 错误处理程序,并将其附加到文档上,以便它能够捕获我们页面中的所有 AJAX 错误:

$(document).ajaxError(function(event, request, settings) {
  alert("Error trying to reach '" + settings.url + "'. ERROR CODE: " + request.status + " ERROR MESSAGE: " + request.statusText);
});

.ajaxError方法的回调函数中提供了三个参数,我们可以使用这些参数了解有关错误的更多信息。在这个例子中,我们从settings变量和request对象中提取目标 URL 的信息和状态信息。

如果您在 Web 浏览器中打开此 HTML 文件并单击#makeRequest按钮,将显示一个 JavaScript 警报框,其中提供有关错误的信息,如下面的屏幕截图所示:

它是如何工作的...

还有更多...

在这个例子中,我们创建了一个全局 AJAX 错误处理程序来捕获页面中的所有 AJAX 请求错误。全局 AJAX 错误处理程序非常适合请求错误,例如文件丢失或主机不可达。在这些情况下,可以以相同的方式处理所有 AJAX 请求的错误,并且不需要有关个别请求的更具体的信息。

在您的应用程序中可能会出现这样的情况,您可能需要以不同的方式处理一个或多个 AJAX 请求错误。为此,您可以使用.fail()函数,该函数与.done()的使用方式相同。以下 jQuery 代码提供了一个使用.fail()的示例用法,以实现一个简单的 AJAX 请求的全局错误处理相同的结果:

$.ajax({
  url: 'i-do-not-exist.html',
  type: 'GET'
}).done(function(data){
  //Will not succeed as now file exists
}).fail(function(event){
  alert("An error occurred. Error Code: " + event.status);
});

请注意,关于错误的直接可用信息较少。

处理 JSON 数据

JavaScript 对象表示法JSON)为 Web 开发人员提供了一种干净高效的数据编码方式。JSON 是一种被广泛采用的格式。它简化了数据处理和操作。要了解更多关于为什么应该使用 JSON 的信息,请访问www.revillweb.com/why-use-json/

准备工作

确保您的 Web 服务器正在运行,并且您可以访问您可以保存/上传作为此配方的一部分创建的文件的网络根目录。

如何做...

通过执行以下步骤来学习如何使用 JavaScript 处理 JSON 格式的数据:

  1. 创建一个名为request-3.php的 PHP 文件,并将其保存到您的网络服务器的网络根目录中。使用以下 PHP 代码创建并输出一个名字列表作为 JSON 数据:

    <?php
      //Create an array of people
      $people = array(
        1 => array(
          "firstname" => "Luke",
          "lastname" => "Skywalker"
        ),
        2 => array(
          "firstname" => "Darth",
          "lastname" => "Vader"
        ),
        3 => array(
          "firstname" => "Mace",
          "lastname" => "Windu"
        )
      );
      //Ensure the browser is expecting the correct content
      //type format and charset
      header("Content-Type: application/json; charset=UTF-8");
      //Encode the array of people into JSON data
      echo json_encode($people);
    ?>
    
  2. 在您的网络服务器的网络根目录中创建一个名为recipe-3.html的 HTML 页面。将以下 HTML 添加到此页面中,它创建了一个无序列表元素,一旦处理完成我们的 JSON 数据,就可以填充该元素:

    <!DOCTYPE html>
    <html>
    <head>
      <title>Chapter 3 :: AJAX & JSON</title>
      <script src="img/jquery.min.js"></script>
      <script>
      </script>
    </head>
    <body>
      <ul id="peopleList"></ul>
    </body>
    </html>
    
  3. 在 HTML 页面的 head 标签内的 script 标签中,添加以下 jQuery 代码以执行对之前创建的request-3.php页面的 AJAX 请求:

    $(function(){
      $.ajax({
        url: '/request-3.php',
        type: 'GET'
      }).done(function(data){
    
      });
    });
    
  4. .done()回调函数中,使用 jQuery 的$.each()函数处理来自我们的 PHP 页面返回的 JSON 数据,并为列表中的每个人添加一个新的列表项到我们的 HTML 页面中:

    $.each(data, function(key, value) {
      $('#peopleList').append("<li>#" + key + " " + value.firstname + " " + value.lastname + "</li>");
    });
    

运行原理...

现在,让我们详细了解之前执行的步骤。

PHP

在实际应用中,你通常会从数据库中检索数据。在这个示例中,我们创建了一个简单的二维姓名数组作为我们的“数据库”,允许我们集中精力编写 jQuery 代码。

$people = array(
  1 => array(
    "firstname" => "Luke",
    "lastname" => "Skywalker"
  ),
  2 => array(
    "firstname" => "Darth",
    "lastname" => "Vader"
  ),
  3 => array(
    "firstname" => "Mace",
    "lastname" => "Windu"
  )
);

接下来,我们手动指定响应内容类型和字符集。要指定响应的内容类型和字符集,以便 web 浏览器和 jQuery 代码知道期望数据的格式。大多数 web 浏览器都可以很好地解决这个问题。然而,Internet Explorer 9 及更低版本在这个领域特别棘手,手动使用 PHP 的 header() 函数指定内容类型和字符集始终是一个好的做法:

header("Content-Type: application/json; charset=UTF-8");

请注意,我们的字符集设置为UTF-8,而不是 utf8utf-8。再次提醒,大多数浏览器都可以接受任一种设置,但一些较早的 Internet Explorer 版本在字符集格式不正确时会产生不良影响。

注意

在这个示例中,与这样简单的数据不太可能出现本文中提到的与浏览器相关的问题。这是一种最佳实践,将为更大型、更复杂的使用 AJAX 和 JSON 的 Web 应用程序提供更大的益处。

最后,我们使用 PHP 提供的 json_encode() 函数将我们的 PHP 数组编码为 JSON 格式,并使用echo输出结果如下:

echo json_encode($people);

如果直接访问request-3.php页面,你会在浏览器窗口中看到以下格式的people数组的输出:

{"1":{"firstname":"Luke","lastname":"Skywalker"},"2":{"firstname":"Darth","lastname":"Vader"},"3":{"firstname":"Mace","lastname":"Windu"}}

或者,可以使用浏览器开发工具并选择网络选项卡,以更可读的方式查看响应。

HTML

我们的 HTML 页面除了包含 jQuery 库外,还创建了一个 HTML 无序列表元素,我们可以在 jQuery 处理后将其填充为 JSON 数据。

jQuery

将我们的代码放在$(function(){});中将导致页面加载时执行它。我们使用 jQuery 的$.ajax()功能来对先前创建的 PHP 文件执行 AJAX 请求,方法如下:

$.ajax({
  url: '/request.php',
  type: 'GET'
}).done(function(data){
});

通过在对象中提供urltype参数给这个方法,我们告诉方法对我们的 web 服务器的 web root 中存在的request-3.php文件发出GET请求。然后我们在$.ajax();方法上附加了一个.done()函数,当请求成功发送时,将执行该函数。.done()方法采用回调函数作为参数,该回调函数包含来自请求的响应数据的data变量——来自 PHP 文件的 JSON 数据。

现在我们已经在data变量中获得了响应数据,我们可以处理 JSON 数据并使用以下代码填充我们的 HTML 列表元素:

$.each(data, function(key, value) {
  $('#peopleList').append("<li>#" + key + " " + value.firstname + " " + value.lastname + "</li>");
});

$.each();是 jQuery 提供的另一个函数,它允许我们循环遍历作为第一个参数指定的一组数据(在本例中是data)。第二个参数是要对data变量中找到的每个项目执行的回调函数。这个回调函数还接受两个参数,keyvalue。使用这些变量,我们可以从 JSON 数据中获取所有信息,包括数组键(例如,1、2、3 等)和值;每个对象的名字和姓氏。

最后,我们选择#peopleList元素,并使用append()函数将 HTML 列表项附加到每个peopleJSON 对象的无序列表中。

另请参阅

  • 搜索 JavaScript 对象

  • 对 JavaScript 对象进行排序

搜索 JavaScript 对象

由于对象是在应用程序中保存数据的主要方法,因此能够找到符合特定条件的对象非常有用。jQuery 并未为我们提供直接搜索对象和对象数组的方法;但是,我们可以很容易地创建此功能。

准备工作

使用你喜欢的文本编辑器,创建一个名为recipe-4.html的空白 HTML 文档,并确保你已安装了最新版本的 jQuery。将以下 HTML 代码添加到此 HTML 文件中:

<!DOCTYPE html>
<html>
<head>
  <title>Chapter 3 :: AJAX & JSON</title>
  <script src="img/jquery.min.js"></script>
  <script>

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

确保你更新了对 jQuery 库的引用,以指出它在计算机上保存的位置。这个 HTML 页面为我们提供了一个网页,我们可以在此处执行这个配方的 JavaScript。

如何做…

创建一个 JavaScript 函数,通过执行以下步骤可以轻松地搜索对象:

  1. 在新创建的recipe-4.html页面的脚本标签中,创建一个对象数组,我们可以对其执行搜索:

    var people = [
    {
      title: "Mr",
      firstname: "John",
      lastname: "Doe"
    },
    {
      title: "Mrs",
      firstname: "Jane",
      lastname: "Doe"
    },
    {
      title: "Sir",
      firstname: "Johnathan",
      lastname: "Williams"
    },
    {
      title: "Sir",
      firstname: "Edward",
      lastname: "Tailor"
    }
    ];
    
  2. 在这个对象数组下面,添加以下递归函数,我们可以用它来遍历前面的对象,并根据提供的参数找到匹配项:

    function findObjects(parameter, value, object) {
      var matches = [];
      for (var i in object) {
        if (typeof object[i] == 'object') {
          matches = matches.concat(findObjects(parameter, value, object[i]));
        } else if (i == parameter && object[parameter] == value) {
          matches.push(object);
        }
      }
    return matches;
    }
    
  3. 通过指定要查找的参数、要匹配的值,然后是要搜索的对象/对象来调用该函数:

    var results = findObjects("title", "Sir", people);
    console.log(results);
    
  4. 在浏览器中打开recipe-4.html,然后打开 JavaScript 控制台(在 Chrome 中按 Ctrl + Shift + J);你将看到搜索结果。

工作原理…

首先,创建一个表示人员的对象数组。这不需要是静态数据集,可以像前面的示例中那样从 AJAX 请求中加载。

我们的 findObjects() 函数将允许我们搜索一个对象或对象数组。这个函数接受三个参数。第一个参数是 parameter,即我们想要在其中搜索的对象;在这个例子中是 title。第二个参数是我们想要查找匹配项的实际值;上面的例子使用了 Sir。最后一个参数是我们创建的对象数组。

我们首先在函数内部创建一个空数组,这个数组将保存符合我们指定条件的每个对象:

var matches = [];

使用原生的 JavaScript for 循环,我们可以遍历对象/对象数组。

for (var i in object) {
}

如果我们提供了一个对象数组,object[i] 在每次迭代中将代表数组内的不同对象。如果我们提供了单个对象,那么 i 将在每次迭代中代表所提供对象内的不同属性。

由于 JavaScript 对象也可以包含其他对象或数组,我们需要允许递归,以便能够搜索无限深度的对象。为此,我们首先检查 object[i](当前迭代的对象或属性值)是否为对象。如果是,我们从函数内部调用我们自己的 findObjects() 函数,并将当前对象作为最后一个参数提供:

if (typeof object[i] == 'object') {
  matches = matches.concat(findObjects(parameter, value, object[i]));
}

由于 findObjects() 函数将返回一组匹配项,我们使用 matches = matches.concat() 将返回结果的数组添加到当前匹配项数组中。我们添加了一个 else if 语句来过滤值不是对象的情况。

if (typeof object[i] == 'object') {
  matches = matches.concat(findObjects(parameter, value, object[i]));
} else if (i == parameter && object[parameter] == value) {
  matches.push(object);
}

else if 语句中,我们检查当前属性(由 i 表示)是否与我们提供的参数匹配。如果是,则检查该属性的值是否与我们提供的参数值匹配。如果也是,则使用 matches.push(object) 将当前对象添加到 matches 数组中。最后,一旦我们遍历了所有对象和属性,我们就返回 matches 数组。

在上面的例子中,我们简单地使用 console.log(); 将匹配的对象数组输出到浏览器的 JavaScript 控制台。这个数组可以以任何方式使用,比如填充 HTML 列表元素。

还有更多…

在 JavaScript 对象中搜索通常会成为你应用程序的常见部分。确保将此类函数尽可能地制作成通用的,并且不要将其编码为单一操作。然后,你将能够在应用程序中全局使用此函数,并在整个应用程序中重复使用它。此外,在编写递归函数时要小心,因为很容易创建无限循环和复杂难读的代码。

另请参阅

  • 处理 JSON 数据

  • 对 JavaScript 对象进行排序

对 JavaScript 对象进行排序

除了能够高效地找到符合条件的对象外,你通常还需要将对象按照某种顺序输出。

准备工作

与前一个示例一样,创建一个名为 recipe-5.html 的 HTML 页面,我们可以使用以下代码为此示例添加和执行 JavaScript 代码:

<!DOCTYPE html>
<html>
<head>
  <title>Chapter 3 :: AJAX & JSON</title>
  <script src="img/jquery.min.js"></script>
  <script >

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

更新 jQuery 库的引用,以确保在您的计算机上包含正确的文件。

如何做…

创建一个可重复使用的函数来对 JavaScript 对象进行排序,执行以下逐步说明:

  1. 在您刚刚创建的 recipe-5.html 文件中的脚本标签中,添加以下 JavaScript 代码:

    var people = [
      {
        title: "Mrs",
        firstname: "Jane",
        lastname: "Doe"
      },
      {
        title: "Sir",
        firstname: "Johnathan",
        lastname: "Williams"
      },
      {
        title: "Mr",
        firstname: "John",
        lastname: "Andrews"
      },
      {
        title: "Sir",
    
        firstname: "Edward",
        lastname: "Tailor"
      }
    ];
    
  2. 在此数组下方,添加以下可用于对数组中的 JavaScript 对象进行排序的函数:

    function sortObjectsByParam(param) {
      return function(a, b) {
        if (a[param] == b[param]) { return 0; }
        if (a[param] > b[param]) { return 1; }
        else { return -1; }
      }
    }
    
  3. 使用此函数与原生 JavaScript 的 .sort() 函数如下所示:

    people.sort(sortObjectsByParam("lastname"));
    console.log(people);
    
  4. 在浏览器中打开此网页并查看 JavaScript 控制台,将为您提供我们在步骤 1 中创建的 JavaScript 数组中的对象列表。不同之处在于它们将按姓氏排序,而不是它们的原始顺序。

工作原理…

我们必须有一个对象数组,才能成功使用我们的 .sort() 函数对其进行重新排序。这个对象数组可以是静态的,就像示例中一样,也可以通过 AJAX 请求从服务器加载。

JavaScript 提供了一个 .sort() 函数,它将一个函数作为参数,并将两个参数提供给此回调函数。.sort() 的典型用法如下:

people.sort(function(a, b){
  //Compare objects here
});

ab 参数是数组中的两个对象。我们可以比较这两个对象,并确定哪个对象需要放在另一个对象之前。

在我们的示例中,我们需要一些额外的功能;我们需要能够指定要对其进行排序的参数。由于无法向 .sort() 回调函数提供额外的参数,因此我们将回调包装在另一个函数中,如下所示:

function sortObjectsByParam(param) {
  return function(a, b) {

  }
}

然后,我们可以指定一个属性来对对象进行排序,然后在回调函数中使用。回调函数必须返回 0 或正数或负数。在我们的示例中,0 表示不需要排序,两个对象相等。1 表示应将 a 放在 b 之前,-1 表示应将 b 放在 a 之前。我们可以在回调函数中进行此评估,如下所示:

function sortObjectsByParam(param) {
  return function(a, b) {
    if (a[param] == b[param]) { return 0; }
    if (a[param] > b[param]) { return 1; }
    else { return -1; }
  }
}

我们使用 a[param]b[param] 仅检查对象的指定参数。现在,我们可以将此函数与原生 JavaScript 的 .sort() 函数结合使用,根据指定的参数重新排序我们的对象,如下所示:

$(function(){
  people.sort(sortObjectsByParam("lastname"));
  console.log(people);
});

这将按字母顺序重新排列我们稍早创建的对象数组,按其姓氏排序。因此,对象 Mr John Andrews 将是数组中的第一个对象,依此类推。

还有更多…

与用于搜索对象的函数类似,此函数不应编码为单个操作,以便在整个应用程序中重复使用。可重复使用的代码将使您的应用程序更易于管理和调试。

另请参阅

  • 处理 JSON 数据

  • 搜索 JavaScript 对象

缓存 JSON 和 AJAX 请求

Web 开发人员可以增加其 Web 应用程序的速度的一种方法是限制向 Web 服务器发出的请求数量。确保仅在需要时进行数据调用非常重要。我们可以使用缓存来确保只有在需要新的数据集时才发出请求。

准备工作

确保你的 Web 服务器正在运行,并且你有权限将文件添加到服务器的 Web 根目录中。

如何做…

学习如何通过简单的缓存方法加速你的 JavaScript 应用程序,按照以下说明执行:

  1. 在你的 Web 服务器的 Web 根目录中创建一个名为 request-6.php 的 PHP 文件。使用以下 PHP 代码创建并输出名称列表作为 JSON 数据:

    <?php
      //Create an array of people
      $people = array(
        1 => array(
          "firstname" => "Luke",
          "lastname" => "Skywalker"
        ),
        2 => array(
          "firstname" => "Darth",
          "lastname" => "Vader"
        ),
        3 => array(
          "firstname" => "Mace",
          "lastname" => "Windu"
        )
      );
      //Ensure the browser is expecting the correct content
      //type format and charset
      header("Content-Type: application/json; charset=UTF-8");
      //Encode the array of people into JSON data
      echo json_encode($people);
    
  2. 使用以下 HTML 代码在 Web 服务器的 Web 根目录中创建一个名为 recipe-6.html 的页面,以便你可以向你的 PHP 文件发出 AJAX 请求:

    <!DOCTYPE html>
    <html>
    <head>
      <title>Chapter 3 :: AJAX & JSON</title>
      <script src="img/jquery.min.js"></script>
      <script>
    
      </script>
    </head>
    <body>
      <ul id="peopleList"></ul>
      <button class="getPeople">Get People</button>
    </body>
    </html>
    
  3. 在 HTML 页面的 head 标签中的 script 标签中,添加以下 jQuery 代码以发出 AJAX 请求,以检索在 PHP 文件中创建的 people 数组,然后缓存结果:

    var cache = [];
    $(function(){
      $('.getPeople').click(function(){
        if (cache.length == 0) {
          $.ajax({
              url: '/request-6.php',
              type: 'GET',
              async: false
          }).done(function(data){
              cache = data;
          });
        }
        $('#peopleList').empty();
        $.each(cache, function(key, value){
          $('#peopleList').append("<li>#" + key + " " + value.firstname + " " + value.lastname  + "</li>");
        });
      });
    });
    

工作原理…

现在,让我们详细了解之前执行的步骤。

PHP

请参考本章的上一个示例,处理 JSON 数据,以详细了解这段 PHP 代码的工作原理。

HTML

我们创建的 HTML 页面非常基础,不需要太多解释。我们只是创建了一个无序列表元素,我们可以用 jQuery 填充它,并且一个按钮,用户可以点击它来触发从 PHP 文件加载 JSON 数据的 AJAX 请求。

jQuery

首先,我们创建一个空的 JavaScript 数组,我们可以用来缓存从 AJAX 请求接收到的数据,如下所示:

var cache = [];

然后,在 $(function(){}); 中,这将在页面加载时执行,我们将点击事件处理程序附加到 .getPeople 按钮上。

$(function(){
  $('.getPeople').click(function(){

  });
});

在此事件处理程序的回调函数中,我们通过评估 cache 数组的长度来检查当前是否有任何内容:

if  (cache.length == 0) {

}

如果 cache 数组中没有任何内容,那么我们没有任何缓存的数据。我们需要向我们的 PHP 文件发出 AJAX 请求,以获取 JSON 数据,如下所示的代码片段所示。这将确保仅在需要数据时才进行 AJAX 请求,并且每次点击按钮时不会进行请求。

if  (cache.length == 0) {
  $.ajax({
    url: '/request.php',
    type: 'GET',
    async: false
  }).success(function(data){
    cache = data;
  });
}

在 AJAX 请求成功时,我们将结果存储在我们的 cache 数组中。请注意,我们将 async 属性设置为 false,这意味着在 AJAX 请求之后任何 JavaScript 代码都不会被执行,直到有响应为止。这是为了在 cache 数组填充数据之前防止 HTML 列表被填充的理想解决方案。对于大型应用程序来说,这不是理想的解决方案,因为如果 AJAX 请求花费很长时间响应,这可能会导致浏览器挂起或崩溃。阅读本章的 等待 AJAX 响应 示例,以了解等待 AJAX 请求完成的首选方法。

cache 数组被填充后,我们可以使用它来向我们的 HTML 无序列表中添加项目。我们使用了 jQuery 的 $.each() 函数,它允许我们遍历 cache 数组中的每个对象。对于这些对象中的每一个,我们使用 .append() 来添加一个列表项以及对象中的数据到 #peopleList 列表中。

$('#peopleList').empty();
$.each(cache, function(key, value){
  $('#peopleList').append("<li>#" + key + " " + value.firstname + " " + value.lastname  + "</li>");
});

在我们填充列表之前,我们首先使用 $('#peopleList').empty(); 来清空 DOM 中的列表。这是为了防止额外的按钮点击添加重复的项目。

还有更多…

这种数据缓存方法可以加快你的 Web 应用程序。然而,这种方法对于请求的数据经常变化的情况不太适用,因为用户只有在刷新或重新访问页面时才会得到更新的数据。

jQuery 中的 AJAX 请求有它们自己的一种缓存方式,本质上与浏览器缓存是一样的。通过提供给 $.ajax() 函数的设置,你可以控制这种缓存的工作方式。虽然这种缓存很有用,但它并没有手动缓存方法所提供的同样级别的控制。

创建一个搜索特性

允许用户在你的 Web 应用程序中搜索数据是一个基本原则。这个示例将向你展示如何使用 jQuery 和 AJAX 来创建一个快速高效的搜索功能,后端使用 PHP 和 MySQL。

准备工作

这个方法不仅要求你有一个运行着 PHP5 的 Web 服务器,还需要一个准备好接受 PHP 脚本连接的 MySQL 服务器。

如何做…

了解如何从零开始创建一个搜索特性,这将向你展示有价值的 jQuery 原则在实际操作中的运行,执行以下步骤:

  1. 我们需要创建一个数据库和一张表来存储用户可以搜索的数据。在你的数据库服务器上创建一个名为 jquerycookbook 的数据库,并使用下面的 SQL 代码来创建并填充一张包含一些数据的表:

    USE `jquerycookbook`;
    
    CREATE TABLE IF NOT EXISTS `stationary` (
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
      `title` varchar(128) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
    
    INSERT INTO `stationary` (`id`, `title`) VALUES
    (1, 'Ruler'),
    (2, 'Pencil'),
    (3, 'Pen'),
    (4, 'Rubber'),
    (5, 'Sharpener');
    
  2. 为了让用户能够从他们的浏览器(客户端)搜索到我们的数据库中的数据,我们需要能够根据他们的搜索提取出数据库中的信息。我们可以使用 PHP 来查询 MySQL 数据库,以根据用户通过客户端提供的搜索词来获取数据。在我们能够做到这一点之前,我们需要能够连接到刚刚创建的数据库。在 Web 服务器的根目录下创建一个名为 db.inc.php 的 PHP 文件,并添加以下代码:

    <?php
      $dbhost = 'localhost'; //hostname
      $dbuser = 'root'; //database username
      $dbpass = ''; //database password
      $dbname = 'jquerycookbook'; //database name
    
      $db = new mysqli($dbhost, $dbuser, $dbpass);
    
      $db->select_db($dbname);
      if($db->connect_errno > 0){
        die('ERROR! - COULD NOT CONNECT TO mySQL DATABASE: ' . $db->connect_error);
      }
    
  3. 请确保将$dbhost$dbuser$dbpass的值改为与你的配置匹配。

  4. 在 Web 服务器的根目录下创建一个名为 search.php 的 PHP 文件,并添加以下代码:

    <?php
      //Prepare an object to hold data we are going to send
      //back to the jQuery
      $data = new stdClass;
      $data->success = false;
      $data->results = array();
      $data->error = NULL;
      //Has the text been posted?
      if (isset($_POST['text'])) {
        //Connect to the database
        require_once('db.inc.php');
        //Escape the text to prevent SQL injection
        $text = $db->real_escape_string($_POST['text']);
        //Run a LIKE query to search for titles that are like
        //the entered text
        $q = "SELECT * FROM `stationary` WHERE `title` LIKE '%{$text}%'";
        $result = $db->query($q);
        //Did the query complete successfully?
        if (!$result) {
          //If not add an error to the data array
          $data->error = "Could not query database for search results, MYSQL ERROR: " . $db->error;
        } else {
          //Loop through the results and add to the results
          //array
          while ($row = $result->fetch_assoc()) {
            $data->results[] = array(
              'id' => $row['id'],
              'title' => $row['title']
            );
          }
          //Everything went to plan so set success to true
          $data->success = true;
        }
      }
      //Set the content type for a json object and ensure
      //charset is UTF-8\. Not utf8 otherwise it will not work in IE
      header("Content-Type: application/json; charset=UTF-8");
      //json encode the data
      echo json_encode($data);
    
  5. 在 Web 服务器的根目录下创建一个名为 recipe-7.html 的 HTML 文件,使用以下 HTML 代码:

    <!DOCTYPE html>
    <html>
    <head>
      <title>Chapter 3 :: AJAX & JSON</title>
      <script src="img/jquery.min.js"></script>
      <script src='script-7.js'></script>
      <link href='style-7.css' rel="stylesheet" />
    </head>
    <body>
      <div id='frame'>
        <div class='search'>
          <div class='header'>
            <h1>Chapter 3 :: Search Feature</h1>
            <input type='text' id='text' /> <button id='search'>Search</button>
          </div>
          <div id='results-holder'>
            <div class="loading-holder">
              <div class="loading">Loading...</div>
            </div>
            <ul id='results-list'></ul>
          </div>
        </div>
      </div>
    </body>
    </html>
    
  6. 为了使我们的搜索功能更加吸引人,我们可以使用 CSS 来为我们刚刚创建的 HTML 页面添加样式。您可能已经注意到,在 HTML 页面头部,我们包含了一个名为 style-7.css 的 CSS 文件。创建 style-7.css 文件,将其保存到您的 Web 服务器的 Web 根目录中,并添加以下 CSS 代码:

    /* Include a web font from Google  */
    @import url(http://fonts.googleapis.com/css?family=Denk+One);
    /* Basic CSS for positioning etc */
    body {
      font-family: 'Denk One', sans-serif;
    }
    #frame {
      width: 500px;
      margin: 125px auto auto auto;
      border: solid 1px #CCC;
      /* SOME CSS3 DIV SHADOW */
      -webkit-box-shadow: 0 0 10px #CCC;
      -moz-box-shadow: 0 0 10px #CCC;
      box-shadow: 0 0 10px #CCC;
      /* CSS3 ROUNDED CORNERS */
      -moz-border-radius: 5px;
      -webkit-border-radius: 5px;
      -khtml-border-radius: 5px;
      border-radius: 5px;
      background-color: #FFF;
    }
    .search .header {
      margin: 25px;
    }
    .search .header {
      text-align: center;
    }
    .search .header input {
      width: 350px;
    }
    #results-holder {
      min-height: 200px;
    }
    .loading {
      text-align: center;
      line-height: 30px;
      display: none; /* DONT DISPLAY BY DEFAULT */
    }
    .loading-holder {
      height: 30px;
    }
    /* Styling for the results list */
    #results-list {
      margin: 0;
      padding: 0;
      list-style: none; /* REMOVE THE BULLET POINTS */
    }
    #results-list li {
      line-height: 30px;
      border-bottom: solid 1px #CCC;
      padding: 5px 5px 5px 10px;
        color: #333;
    }
    /* REMOVE THE BORDER FROM THE LAST LIST ELEMENT SO IT DOESN'T CLASS WITH THE FRAME BORDER */
    #results-list li:last-child {
    	border: none;
    }
    
    /* STYLE THE NO RESULTS LIST ITEM */
    #results-list .no-results {
      text-align: center;
      font-weight: bold;
      font-size: 14px;
    }
    
  7. 使用 jQuery,我们将能够接受用户的搜索查询,并将请求发送到我们的 PHP 脚本。在您的 Web 服务器的 Web 根目录中创建一个名为 script-7.js 的 JavaScript 文件。请注意,这也包含在 HTML 文件的头部中。将以下 jQuery 代码添加到此文件中:

    $(function(){
      //Hide the result list on load
      $('#results-list').hide();
      //Click event when search button is pressed
      $('#search').click(function(){
        doSearch();
      });
        //Keypress event to see if enter was pressed in text
        //input
      $('#text').keydown(function(e){
      if(e.keyCode == 13){
        doSearch();
      }
      });
    });
    
    function doSearch() {
      var searchText = $('#text').val();
      //Rehide the search results
      $('#results-list').hide();
      $.ajax({
        url: '/search.php',
        type: 'POST',
        data: {
          'text': searchText
        },
        beforeSend: function(){
          $('.loading').fadeIn();
        },
        success: function(data) {
          $('.loading').fadeOut();
          //Was everything successful, no errors in the PHP
          //script
          if (data.success) {
            $('#results-list').empty();
            if(data.results.length > 0) {
              $.each(data.results, function(){
                $('#results-list').append("<li>" + this.title + "</li>");
              });
            } else {
              $('#results-list').append("<li class='no-results'>Your search did not return any results</li>");
            }
            //Show the results list
            $('#results-list').fadeIn();
          } else {
            //Display the error message
            alert(data.error);
          }
        }
      });
    }
    
  8. 访问您的 Web 服务器上的 recipe-7.html 文件将呈现给您一个简单样式的搜索输入,允许您在我们添加到 MySQL 数据库的静态项上执行搜索。下面的截图与完成搜索后您将看到的类似:操作步骤…

工作原理…

现在,让我们详细了解之前执行的步骤。

SQL

通过 SQL 代码,我们简单地告诉 SQL 脚本使用我们创建的 jquerycookbook 数据库;我们创建一个名为 stationary 的表,然后向表中插入五个静态项。

PHP

我们创建的第一个 PHP 脚本,db.inc.php,只是用来连接到我们创建的数据库,然后允许我们查询其中的数据。我们创建了四个变量来保存数据库服务器的主机名(通常是 localhost)、用户名、密码,以及我们希望连接的数据库的名称。

$dbhost = 'localhost'; //hostname
$dbuser = 'root'; //database username
$dbpass = ''; //database password
$dbname = 'jquerycookbook'; //database name

在我们的 PHP 脚本中有了这些信息后,我们创建一个新的 mysqli 连接,并选择 jquerycookbook 数据库供使用。

$db = new mysqli($dbhost, $dbuser, $dbpass);
$db->select_db($dbname);

最后,我们添加了一些基本的错误处理代码,如果连接到数据库服务器失败,将停止任何进一步的执行。我们还提供了一些关于错误的信息以供调试。

if ($db->connect_errno > 0){
  die('ERROR! - COULD NOT CONNECT TO mySQL DATABASE: ' . $db->connect_error);
}

现在我们有了一个可以调用以连接到数据库的脚本,我们可以编写 PHP 脚本,从客户端获取信息并对数据库执行查询。

首先,我们创建一个名为 $data 的对象,用于保存脚本的结果和任何错误。我们使用 PHP 的 stdClass 来创建此对象,如下所示:

$data = new stdClass;
$data->success = false;
$data->results = array();
$data->error = NULL;

接下来,我们检查客户端请求是否包含一些以 text 为键的 POST 信息。如果没有查询文本,这会防止脚本无谓地运行。

if (isset($_POST['text'])) {

PHP 的isset()函数简单地检查提供的参数是否已设置并可供使用。如果已经有一些数据通过键text发布到脚本中,我们可以通过使用require_once();包含我们的数据库连接脚本来继续连接到数据库。有多种方法可以包含额外的 PHP 文件。我们使用require_once()是因为在没有数据库连接的情况下无法继续执行。如果在使用require_once()时找不到指定的文件,则脚本会提供致命错误并停止执行。

if (isset($_POST['text'])) {
  //Connect to the database
  require_once('db.inc.php');
  //Escape the text to prevent SQL injection
  $text = $db->real_escape_string($_POST['text']);
}

在包含数据库连接文件并连接到数据库之后,我们可以引用在该文件中实例化的$db连接变量。然后我们使用real_escape_string()函数,该函数将从提供的text字符串中删除任何有害字符,以防止安全漏洞,如 MySQL 注入(在dev.mysql.com/tech-resources/articles/guide-to-php-security-ch3.pdf上阅读更多内容)。我们将$_POST['text']传递给此函数,并将结果存储在一个$text变量中,现在我们可以安全地在 MySQL 查询中使用它。

$q = "SELECT * FROM `stationary` WHERE `title` LIKE '%{$text}%'";
$result = $db->query($q);
if (!$result) {
  $data->error = "Could not query database for search results, MYSQL ERROR: " . $db->error;
} else {

}

我们使用$text字符串构造一个 MySQLLIKE查询,然后使用$result = $db->query($q);在数据库上执行查询。我们首先评估$result变量是否为false值,以确定查询是否成功执行。如果查询未成功执行,则在$data对象中存储错误。

如果查询成功执行,我们可以准备将结果发送回客户端,如下所示:

if (!$result) {
  $data->error = "Could not query database for search results,MYSQL ERROR: " . $db->error;
} else {
  while ($row = $result->fetch_assoc()) {
    $data->results[] = array(
      'id' => $row['id'],
      'title' => $row['title']
    );
  }
  $data->success = true;
}

通过使用带有$result->fetch_assoc()while循环,我们能够迭代返回的每个结果从数据库查询。然后,我们可以提取所需的信息,并将结果数组中的每个项目存储在$data对象中。完成此操作后,我们将$data对象的success变量设置为true,这将告诉客户端内部的 jQuery 一切都按计划进行。

最后,我们设置标题以强制 jQuery 期望 JSON 数据,将我们的$data对象编码为 JSON,并将编码数据输出如下:

header("Content-Type: application/json; charset=UTF-8");
echo json_encode($data);

HTML

我们创建的 HTML 页面为用户提供了一个输入框,他们可以在其中输入他们的搜索查询,并提供了一个按钮来提交搜索。它为我们提供了一个无序列表元素来向用户显示结果。我们还使用 jQuery 创建一个显示加载中...消息的 div 元素,这将在进行 AJAX 请求时显示。

CSS

我们创建的 CSS 将我们的 HTML 元素定位在页面上并为每个项目设置样式,以提供更好的用户体验。请注意,我们正在使用 Google 字体为我们的搜索功能添加额外的美学效果;您可以在www.google.com/fonts/上阅读更多相关信息。

jQuery

script-7.js 文件中,我们在页面加载时执行三个操作,如下所示:

$(function(){
  $('#results-list').hide();
  $('#search').click(function(){
    doSearch();
  });
  $('#text').keydown(function(e){
    if(e.keyCode == 13){
      doSearch();
    }
  });
});

首先,我们使用 $('#results-list').hide(); 隐藏结果列表,这样默认情况下它将被隐藏。然后,我们将点击事件处理程序附加到搜索按钮,当单击此按钮时将执行搜索。在此事件处理程序的回调函数中,我们调用 doSearch(); 函数,该函数在我们的 JavaScript 文件中稍后声明。我们在页面加载时执行的最后一个操作是向搜索输入添加 keydown 事件处理程序,以便我们可以检测是否按下了 Enter 键。如果是,我们可以调用 doSearch(); 函数来触发搜索。

doSearch() 函数执行 AJAX 请求,将搜索查询文本发送到 PHP 脚本。它还处理响应并相应地更新 HTML 页面。该函数使用 $('#text').val(); 从搜索输入中获取输入的文本,并将其存储在 searchText 变量中以供使用。它还隐藏 #results-list,以确保在进行 AJAX 请求之前始终隐藏它,为显示加载文本提供空间。

function doSearch() {
  var searchText = $('#text').val();
  $('#results-list').hide();
}

此函数使用 jQuery 提供的 $.ajax() 方法来设置并发出到我们的 search.php 脚本的 AJAX 请求:

$.ajax({
  url: '/search.php',
  type: 'POST',
  data: {
    'text': searchText
  },
  beforeSend: function(){
    $('.loading').fadeIn();
  },
  success: function(data) {
    $('.loading').fadeOut();
  }
});

我们提供给 AJAX 函数的初始参数是我们希望进行请求的 URL、我们希望进行的请求类型以及我们希望随请求发送的数据。我们将请求目标指定为 search.php 文件,将请求类型指定为 POST,这样我们就可以发送数据到 PHP 文件而无需将其放在 URL 中。在数据对象中,我们将 searchText 变量放置在 text 键下,这将被我们之前创建的 PHP 脚本拾取,使其能够使用用户输入的文本。

在这些初始参数之后,我们包含 beforeSend,这允许我们指定在 AJAX 请求发出之前执行的回调函数。我们能够通过此函数使用 $('.loading').fadeIn(); 添加一些动画并显示 .loading div 元素。这将显示 Loading… 文本,告知用户请求正在进行中。在 success 回调函数中,该函数在请求成功且已收到响应时执行,我们能够使用 $('.loading').fadeOut(); 使用一些额外的动画隐藏 Loading… div 元素。

success 回调函数具有数据参数,该参数将保存来自 PHP 文件的所有响应数据。回顾一下 PHP 脚本,您将记得我们创建的 $data 对象用于存储有关响应的信息。我们检查此对象的 success 属性是否设置为 true,这意味着查询成功。

success: function(data) {
  $('.loading').fadeOut();
  if (data.success) {

} else {
  alert(data.error);
  }
}

如果 success 属性未设置为 true 并且出现了问题,我们将使用 alert(data.error); 通过 search.php 脚本创建的错误消息警告用户。

如果data.success被设置为true,我们可以按照以下方式处理搜索结果并更新 HTML 页面:

success: function(data) {
  $('.loading').fadeOut();
  if (data.success) {
    $('#results-list').empty();
    if(data.results.length > 0) {
      $.each(data.results, function(){
        $('#results-list').append("<li>" + this.title + "</li>");
      });
    } else {
      $('#results-list').append("<li class='no-results'>Your search did not return any results</li>");
    }
    $('#results-list').fadeIn();
  } else {
    alert(data.error);
  }
}

if语句内,我们清空结果列表中的任何数据,以防止多次搜索重复结果。我们使用$('#results-list').empty();来执行此操作。然后,我们检查results的长度。如果有结果,我们需要处理它们;否则,我们向用户显示消息,告知他们的搜索没有返回任何结果。以下是代码:

$('#results-list').append("<li class='no-results'>Your search did not return any results</li>");

如果data.results.length > 0条件被评估为true,这意味着有结果要显示,因此,我们使用 jQuery 的$.each()函数来迭代响应中的每个结果,并将它们附加到结果列表中,如下所示:

$.each(data.results, function(){
  $('#results-list').append("<li>" + this.title + "</li>");
});

现在,用户的搜索结果将显示在列表中。

另请参阅

  • 创建自动建议功能

创建自动建议功能

互联网上有大量的自动建议功能。有许多可用于 jQuery 和 jQuery UI 的插件,可以让您快速轻松地将自动建议功能添加到您的网站中。本配方将向您展示如何从头开始创建一个自动建议功能,您可以自定义并添加自己的独特功能。

准备工作

本配方的服务器端代码与上一个配方相似。确保您的 Web 服务器和 MySQL 数据库服务器正在运行并且可以使用。

如何做…

下面是创建自动建议功能的步骤:

  1. 请参考本章的前一配方创建搜索功能,以创建和设置一个静态数据库和search.php脚本。我们将使用完全相同的代码来实现自动建议功能。

  2. 在您的 Web 服务器的 Web 根目录中,创建一个名为recipe-8.html的 HTML 文件。添加以下 HTML 代码以创建自动建议用户界面的基础:

    <!DOCTYPE html>
    <html>
    <head>
      <title>Chapter 3 :: AJAX & JSON</title>
      <script src="img/jquery.min.js"></script>
      <script src='script-8.js'></script>
      <link href='style-8.css' rel="stylesheet" />
    </head>
    <body>
      <div id='frame'>
        <div class='search'>
          <div class='header'>
            <h1>Chapter 3 :: Auto-Suggest</h1>
          </div>
          <div class="suggest-input">
            <input type='text' id='text' />
            <ul class="suggest-list"></ul>
          </div>
        </div>
      </div>
    </body>
    </html>
    
  3. 您可能已经注意到,在我们的recipe-8.html文件的头部,我们已经包含了一个名为style-8.css的级联样式表。创建此文件并将其保存在您的 Web 服务器的 Web 根目录中。添加以下 CSS 代码,将样式和定位应用到recipe-8.html中的 HTML 元素:

    /* Include a web font from Google  */
    @import url(http://fonts.googleapis.com/css?family=Denk+One);
    /* Basic CSS for positioning etc */
    body {
      font-family: 'Denk One', sans-serif;
    }
    #frame {
      width: 500px;
      margin: 125px auto auto auto;
      border: solid 1px #CCC;
      /* SOME CSS3 DIV SHADOW */
      -webkit-box-shadow: 0 0 10px #CCC;
      -moz-box-shadow: 0 0 10px #CCC;
      box-shadow: 0 0 10px #CCC;
      /* CSS3 ROUNDED CORNERS */
      -moz-border-radius: 5px;
      -webkit-border-radius: 5px;
      -khtml-border-radius: 5px;
      border-radius: 5px;
      background-color: #FFF;
    }
    .search .header {
      margin: 25px;
    }
    .search .header {
      text-align: center;
    }
    .suggest-input input {
      width: 440px;
    }
    .suggest-input {
      position: relative;
      padding: 25px;
    }
    /* SUGGESTION LIST STYLES */
    .suggest-list {
      position: absolute;
      width: 424px;
      background-color: #f1f1f1;
      margin: 0;
      left: 25px;
      top: 50px;
      z-index: 100;
      display: none;
      list-style: none;
      padding: 10px;
    }
    
  4. 除了 CSS 文件之外,我们还将script-8.js包含在我们的 HTML 页面中。创建此 JavaScript 文件并添加以下代码:

    $(function(){
      $('#text').keyup(function(e){
        if ($('#text').val().length > 2) {
          $('.suggest-list').show();
          makeSuggestion();
        } else {
          $('.suggest-list').hide();
        }
      });
      $('.search').on("click", ".suggestion", function(){
        $('#text').val($(this).html());
      });
    });
    
    function makeSuggestion() {
      var searchText = $('#text').val();
      $('.suggest-list').empty();
      $.ajax({
        url: '/search.php',
        type: 'POST',
        data: {
          'text': searchText
        },
        beforeSend: function(){
          $('.suggest-list').append("<li class='loading'>Loading...</li>");
        },
        success: function(data) {
          if (data.success) {
            $('.suggest-list').empty();
            if(data.results.length > 0) {
              $.each(data.results, function(){
                $('.suggest-list').append("<li><a href='#' class='suggestion'>" + this.title + "</a></li>");
              });
            } else {
              $('.suggest-list').append("<li class='no-results'>Nothing to suggest...</li>");
            }
          } else {
            alert(data.error);
          }
        }
      });
    }
    
  5. 访问由 Web 服务器提供的recipe-8.html将向您呈现自动建议功能。它将根据输入到文本框中的文本提供建议,而您键入。在用户输入超过两个字符之前,不会提供任何建议。这在以下截图中显示:如何做…

工作原理…

现在,让我们详细了解以前执行的步骤。

SQL 和 PHP

请参考本章的前一配方创建搜索功能,其中详细说明了 SQL 和 PHP 代码的创建过程。

HTML

我们创建的 HTML 文件非常简单。我们创建一个输入框,允许用户输入文本,然后我们创建一个无序列表元素,我们可以使用 jQuery 填充建议。

CSS

我们创建的 CSS 代码为我们的功能添加了基本样式,包括定位主文本输入区域。

这段 CSS 代码的主要任务是定位建议列表,使建议直接显示在输入框下方。为了实现这一点,我们首先需要将.suggest-input div 元素的位置设置为relative。这将允许我们有绝对定位的兄弟元素,而不会让它们漂移到页面的其他区域。

.suggest-input {
  position: relative;
  padding: 25px;
}

有了这个定位设置,我们可以继续为我们的.suggest-list元素添加所需的样式,该元素将保存建议。我们需要将该元素定位在输入框的正下方。这意味着我们需要使.suggest-list元素的宽度与输入框相同。我们还需要确保.suggest-list元素的左和顶部位置被指定,考虑到输入文本框的大小和填充。

.suggest-list {
  position: absolute;
  width: 424px;
  background-color: #f1f1f1;
  margin: 0px;
  padding: 0px;
  left: 25px;
  top: 50px;
  z-index: 100;
  display: none;
  list-style: none;
  padding: 10px;
}

在这段 CSS 中,我们从列表元素中移除任何默认填充和边距,并将其位置设置为绝对。具有绝对定位的任何元素都不会受到页面上其他元素的影响,除了它们的父元素,如果它们具有相对位置的话。这使我们能够设置其左和顶部位置值,精确控制其相对于文本输入框的位置。我们还将此元素的z-index值设置为100,以确保它始终浮在页面上的其他元素之上。最后,我们使用display: none;,这将使此元素默认隐藏,因为我们希望使用 jQuery 动态显示它。

jQuery

在我们的script-8.js文件中,当页面加载时,我们执行两个动作如下:

$(function(){
  $('#text').keyup(function(e){
    if ($('#text').val().length > 2) {
      $('.suggest-list').show();
      makeSuggestion();
    } else {
      $('.suggest-list').hide();
    }
  });
  $('.search').on("click", ".suggestion", function(){
    $('#text').val($(this).html());
  });
});

前一个动作是将一个keyup事件处理程序附加到文本输入上。当用户在输入框中输入字符并释放键时,此事件处理程序将执行。在回调函数中,我们使用$('#text').val();检查文本输入的当前长度。如果此值大于2,我们需要寻找一些建议;所以,我们调用makeSuggestion()函数,该函数在 JavaScript 文件中进一步声明。我们还使用$('.suggest-list').show();显示.suggest-list元素,以便用户能够看到它。如果输入的文本长度小于两个字符,我们只需确保.suggest-list被隐藏,使用$('.suggest-list').hide();

我们在页面加载时执行的另一个动作是附加另一个事件处理程序。此事件处理程序将监听具有.suggestion类的任何元素上的点击。我们使用 jQuery 提供的.on()函数,以便我们可以监听动态添加到 DOM 中的元素的点击事件,这是使用.click()函数不可能的。请参阅第二章中的通过使用 jQuery 事件与用户进行交互,以了解更多关于这些事件处理程序函数的信息。在此事件处理程序的回调函数中,我们使用$(this).html()获取点击元素的 HTML 代码。将其提供给$('#text').val();函数,该函数将更新文本输入的值。这将用于允许用户点击建议并使用其值更新文本输入。

我们的makeSuggestion()函数获取输入元素的文本,并向我们的search.php文件发送 AJAX 请求以查询数据库并查找与用户输入的任何内容相似的内容。然后,此函数获取结果并为用户选择填充.suggest-list列表。

函数的第一部分获取文本输入的当前值并清空.suggest-list无序列表元素。

var searchText = $('#text').val();
$('.suggest-list').empty();

接下来,我们使用$.ajax()函数设置 AJAX 请求。我们使用url参数将search.php文件指定为目标,请求类型为POST,并将输入的文本作为数据提供给要发送到 PHP 文件的数据。请参阅创建搜索功能配方以获取更多关于此的详细信息。

$.ajax({
  url: 'search.php',
  type: 'POST',
  data: {
    'text': searchText
  },
  beforeSend: function(){
    $('.suggest-list').append("<li class='loading'>Loading...</li>");
  },
  success: function(data) {

  }
});

我们使用beforeSend参数并提供一个回调函数,该函数将一个带有.suggest-list元素的列表项附加上文本正在加载……。此回调函数将在进行 AJAX 请求之前执行,允许我们通知用户请求正在加载,如下面的屏幕截图所示:

jQuery

success回调函数在请求成功时执行,这是我们检查数据库查询是否返回所需结果的函数;是否有任何建议可以填充列表。

success: function(data) {
  if (data.success) {
    $('.suggest-list').empty();
    if(data.results.length > 0) {
      $.each(data.results, function(){
        $('.suggest-list').append("<li><a href='#' class='suggestion'>" + this.title + "</a></li>");
      });
    } else {
      $('.suggest-list').append("<li class='no-results'>Nothing to suggest...</li>");
    }
  } else {
    alert(data.error);
  }
}

success回调函数内的data参数保存了从 PHP 文件发送的所有数据。我们在 PHP 中创建的发送回客户端的对象具有success参数,我们可以使用它来检查一切是否按计划进行。

if (data.success) {

} else {
  alert(data.error);
}

如果出现问题,我们将错误消息显示为警报,该消息由 PHP 中的error参数提供。

如果查询成功执行,则首先再次清空建议列表,以删除在beforeSend()回调函数中添加的加载项。然后,我们使用data.results.length检查结果的长度,以查看是否有任何建议可以填充我们的列表元素。如果有的话,我们使用 jQuery 的$.each()函数来遍历每个项并将其附加到我们的.suggest-list元素。我们还使用.suggestion类将建议包装在<a></a>标签中。单击这些建议将触发我们之前创建的事件处理程序,然后使用建议的文本更新文本输入。

这还不止……

由于自动建议功能在现代网站和 Web 应用程序中是如此常见的实现,因此有许多 jQuery 插件可帮助您将此功能添加到您的应用程序中。jQuery UI,即 jQuery 自己的用户界面框架,具有现成的自动建议模块。您应进一步调查此功能,以查看您的应用程序是否可以从此现成的解决方案中受益。第九章,jQuery UI,专门介绍了 jQuery UI,正如其名称所示,您还将找到一个关于实现自动完成功能的整个食谱。

另请参阅

  • 创建搜索功能

等待 AJAX 响应

jQuery AJAX 请求的默认行为是异步运行,这意味着您可以同时运行许多 AJAX 请求或其他 JavaScript 进程。如果使用默认设置调用$.ajax()函数,则此 AJAX 请求之后的任何 JavaScript 代码都将在等待响应的情况下执行。在大多数情况下,这是期望的行为,但有一些情况下,您希望在等待 AJAX 调用的响应之前阻止进一步执行。这可能是因为您需要从第一个 AJAX 调用获取一些信息来进行第二个调用,或者只是您的应用程序在运行第二个调用之前需要第一个调用的数据。有几种方法可以实现这一点;请参考本章的缓存 JSON 和 AJAX 请求部分,看看一个非常基本的实现,其中您只需关闭异步行为。但首选的实现是使用 jQuery 的.when().done()函数。

准备工作

确保您的 Web 服务器正在运行,并且您有权限向 Web 根目录添加文件。

如何实现…

通过执行以下步骤来了解使用 jQuery 等待 AJAX 响应的正确方法:

  1. 在您的 Web 服务器的 Web 根目录中创建一个名为recipe-9.html的 HTML 文件。添加以下代码,其中有一个按钮可以触发一系列 AJAX 请求,并且有一个可以使用响应信息更新的元素:

    <!DOCTYPE html>
    <html>
    <head>
      <title>Chapter 3 :: AJAX & JSON</title>
      <script src="img/jquery.min.js"></script>
       <script src="img/script-9.js"></script>
    </head>
    <body>
      <button class="load">Load</button>
      <div class="info"></div>
    </body>
    </html>
    
  2. 为了能够等待一组 AJAX 请求,我们需要能够成功地调用 Web 服务器。在 Web 服务器的网站根目录中创建一个名为loading1.php的 PHP 文件,并添加以下代码来模拟一个有效的 PHP 脚本。在你的应用程序中,这可以是任何 PHP 脚本。

    <?php
    for ($i = 1; $i <= 2; $i++) {
      sleep(1);
    }
    echo "Call 1 complete.";
    
  3. 在 Web 服务器的网站根目录中创建另一个名为loading2.php的 PHP 文件,并添加以下代码:

    <?php
    for ($i = 1; $i <= 5; $i++) {
      sleep(1);
    }
    echo "Call 2 complete.";
    
  4. 你可能已经注意到在 HTML 页面的头部,我们包含了script-9.js。创建这个文件并将其保存在 Web 服务器的网站根目录中,添加以下代码:

    $(function(){
      $('.load').click(function(){
        $.when(call1(), call2()).done(function(c1, c2){
          $('.info').append("Both AJAX requests complete!");
        });
      });
    });
    function call1() {
      return $.ajax({
        url: '/loading1.php',
        type: 'GET'
      }).success(function(data){
        $('.info').append(data);
      });
    }
    function call2() {
      return $.ajax({
        url: '/loading2.php',
        type: 'GET'
      }).success(function(data){
        $('.info').append(data);
      });
    }
    
  5. 在 Web 浏览器中打开recipe-9.html,点击Load按钮将给你每个 AJAX 调用的输出。最后,你将看到.done()函数的输出,它只有在两个 AJAX 请求都完成后才会执行。

工作原理...

现在,让我们更详细地了解之前执行的步骤。

HTML

我们非常基本的 HTML 页面只是创建一个按钮,来触发 AJAX 请求,并为我们提供一个 HTML 元素,用于从响应中更新数据。

PHP

我们创建的两个 PHP 脚本只是模拟 AJAX 调用的终点。两个脚本几乎是相同的,只有两处细微的差异。loading1.php脚本循环两次,调用 PHP 的sleep()方法,并提供1作为参数。这将在for循环的每次迭代中暂停脚本 1 秒钟。

<?php
  for ($i = 1; $i <= 2; $i++) {
    sleep(1);
  }
  echo "Call 1 complete.";
?>

for循环执行后,脚本输出Call 1 complete消息,然后可以使用 jQuery 在 Web 浏览器中显示。第二个脚本loading2.php也是一样的,只是它的for循环迭代五次,我们提供了一个不同的输出来区分这两个脚本。

这两个脚本循环的次数不同,以确保前一个脚本会先完成,这样我们可以展示我们可以在我们的 jQuery 代码中等待两个脚本都完成。

jQuery

在我们的 JavaScript 文件中,我们为.load按钮附加一个点击事件处理程序,在页面加载时将创建这个按钮。在这个事件的回调函数中,我们使用 jQuery $.when()函数,并将call1()call2()函数的结果作为参数提供。然后我们在$.when()函数的末尾链接.done(),这将在when()函数完成后执行。在.done()函数中,我们提供一个回调函数,它允许我们为$.when()提供的每个函数提供一个参数。由于我们在$.when()中提供的函数是 AJAX 请求,所以.done()函数的回调中提供的参数将包含每个 AJAX 请求的响应、状态和jqXHR对象。

jqXHR对象是 jQuery $.ajax() 函数的返回值,其中包含有关 AJAX 请求的大量信息。直到call1()call2()从各自的 AJAX 请求接收到完整响应并完成执行之前,.done()函数将不会被执行。

$(function(){
  $('.load').click(function(){
    $.when(call1(), call2()).done(function(c1, c2){
      $('.info').append("Both AJAX requests complete!");
    });
  });
});

.done()函数的回调中,我们向.infoHTML 元素附加一些文本,显示$.when()中的两个 AJAX 调用都已完成。

我们创建的两个调用函数简单地返回$.ajax(),它们都会向我们创建的 PHP 文件发出GET请求。对于这两个 AJAX 请求,我们都附加了.success()函数,一旦相应的 AJAX 调用成功,该函数就会被执行。在.success()的回调函数中,我们使用$('.info').append();将调用的响应附加到.infoHTML 元素上。

如果您使用浏览器访问您的 Web 服务器的根目录并选择加载按钮,您将首先看到从loading1.php脚本添加到.info div 元素的响应。不久后,您将看到从loading2.php脚本和.done()回调添加的文本的响应。

另请参见

  • 缓存 JSON 和 AJAX 请求

第四章:用 jQuery 效果添加引人入胜的视觉效果

在本章中,我们将涵盖:

  • 滑动页面元素

  • 隐藏和显示元素

  • 淡入淡出元素

  • 切换效果

  • 停止效果

  • 链接效果

  • 创建一个基本的相册

  • 创建一个闪烁的按钮

  • 使用效果删除元素

介绍

本章将向您展示如何向您的界面添加简单的效果,以增强网站的整体美观度和用户体验。向元素添加基本效果可以对用户的印象产生巨大影响。jQuery 提供了让开发人员快速添加效果(如滑动、淡入淡出、隐藏等)的功能。

滑动页面元素

滑动页面元素的能力使开发人员能够创建一系列接口,如手风琴。这个食谱将向您展示如何将滑动效果应用于一系列元素。

准备工作

使用你喜欢的文本编辑器或 IDE,在一个易于访问的位置创建一个空白的 HTML 页面,并将此文件保存为recipe-1.html。确保你已经在与此 HTML 文件相同的位置下载了最新版本的 jQuery。

如何做…

通过执行以下步骤学习如何使用 jQuery 滑动页面元素:

  1. 将以下 HTML 代码添加到recipe-1.html中。确保将 jQuery 库的源位置更改为下载并放置在您计算机上的最新版本 jQuery 的位置。

    <!DOCTYPE html>
    <html>
    <head>
      <script src="img/jquery.min.js"></script>
      <script src="img/recipe-1.js"></script>
      <title>Chapter 4 :: JQuery Effects</title>
      <link type="text/css" media="screen" rel="stylesheet" href="recipe-1.css" />
    </head>
    <body>
      <div class="frame">
        <div class="actions">
          <button id="down">Slide Down</button>
          <button id="up">Slide Up</button>
        </div>
        <div class="box one"></div>
        <div class="box two"></div>
        <div class="box three"></div>
        <div class="box four"></div>
      </div>
    </body>
    </html>
    
  2. 除了 jQuery 库文件之外,您可能还注意到我们还包含了一个名为recipe-1.js的第二个 JavaScript 文件。创建此 JavaScript 文件并将其保存在与 HTML 文件相同的目录中。将以下 JavaScript 代码添加到recipe-1.js文件中:

    $(function(){
      $('#up').click(function(){
        $('.one').slideUp(4000);
        $('.two').slideUp(3000);
        $('.three').slideUp(2000);
        $('.four').slideUp(1000);
      });
      $('#down').click(function(){
        $('.one').slideDown(4000);
        $('.two').slideDown(3000);
        $('.three').slideDown(2000);
        $('.four').slideDown(1000);
      });
    });
    
  3. 除了这两个 JavaScript 文件,我们还包含了一个 CSS 文件,为我们的 HTML 元素添加了一些样式。在同一目录中创建recipe-1.css文件,并添加以下代码:

    .frame {
      width: 530px;
      height: 190px;
      margin: 50px auto auto auto;
      background-color: #E1E1E1;
      padding: 10px;
    }
    .frame .box {
      width: 125px;
      height: 125px;
      float: left;
      margin-right: 10px;
    }
    .frame .box:last-child {
      margin-right: 0;
    }
    .frame .actions {
      background-color: #333333;
      margin-bottom: 10px;
      text-align: center;
      padding: 10px;
    }
    .frame .actions button {
      height: 35px;
    }
    .one {
      background-color: red;
    }
    .two {
      background-color: green;
    }
    .three {
      background-color: blue;
    }
    .four {
      background-color: orange;
    }
    
  4. 在网络浏览器中打开recipe-1.html,您应该看到一个类似以下截图的网页:如何做…

  5. 单击向上滑动按钮,以看到应用于每个彩色框元素的向上滑动效果,速度各异;然后单击向下滑动以查看相反效果。

它是如何工作的…

现在,让我们详细了解以前执行的步骤。

HTML

我们为此食谱创建的 HTML 文件简单地使用 div 元素创建了四个框,然后提供了两个按钮,可与 jQuery 结合使用来触发元素效果。

jQuery

我们将所有 JavaScript 代码都包裹在$(function(){});中。这将确保我们的代码在页面加载时执行。在函数内部,我们按照以下代码片段所示,将点击事件附加到每个按钮:

$('#up').click(function(){
  $('.one').slideUp(4000);
  $('.two').slideUp(3000);
  $('.three').slideUp(2000);
  $('.four').slideUp(1000);
});
$('#down').click(function(){
  $('.one').slideDown(4000);
  $('.two').slideDown(3000);
  $('.three').slideDown(2000);
  $('.four').slideDown(1000);
});

.click() 函数允许我们在用户点击相应按钮后执行一组代码。在每个 .click() 方法的回调函数中,我们选择每个框的 div 元素,并使用 jQuery 的 .slideUp().slideDown() 函数,具体取决于用户单击了哪个按钮。

jQuery 的幻灯片函数允许您指定一系列参数。在上面的例子中,我们已经指定了效果持续时间(以毫秒为单位)。这使我们能够控制每个框元素向上或向下滑动所花费的时间,从而提供瀑布效果。

CSS

我们创建的 CSS 文件添加了样式并定位了每个 HTML 元素,使我们能够最好地展示 jQuery 的幻灯片功能。它允许我们更改每个框的背景颜色,并允许我们将界面居中对齐。

还有更多...

在前面的例子中,如果您多次单击 向上滑动向下滑动 按钮,您可能会注意到不同框元素之间的一些闪烁。这种闪烁是因为当向上滑动效果完成时,框元素的 CSS display 属性被设置为 none。这意味着该元素不仅将不可见,而且还不会影响任何相邻元素的位置。

因此,将设置为左浮动的元素会有更多空间向左移动,因为完成其向上滑动效果的框元素不再妨碍。如下截图所示:

还有更多...

在这里,您可以看到第二个绿色框元素的显示值设置为 none,导致其他框元素进一步向左浮动。当幻灯片动画已经多次触发并且元素必须向左移动以使其他元素变得不可见时,显示可能会闪烁更多。可以通过不允许触发多次触发效果来防止此类问题。在本章后面的 创建基本相册 配方中已经解释了这个问题的一个简单解决方案。

另请参阅

  • 淡入淡出元素

  • 隐藏和显示元素

  • 创建基本的相册

隐藏和显示元素

jQuery 包含一些函数,可以让您简单地隐藏和显示元素,尽管您可以将这些函数与其他效果结合使用。

准备就绪

创建一个名为 recipe-2.html 的新 HTML 文件,并将其保存到与您的 jQuery 库相同的文件夹中。

如何做…

通过执行以下步骤,了解如何使用 jQuery 轻松隐藏和显示 DOM 中的元素:

  1. recipe-2.html 中,添加以下 HTML 代码。确保对 jQuery 库的引用指向您下载版本的正确位置和文件名。

    <!DOCTYPE html>
    <html>
    <head>
      <title>Chapter 4 :: JQuery Effects :: Recipe 2</title>
      <script src="img/jquery.min.js"></script>
      <script src="img/recipe-2.js"></script>
    </head>
    <body>
    <button class="show">Show</button>
    <button class="hide">Hide</button>
    <p class="text">Hiding and showing HTML elements with jQuery is so easy!</p>
    </body>
    </html>
    
  2. 创建一个名为 recipe-2.js 的 JavaScript 文件,并将其保存在与您刚刚创建的 HTML 文件相同的目录中。将以下 JavaScript 代码添加到此文件中:

    $(function(){
      $('#show').click(function(){
          $('.text').show();
      });
      $('#hide').click(function(){
          $('.text').hide();
      });
    });
    
  3. 在网页浏览器中打开recipe-2.html将呈现出一个非常基本的网页,其中包含两个按钮和一些文本。单击显示隐藏按钮将在文本上执行相关效果,演示如何使用 jQuery 显示和隐藏元素是多么简单。

工作原理…

现在,让我们详细了解之前执行的步骤。

HTML

此配方中使用的 HTML 代码非常基础,需要很少的解释。HTML 代码创建了一个带有两个按钮的网页。每个按钮都有自己的 ID——showhide。还有一个具有text类的单个段落元素。jQuery 将使用这些 ID 来监听点击事件并在段落元素上执行效果。

jQuery

与前一篇配方类似,我们为每个按钮附加了一个点击事件处理程序。这使我们能够根据点击了哪个按钮来执行效果。为此,我们使用以下代码:

$('#show').click(function(){
  $('.text').show();
});
$('#hide').click(function(){
  $('.text').hide();
});

要执行显示和隐藏效果,我们使用相应的 jQuery 函数show()hide()。这些 jQuery 函数简单地切换所选元素的显示属性(在本例中,段落元素具有text类)。将display属性设置为none可隐藏元素;将其设置为block可显示元素。

还有更多…

使用 jQuery 的show()hide()函数有额外的好处。使用 jQuery,您可以根据它们的内部 HTML 代码显示和隐藏元素。您还可以将show()hide()函数与其他 jQuery 效果或动画一起使用。

参见

  • 淡入淡出元素

  • 滑动页面元素

淡入淡出元素

如果仅仅显示或隐藏元素还不够,jQuery 提供了淡入淡出 HTML 元素的功能。此配方利用了 jQuery 的淡入和淡出功能,在选择显示或隐藏元素时添加了更多效果。

准备工作

创建一个名为recipe-3.html的空白 HTML 文件,并将其保存在与最新版本的 jQuery 相同的目录中。

如何做…

使用 jQuery 执行以下步骤来淡入淡出 DOM 元素:

  1. 将以下 HTML 代码添加到recipe-3.html,确保对 jQuery 库的引用正确:

    <!DOCTYPE html>
    <html>
    <head>
      <title>Chapter 4 :: JQuery Effects :: Recipe 3</title>
      <script src="img/jquery.min.js"></script>
      <script src="img/recipe-3.js"></script>
      <link type="text/css" media="screen" rel="stylesheet" href="recipe-3.css" />
    </head>
    <body>
      <div class="frame">
        <div class="top">
          <label>Add Item:</label>
          <input type="text" id="new-item" />
          <button id="add-new-item">Add</button>
        </div>
        <ol class="list"></ol>
      </div>
    </body>
    </html>
    
  2. 在相同目录中创建一个 CSS 文件。将其保存为recipe-3.css,并添加以下代码来为 HTML 页面设置样式:

    .frame {
      width: 500px;
      min-height: 200px;
      margin: 50px auto auto auto;
      background-color: #E1E1E1;
      padding: 10px;
    }
    .top {
      background-color: #333333;
      padding: 10px;
      text-align: center;
      color: #FFF;
    }
    .list li {
      line-height: 30px;
    }
    
  3. 创建一个名为recipe-3.js的 JavaScript 文件,并添加以下 jQuery 代码:

    $(function(){
      $('#add-new-item').click(function(){
        var item = $('#new-item').val();
        if (item.length > 0) {
          var newItem = $("<li>" + item + "</li>").fadeIn();
          $('.list').append(newItem);
          $('#new-item').val("");
        }
      });
    });
    
  4. 在网页浏览器中打开recipe-3.html,你将看到一个类似以下截图的网页:如何做…

  5. 添加项目文本框中输入一些文本,然后单击添加按钮将使用 jQuery 淡入效果将输入的文本追加到列表中。

工作原理…

现在,让我们详细了解之前执行的步骤。

HTML

HTML 代码创建了一个包含文本输入和按钮以及一个空有序列表元素的简单界面,然后可以使用 jQuery 填充它。

CSS

添加了一个 CSS 文件以定位和样式化简单的用户界面,这样我们就可以更好地用 jQuery 展示淡入效果。

jQuery

首先,jQuery 代码使用以下代码将一个点击事件附加到添加按钮:

$(function(){
  $('#add-new-item').click(function(){

  });
});

我们在此回调函数中添加了以下代码,以提供所需的效果,使用fadeIn()函数将输入文本添加到列表中:

var item = $('#new-item').val();
if (item.length > 0) {
var newItem = $("<li>" + item + "</li>");
$('.list').append(newItem).fadeIn();
$('#new-item').val("");
}

此代码创建了item变量,并使用$('#new-item').val()将输入框的值赋给它。然后我们检查这个值的长度是否大于零,因为我们不想向列表中添加空白项。我们可以使用 JavaScript 简单地使用variablename.length(在本例中为item.length)来检查字符串的长度。

在这个if语句内部,我们创建另一个名为newItem的变量。我们将一个新创建的 HTML 列表项元素赋值给它,值是来自输入框的item变量。我们使用 jQuery 的选择器($())将列表项封装起来,这使我们能够对此 DOM 元素使用fadeIn()函数。

现在我们有了一个列表项,我们可以使用 jQuery 提供的append()函数将其追加到具有类名list的有序列表元素中。这将把新创建的 DOM 元素添加为有序列表的最后一个子元素。因为我们在这个 DOM 元素上使用了fadeIn()函数,它首先会隐藏,然后淡入,从而得到我们想要的效果。

还有更多...

在本文中,我们使用了fadeIn()函数,它允许我们使用淡入效果将一个不可见的元素变为可见。jQuery 还为我们提供了一个fadeOut()函数,它提供了相反的功能。这两个函数都接受一系列参数,允许开发人员调整行为。主要参数是持续时间,它允许我们以毫秒为单位指定元素淡入或淡出的时间。阅读有关这些函数的可用选项的更多信息,请访问api.jquery.com/fadeIn/

此外,jQuery 提供了一个fadeTo()函数,允许您在效果完成后不完全隐藏或显示元素,调整元素的不透明度。了解更多功能,请访问api.jquery.com/fadeTo/

另请参阅

  • 使用效果删除元素

  • 创建一个基本的照片库

  • 创建一个闪烁的按钮

切换效果

许多 jQuery 效果都有相反的功能,例如hide()show()以及fadeIn()fadeOut()。到目前为止,本章中的代码示例已经分别处理了每一个函数;例如,一个按钮用于显示,另一个按钮用于隐藏。对于其中一些函数,jQuery 提供了能够切换这些相反效果的能力。这是有益的,因为我们不需要单独处理每种情况,或者决定我们需要使用其中的哪一个。本文将查看切换功能,并向您展示如何使用它们。

准备工作

在您喜欢的文本编辑器或 IDE 中,创建一个名为recipe-4.html的空白 HTML 文件,并将其保存在与您的 jQuery 库相同的目录中。

操作步骤…

  1. 将以下 HTML 代码添加到recipe-4.html以创建一个基本的网页:

    <!DOCTYPE html>
    <html>
    <head>
      <script src="img/jquery.min.js"></script>
      <script src="img/recipe-4.js"></script>
      <title>Chapter 4 :: JQuery Effects :: Recipe 4</title>
    </head>
    <body>
      <div>
        <button class="fadeToggle">Toggle Fade!</button>
        <button class="slideToggle">Toggle Slide!</button>
        <button class="hideToggle">Toggle Hide!</button>
      </div>
      <p class="text">Here is some text that can be faded in and out! Here is some text that can be faded in and out! Here is some text that can be faded in and out! Here is some text that can be faded in and out! Here is some text that can be faded in and out! Here is some text that can be faded in and out! Here is some text that can be faded in and out! Here is some text that can be faded in and out! Here is some text that can be faded in and out! Here is some text that can be faded in and out! Here is some text that can be faded in and out! Here is some text that can be faded in and out!</p>
    </body>
    </html>
    
  2. 您可能已经注意到我们在此 HTML 页面中包含了一个 JavaScript 文件。在与recipe-4.html相同的目录中创建此 JavaScript 文件,并将其保存为recipe-4.js。将以下 jQuery 代码添加到此文件中,以将点击事件处理程序附加到 HTML 中的按钮元素:

    $(function(){
      $('.fadeToggle').click(function(){
        $('.text').fadeToggle();
      });
      $('.slideToggle').click(function(){
        $('.text').slideToggle();
      });
      $('.hideToggle').click(function(){
        $('.text').toggle();
      });
    });
    
  3. 在 web 浏览器中打开recipe-4.html,您应该看到一个类似于以下截图的网页:操作步骤…

  4. 单击其中一个按钮将切换相关效果并将其应用于段落元素。

工作原理…

现在,让我们详细了解先前执行的步骤。

HTML

本示例中的 HTML 代码创建了一个带有一些文本的段落元素。该元素具有text类名,允许我们选择此元素并执行一系列效果。除了这个段落元素之外,HTML 还提供了三个不同的按钮。每个按钮都有不同的类名,允许我们使用 jQuery 检测每个单独的点击并根据点击的按钮执行不同的效果。

jQuery

本示例中的 jQuery 代码非常基础。在页面加载时,我们为每个按钮附加一个点击事件处理程序。每个点击事件处理程序在其回调函数内部有一个不同的切换功能。

jQuery 的切换函数确定了所选元素的状态,然后执行相反的效果。这意味着我们不需要将此逻辑编程到我们的应用程序中,而可以将其卸载到 jQuery。通过使用toggleFade()函数,我们可以使用一行代码来淡入或淡出段落元素,而无需针对每种情况编码,就像我们在先前的示例中所做的那样。对于执行滑动动画的slideToggle()方法也是如此。最后,我们可以使用toggle方法,它简单地隐藏或显示所选元素。

更多内容……

与其他 jQuery 效果函数一样,切换函数还可以接受一组可选参数。主要参数是效果持续时间。以下代码将强制幻灯片效果持续 1000 毫秒:

$('.slideToggle').click(function(){
$('.text').slideToggle(1000);
});

您可以在 jQuery API 文档中阅读有关其他可用选项的信息,该文档位于api.jquery.com/slideToggle/

停止效果

随着您的应用程序的增长以及开始使用更复杂的效果,您可能希望能够停止这些效果和转换。这可能是由于用户动作导致不再需要当前效果或某种其他形式的事件。

准备工作

创建一个名为recipe-5.html的空白 HTML 文档,并将其保存到最新版本的 jQuery 库所在的相同目录中。

操作步骤…

学习通过执行以下步骤停止 jQuery 效果:

  1. 将以下 HTML 代码添加到recipe-5.html中,以创建一个基本的网页,用于演示如何停止效果:

    <!DOCTYPE html>
    <html>
    <head>
      <script src="img/jquery.min.js"></script>
      <script src="img/recipe-5.js"></script>
      <title>Chapter 4 :: JQuery Effects :: Recipe 5 </title>
      <link type="text/css" media="screen" rel="stylesheet" href="recipe-5.css" />
    </head>
    <body>
    <div class="frame">
      <div class="actions">
        <button id="slide">Slide</button>
        <button id="stop">Stop</button>
        <button id="Finish">Finish</button>
      </div>
      <ul class="output"></ul>
      <div class="slideMe"></div>
    </div>
    </body>
    </html>
    
  2. 为了更好地演示 jQuery 效果,我们需要添加一些 CSS 代码来样式化和定位recipe-5.html中的 HTML 元素。在同一目录中创建一个名为recipe-5.css的 CSS 文件,并添加以下代码:

    .frame {
      width: 600px;
      margin: auto;
      background-color: #CCC;
      padding: 10px;
    }
    .actions {
      padding: 10px;
      background-color: #333;
      text-align: center;
    }
    .slideMe {
      background-color: green;
      height: 150px;
      margin-top: 10px;
    }
    
  3. 要启动和停止 jQuery 效果,请创建一个名为recipe-5.js的 JavaScript 文件,并将其保存在与 HTML 和 CSS 文件相同的目录中。添加以下 jQuery 代码:

    $(function(){
      $('#slide').click(function(){
        $('.slideMe').slideToggle(1000, function(){
          $('.output').append("<li>Slide effect completed.</li>");
        });
      });
      $('#stop').click(function(){
        $('.slideMe').stop();
      });
      $('#finish').click(function(){
        $('.slideMe').finish();
      });
    });
    
  4. 在 Web 浏览器中打开recipe-5.html,您将看到一个类似以下屏幕截图的网页:操作步骤…

  5. 单击Slide按钮将开始该效果,绿色框 division 元素将开始向上滑动 1000 毫秒。单击Stop按钮将在您单击它的点停止效果,Finish按钮将立即完成效果。

工作原理…

现在,让我们详细了解之前执行的步骤。

HTML

我们这个教程的简单 HTML 为我们提供了一个可以应用效果的 division 元素,一些可以用于触发 jQuery 代码的按钮,以及我们可以用来输出有关执行的 jQuery 代码的一些信息的列表。

CSS

包含在 HTML 页面中的 CSS 代码使我们能够以一种能够轻松演示本教程中效果的方式定位每个 HTML 元素。

jQuery

我们在 HTML 页面中为三个按钮附加了三个不同的点击事件处理程序,通过使用它们的 ID 进行选择:slidestopfinish。在这些事件处理程序的回调函数中,我们使用以下代码启动幻灯片效果:

$('#slide').click(function(){
$('.slideMe').slideToggle(1000, function(){
  $('.output').append("<li>Slide effect completed.</li>");
});
});

我们使用slideToggle()函数来启动滑下或滑上效果,这取决于slideMedivision 元素当前是否可见。我们向slideToggle()函数提供了两个参数。第一个参数是我们希望滑动效果生效的持续时间。第二个参数是一个回调函数,一旦动画完成,将执行该函数。

在这个回调函数中,我们向具有类名output的无序列表元素追加了一个列表项。这意味着当幻灯片效果完全完成时,将在output列表中可见一个新的列表项。我们这样做是为了演示停止效果和完成效果之间的区别,后面的部分将对此进行描述。

另外两个事件处理程序,如下面的代码片段所述,以与先前提到的事件处理程序相同的方式选择slideMedivision 元素,除了这些不会启动一个效果,而是停止当前的效果:

$('#stop').click(function(){
  $('.slideMe').stop();
});
$('#finish').click(function(){
  $('.slideMe').finish();
});

stop()函数将停止在所选元素上当前正在运行的任何效果。如果滑动向上效果已经完成一半,您单击了Stop,您将看到一半绿色的slideMe分区元素。stop()函数不会完成滑动效果,因此slideToggle()回调函数不会被执行,并且不会向输出列表添加列表项。相反,finish()函数会立即完成在所选元素上正在执行的任何效果。这意味着如果滑动向上效果已经完成一半,您单击了FinishslideMe分区元素将立即变为不可见,然后向输出列表添加一个新项,上面写着滑动效果已完成。如果在效果回调函数中存在对您的应用程序至关重要的代码,您可以使用finish()来确保它被执行。或者,您可能不想执行此代码和/或想要明显地停止效果;在这种情况下,您将使用stop()

串联效果

jQuery 允许我们将不同的效果函数链到单个选定元素上。这使我们能够轻松地按顺序执行多个效果。

如何操作…

通过执行以下步骤,学习使用 jQuery 的强大功能来编写更好的代码:

  1. 创建一个名为recipe-6.html的空白 HTML 文件,并将其保存在计算机上易于访问的位置。将以下 HTML 代码添加到此文件中,并确保更新对 jQuery 库的引用:

    <!DOCTYPE html>
    <html>
    <head>
      <title>Chapter 4 :: JQuery Effects :: Recipe 6</title>
      <script src="img/jquery.min.js"></script>
      <script src="img/recipe-6.js"></script>
      <link type="text/css" media="screen" rel="stylesheet" href="recipe-6.css" />
    </head>
    <body>
      <button id="start">Start</button>
      <div class="box"></div>
    </body>
    </html>
    
  2. 创建一个名为recipe-6.css的 CSS 文件,并添加以下代码:

    .box {
      width: 200px;
      height: 200px;
      background-color: red;
    }
    Create a JavaScript file and save it as recipe-6.js. Add the following JavaScript code.
    $(function(){
      $('#start').click(function(){                                              $('.box').fadeOut().fadeIn().slideUp().slideDown().fadeTo(1000, 0.1).fadeTo(1000, 1);
      });
    });
    
  3. 在网页中打开recipe-6.html文件,然后单击Start按钮。红色框将执行一系列效果。

工作原理…

本示例提供了一个非常简单的例子,说明了如何串联 jQuery 提供的不同效果函数。在此示例中,我们对盒子 div 元素执行fadeOut()fadeInslideUp()slideDown()和两个fadeTo()效果。由于以下代码位于start按钮的单击事件处理程序回调函数中,因此这些效果将依次执行:

$('.box').fadeOut().fadeIn().slideUp().slideDown().fadeTo(1000, 0.1).fadeTo(1000, 1);

fadeTo()函数会为选定的元素动画并改变其不透明度,它们都被提供了两个参数。第一个参数是效果持续的毫秒数,第二个是效果应该完成的不透明度。

参见

  • 创建基本的图库

创建基本的图库

大多数人都知道网络上有许多 jQuery 图库实现可供使用;其中许多是 jQuery 插件,可以快速实现。学习如何创建自己的图库也有好处。您将深入了解其中一些插件的工作原理,从而更轻松地定制它们以更好地满足您的需求。您还将了解更多关于 jQuery 的强大功能以及如何在本书中前面学到的技能。

准备工作

我们首先需要一个名为recipe-7.html的空白 HTML 文件,保存在与最新版本的 jQuery 相同的目录中。要创建一个图像画廊,我们还需要一些图像。在与recipe-7.html文件相同的目录中创建一个名为images的文件夹,并保存至少八张在 Internet 上免费可用的图像。

如何做…

通过执行以下步骤学习如何从头开始使用 jQuery 创建一个吸引人的相册:

  1. 将以下 HTML 代码添加到recipe-7.html以创建我们的网页和图像画廊 HTML 模板:

    <!DOCTYPE html>
    <html>
    <head>
      <script src="img/jquery.min.js"></script>
      <script src="img/recipe-7.js"></script>
      <link rel="stylesheet" type="text/css" href="recipe-7.css" media="screen" />
      <title>Chapter 4 :: JQuery Events :: Recipe 7 - jQuery image gallery</title>
    </head>
    <body>
      <div class="gallery" data-thumb-width="150">
        <div class="frame">
          <img src="img/Chrysanthemum.jpg" />
          <img src="img/Desert.jpg" />
          <img src="img/Hydrangeas.jpg" />
          <img src="img/Jellyfish.jpg" />
          <img src="img/Koala.jpg" />
          <img src="img/Lighthouse.jpg" />
          <img src="img/Penguins.jpg" />
          <img src="img/Tulips.jpg" />
        </div>
        <div class="bottom">
          <a href="#" class="arrow left-arrow" data-direction="left"><i class="arrow-left"></i></a>
          <a href="#" class="arrow right-arrow" data-direction="right"><i class="arrow-right"></i></a>
          <div class="thumbs"></div>
        </div>
      </div>
    </body>
    </html>
    
  2. 更新 frame division 元素内每个图像的源(src="img/code>),使其指向您刚刚添加的图像。

  3. 在与recipe-7.html相同的目录中创建一个名为recipe-7.css的 CSS 文件,并添加以下 CSS 代码来样式化我们的画廊:

    body {
      margin: 0;
      padding: 0;
      background-color: #333;
    }
    .gallery {
      width: 600px;
      margin: 50px auto auto auto;
      position: relative;
    }
    .gallery .frame {
      height: 450px;
      margin-bottom: 10px;
      position: relative;
    }
    .gallery .frame img {
      display: block;
      width: 100%;
      position: absolute;
      left: 0;
      top: 0;
    }
    .gallery .bottom {
      overflow: hidden;
    }
    .gallery .thumbs {
      height: 120px;
      white-space: nowrap;
      text-align: center;
    }
    .gallery .thumbs a {
      display: inline-block;
      opacity: 0.5;
      -webkit-transition: opacity 0.5s ease-in-out;
      -moz-transition: opacity 0.5s ease-in-out;
      -ms-transition: opacity 0.5s ease-in-out;
      -o-transition: opacity 0.5s ease-in-out;
      transition: opacity 0.5s ease-in-out;
    }
    .gallery .thumbs a:hover {
      opacity: 1.0;
    }
    .gallery .arrow {
      width: 50px;
      height: 50px;
      background-color: #000;
      position: absolute;
      -webkit-border-radius: 50px;
      -moz-border-radius: 50px;
      border-radius: 50px;
      bottom: 35px;
    }
    .gallery .arrow.disabled {
      background-color: #252525;
    }
    .gallery .left-arrow {
      left: -60px;
    }
    .gallery .right-arrow {
      right: -60px;
    }
    .gallery .arrow-right {
      width: 0;
      height: 0;
      border-top: 12px solid transparent;
      border-bottom: 12px solid transparent;
      border-left: 12px solid #1a1a1a;
      position: absolute;
      right: 16px;
      top: 13px;
    }
    .gallery .arrow-left {
      width: 0;
      height: 0;
      border-top: 12px solid transparent;
      border-bottom: 12px solid transparent;
      border-right:12px solid #1a1a1a;
      position: absolute;
      right: 21px;
      top: 13px;
    }
    
  4. 创建一个名为recipe-7.js的 JavaScript 文件,并添加以下 JavaScript 代码来启动我们的画廊:

    /** DECLARE SOME DEFAULT VARIABLES WHICH WILL BE USED THROUGHOUT **/
    var images;
    var imageWidth;
    $(function(){
      imageWidth = $('.gallery').data("thumb-width");
      /** COLLECT ALL THE IMAGES FROM WITHIN THE .gallery DIV **/
      images = $('.gallery').find('img');
      /** FOR EACH OF THESE IMAGES, CREATE A THUMBNAIL AND ADD A CLASS TO IDENTIFY THE IMAGE AND THUMBNAIL RELATIONSHIP **/
      $.each(images, function(index, value){
        $(value).addClass("img" + index);
        $('.gallery .thumbs').append("<a href='#' data-index='" + index + "' class='thumb'><img src='" + $(this).prop("src") + "' width='" + imageWidth + "' height='120' border='0' /></a>");
      });
      /** UPDATE THE SCROLL BUTTONS **/
      updateScrollButtons();
      /** EVENT HANDLERS FOR SCROLL BUTTONS **/
      $('.arrow').click(function(){
        var element = $(this);
        if (!element.hasClass('disabled')) {
          element.addClass('disabled');
          var scrollString = "-=";
          if ($(this).data("direction") == "left") {
            scrollString = "+=";
          }
          $('.thumbs').animate({
            marginLeft: scrollString + imageWidth + "px"
          }, "fast", function(){
            element.removeClass('disabled');
            updateScrollButtons();
          });
        }
      });
      /** EVENT HANDLERS FOR IMAGES **/
      $('.gallery').on("click", ".thumb", function(){
        var thumb = $(this);
        var image = $('.img' + thumb.data('index'));
        $.each(images, function(index, value){
          if (!$(value).hasClass('img' + thumb.data('index'))) {
            $(value).hide();
          }
        });
        if (image.css("display") != "block") {
          image.fadeIn();
        }
      });
    });
    function updateScrollButtons() {
      var thumbs = $('.thumbs');
      var thumbsMarginLeft = parseInt(thumbs.css("margin-left"));
      var thumbsMaxWidth = (images.length * imageWidth);
      if (thumbsMarginLeft >= 0) {
        $('.left-arrow').addClass('disabled');
      } else {
        $('.left-arrow').removeClass('disabled');
      }
      if ((thumbsMarginLeft * -1) >= (thumbsMaxWidth - thumbs.width() / 2)) {
        $('.right-arrow').addClass('disabled');
      } else {
        $('.right-arrow').removeClass('disabled');
      }
    }
    
  5. 在 Web 浏览器中打开recipe-7.html,您将看到一个类似以下截图的 jQuery 图像画廊:How to do it…`

  6. 选择左右箭头将允许您滚动照片,单击照片将在主框架中显示较大版本。

工作原理…

现在,让我们详细了解之前执行的步骤。

HTML

由于 jQuery 的帮助,我们能够用极少的 HTML 代码创建一个吸引人且功能齐全的画廊。除了基本的 HTML 文档结构之外,我们还定义了一个类为gallery的 division 元素。以下是 jQuery 将用来基于大多数 DOM 交互的 division 元素代码:

<div class="gallery" data-thumb-width="150"></div>

另外,我们还使用 HTML5 数据属性来定义缩略图的宽度。我们的 jQuery 代码将使用此值来调整缩略图的大小。

使用以下 HTML 代码,我们还创建了一个类名为frame的 division 元素,其兄弟元素是我们想要在画廊中显示的图像:

<div class="frame">
<img src="img/Chrysanthemum.jpg" />
<img src="img/Desert.jpg" />
<img src="img/Hydrangeas.jpg" />
<img src="img/Jellyfish.jpg" />
<img src="img/Koala.jpg" />
<img src="img/Lighthouse.jpg" />
<img src="img/Penguins.jpg" />
<img src="img/Tulips.jpg" />
</div>

最后,在我们的 HTML 中,我们创建一个左右箭头,它将与 jQuery 一起使用来滚动图像缩略图。我们还创建了一个类为thumbs的 div 元素,将使用以下 jQuery 代码填充缩略图图像:

<div class="bottom">
<a href="#" class="arrow left-arrow" data-direction="left"><i class="arrow-left"></i></a>
<a href="#" class="arrow right-arrow" data-direction="right"><i class="arrow-right"></i></a>
<div class="thumbs"></div>
</div>

CSS

此配方中使用的大部分 CSS 代码都非常基础,只是将元素放置在页面的适当位置。主画廊 division 元素设置为 600 像素宽,并居中显示在屏幕上。为了使我们能够将左右箭头放在画廊框架外部,我们将它们的位置设置为绝对,并使用负边距将它们推到更左和更右。

主缩略图滚动部分的 overflow 值设置为 hidden,防止大部分缩略图被显示。 这使我们可以使用 jQuery 将这些元素滚动到视图中。 缩略图本身的 display 值设置为 inline-block,允许它们在单行中左到右堆叠在一起。

为了产生附加效果,我们还使用了一些基本的 CSS 动画。 缩略图的不透明度设置为 0.5,以便它们不会成为应用程序的主要焦点。 当用户悬停在缩略图上时,使用 CSS 过渡创建淡入效果,如下所示:

.gallery .thumbs a {
  display: inline-block;
  opacity: 0.5;
  -webkit-transition: opacity 0.5s ease-in-out;
  -moz-transition: opacity 0.5s ease-in-out;
  -ms-transition: opacity 0.5s ease-in-out;
  -o-transition: opacity 0.5s ease-in-out;
  transition: opacity 0.5s ease-in-out;
}
.gallery .thumbs a:hover {
  opacity: 1.0;
}

除了官方的 CSS3 transition 属性之外,我们还使用了浏览器特定的替代方案,以确保 CSS 动画在所有最流行的浏览器中都能正常工作。

-webkit-transition: opacity 0.5s ease-in-out;
-moz-transition: opacity 0.5s ease-in-out;
-ms-transition: opacity 0.5s ease-in-out;
-o-transition: opacity 0.5s ease-in-out;

jQuery

JavaScript 文件开头声明了两个变量,以便它们的值可以在整个应用程序中使用;这些变量称为全局变量。 应用程序代码的大部分被放置在 jQuery 的加载函数中,这样一旦页面加载完成,代码就会执行,如下所示:

var images;
var imageWidth;
$(function(){
  imageWidth = $('.gallery').data("thumb-width");
  /** COLLECT ALL THE IMAGES FROM WITHIN THE .gallery DIV **/
  images = $('.gallery').find('img');
  /** FOR EACH OF THESE IMAGES, CREATE A THUMBNAIL AND ADD A CLASS TO IDENTIFY THE IMAGE AND THUMBNAIL RELATIONSHIP **/
  $.each(images, function(index, value){
    $(value).addClass("img" + index);
    $('.gallery .thumbs').append("<a href='#' data-index='" + index + "' class='thumb'><img src='" + $(this).prop("src") + "' width='" + imageWidth + "' height='120' border='0' /></a>");
  });
});

使用 jQuery 的 data() 函数从我们之前创建的 HTML 代码中提取缩略图宽度。 然后将该值存储在 imageWidth 变量中,供以后在应用程序中使用。 使用 $('.gallery').find('img') 函数搜索 gallery div 元素中的所有 img 元素并将它们存储为 images 变量中的数组。 使用 jQuery $.each() 函数来迭代 images 数组中的每个 img 元素。 在 $.each() 的回调函数中,我们首先使用 addClass() 函数基于数组索引为主图像元素添加一个类(即 img0img1 等等)。 然后,创建一个带有图像的锚元素,并使用先前声明的 imageWidth 变量来设置宽度。 使用 append() 函数,然后将锚元素插入到 DOM 中 thumbs div 元素中。 此外,该锚元素的 data-index 属性值设置为与较大图像的类名相匹配。

$.each() 函数中,我们调用一个名为 updateScrollButtons 的自定义函数,该函数在 JavaScript 文件的末尾声明。 该函数用于根据当前缩略图的位置确定是否应该启用箭头按钮。 这可以防止用户将缩略图滚动到图像库的底部部分。 一旦用户向右滚动到最后的缩略图,右箭头按钮就会被禁用。 一旦用户向左滚动到第一个缩略图,左箭头按钮就会被禁用。

接下来,使用以下代码为每个箭头按钮附加了一个点击事件处理程序,以便我们可以检测用户何时想要浏览缩略图图像。

$('.arrow').click(function(){
var element = $(this);
if (!element.hasClass('disabled')) {
  element.addClass('disabled');
  var scrollString = "-=";
  if ($(this).data("direction") == "left") {
    scrollString = "+=";
  }
  $('.thumbs').animate({
    marginLeft: scrollString + imageWidth + "px"
  }, "fast", function(){
    element.removeClass('disabled');
    updateScrollButtons();
  });
}
});

在点击事件处理程序的回调函数中,我们首先声明一个变量,并将点击的元素存储在其中,引用为 $(this),意思是点击的元素。使用此变量,我们可以使用 jQuery 函数 hasClass 来确定点击的元素是否具有类 disabled。我们将此函数中的所有代码包装在 if 语句中,以便如果点击的元素具有 disabled 类,则不执行此代码。在 if 语句中,我们使用 addClassdisabled 类添加到点击的元素中。这是为了防止用户能够频繁点击滚动箭头并导致不希望的动画效果。

我们还声明了一个名为 scrollString 的变量,其默认值为 -=。该值将在 jQuery 的 animate() 函数中使用,该函数将为我们的缩略图提供滚动动画。根据所点击的箭头的 data-direction 属性值,此值将保持为 -=,这意味着 thumbs div 的左边距将被减去(即向右滚动),或者该值将更改为 +=,这意味着左边距将被添加(即向左滚动)。

最后,在此事件处理程序回调函数中,使用 jQuery 的 animate() 函数修改 thumbs div 元素的左边距,从而提供滚动效果。再次使用 imageWidth 变量来设置滚动位置以匹配缩略图的宽度,如下所示:

$('.gallery').on("click", ".thumb", function(){
var thumb = $(this);
var image = $('.' + thumb.attr('rel'));
$.each(images, function(index, value){
    if (!$(value).hasClass(thumb.attr('rel'))) {
        $(value).hide();
    }
});
if (image.css("display") != "block") {
    image.fadeIn();
}
});

下一段代码的下一步是将点击事件处理程序附加到 gallery div 元素上。点击事件处理程序监听任何具有 thumb 类的元素上的点击。这使我们能够指定在单击缩略图后要执行的代码。在回调函数中,我们选择被点击的缩略图并将元素引用存储在 thumb 变量中。我们还使用点击的元素的 data-index 属性值来选择较大的图像,并将其引用存储在 image 中。

再次使用 $.each() 函数来迭代所有图像。我们隐藏与点击的缩略图中的图像不匹配的每个图像。这样只有所选图像才会出现在主查看面板中。我们还使用 css() 函数来检查较大图像的 display 属性,以确定图像当前是否可见。如果不可见,我们使用 jQuery 的淡入效果来显示它,完成图像库功能。

创建一个闪烁的按钮

使用 jQuery 的效果函数,我们可以创建一个闪烁的按钮,可以在 Web 应用程序或网站中使用,以吸引用户的注意力。

准备工作

创建一个名为 recipe-8.html 的空白 HTML 文档,并确保您已下载并准备好将其包含在此 HTML 文件中的最新版本的 jQuery。

如何做...

通过执行以下步骤了解如何使用 jQuery 创建一个简单的闪烁按钮效果:

  1. 将以下代码添加到刚刚创建的recipe-8.html中,记得更新对 jQuery 库的引用。

    <!DOCTYPE html>
    <html>
    <head>
      <script src="img/jquery.min.js"></script>
      <script src="img/recipe-8.js"></script>
      <title>Chapter 4 :: JQuery Effects :: Recipe 8 </title>
      <link type="text/css" media="screen" rel="stylesheet" href="recipe-8.css" />
    </head>
    <body>
    <div class="frame">
      <h1>Newsletter!</h1>
      <p>Enter your email address below to sign-up for our monthly newsletter.</p>
      <form>
        <input type="text" class="email-input" name="email" placeholder="Your Email" />
         <button class="blinker">Sign-up Now!</button>
      </form>
    </div>
    </body>
    </html>
    
  2. 创建一个名为recipe-8.css的 CSS 文件,并添加以下 CSS 代码以为 HTML 中创建的通讯表单添加样式:

    @import url(http://fonts.googleapis.com/css?family=Leckerli+One);
    @import url(http://fonts.googleapis.com/css?family=Happy+Monkey);
    body {
      background-color: #333333;
      font-family: 'Happy Monkey', cursive;
    }
    h1 {
      font-family: 'Leckerli One', cursive;
      font-size: 60px;
      line-height: 80px;
      padding: 0;
      margin: 0;
      text-align: center;
      color: #333;
    }
    .frame {
      width: 500px;
      margin: 50px auto auto auto;
      height: 300px;
      background-color: #FFF;
      box-shadow: #000 3px 3px 2px;
      border-radius: 10px;
      padding: 20px;
      text-align: center;
    }
    .frame p {
      font-size: 18px;
      line-height: 25px;
    }
    .frame form .email-input {
      height: 40px;
      font-size: 30px;
      width: 400px;
      font-family: 'Happy Monkey', cursive;
    }
    .frame form .blinker {
      height: 40px;
      width: 150px;
      font-size: 20px;
      margin-top: 20px;
      font-family: 'Happy Monkey', cursive;
    }
    
  3. 在与 CSS 和 HTML 文件相同的目录中创建一个 JavaScript 文件。将此文件保存为recipe-8.js并添加以下 jQuery 代码:

    $(function(){
      $('.email-input').on('focus', function(){
        $('.blinker').fadeTo(300, 0.1).fadeTo(300, 1);
      })
    });
    
  4. 在 Web 浏览器中打开recipe-8.html,你会看到一个类似下面截图的网页:如何操作…

  5. 单击文本框内部将使“立即注册!”按钮闪烁以吸引用户的注意。

工作原理是…

在此配方中使用的 HTML 和 CSS 代码创建了一个页面,允许用户订阅通讯。HTML 或 CSS 代码中没有复杂的元素,因此不需要进一步解释。

这个配方提供了一个简单的示例,演示了我们如何使用 jQuery 来实现按钮闪烁的外观。其思想是,当用户点击文本框输入电子邮件地址时,“立即注册!”按钮会闪烁以吸引他们的注意。

在我们的 jQuery 代码中,我们首先将事件处理程序附加到文本输入以获得焦点。当页面上的元素受到用户的关注时,即通过点击它或通过标签切换到表单元素时,将触发“焦点”事件。在此事件处理程序的回调函数中,我们使用fadeTo()jQuery 效果函数来顺序淡出并淡入按钮,创建闪烁效果。在本示例中,fadeTo()函数接受两个参数,效果持续时间和元素不透明度。我们在第一个fadeTo()函数中指定元素的不透明度为0.1,以淡出按钮。然后我们指定1.0以淡入按钮。我们可以通过改变指定的持续时间来控制效果的速度,该持续时间设置为300毫秒。

还有更多……

有许多方法可以使用 jQuery 创建闪烁效果。在 第六章 用户界面 中,您将学习如何更改元素的 CSS 属性,从而可以添加阴影和彩色边框,以大大增强闪烁效果。fadeTo()函数提供了创建此效果的最简单方法,但请注意,有一些替代方法可以提供更大的影响,可能更适合您的需求。

当强制元素闪烁、移动或闪烁以吸引用户的注意时,必须非常小心,以免引起烦恼,因为这可能会产生相反的效果,使他们远离。这些效果只应用作微妙的提示,以促使用户与您的用户界面进行交互。

另请参见

  • 淡出元素

  • 创建一个基本的照片库

带有效果的删除元素

通常,您会创建诸如列表或表格之类的界面,用于表示来自数据库的数据。如果界面是用于管理目的,通常可以添加、编辑和删除这些项目。当添加这些项目时,我们可以使用 jQuery 效果来增强用户体验,如淡出元素示例中所述。当从 DOM 中删除项目时,我们也可以提供效果。由于 jQuery,这非常容易做到。

准备就绪

与本章中的其他示例一样,您需要一个空白的 HTML 文档。将此文档保存为recipe-9.html,并确保它与最新版本的 jQuery 在同一个目录中。

如何做...

了解如何通过执行以下步骤以带有效果的方式移除 DOM 元素:

  1. 将以下 HTML 代码添加到您刚刚创建的 HTML 文档中:

    <!DOCTYPE html>
    <html>
    <head>
      <script src="img/jquery.min.js"></script>
      <script src="img/recipe-9.js"></script>
       <title>Chapter 4 :: JQuery Effects :: Recipe 9 </title>
      <link type="text/css" media="screen" rel="stylesheet" href="recipe-9.css" />
    </head>
    <body>
    <div class="frame">
      <h1>User Management</h1>
      <table width="100%" id="user-table">
        <thead>
        <tr>
          <th>Username</th>
          <th>Email</th>
          <th>Full Name</th>
          <th>Date of Birth</th>
          <th></th>
        </tr>
        </thead>
        <tbody>
        <tr>
          <td>jd101</td>
          <td>j.doe@somewhere.com</td>
          <td>John Doe</td>
          <td>16-05-1987</td>
          <td><button class="delete">Delete</button></td>
        </tr>
        <tr>
          <td>msmith17</td>
          <td>smithy@nowhere.com</td>
          <td>Jane Smith</td>
          <td>18-08-1988</td>
          <td><button class="delete">Delete</button></td>
        </tr>
        <tr>
          <td>tommy22</td>
          <td>tom@idontknow.com</td>
          <td>Thomas Knowhow</td>
          <td>10-08-1980</td>
          <td><button class="delete">Delete</button></td>
        </tr>
        </tbody>
      </table>
    </div>
    </body>
    </html>
    
  2. 您可能已经注意到了前一个 HTML 代码的标题中包含的 CSS 文件。创建recipe-9.css并添加以下 CSS 代码:

    @import url(http://fonts.googleapis.com/css?family=Lato:300,400);
    body {
      background-color: #333333;
      font-family: 'Lato', sans-serif;
    }
    h1 {
      line-height: 60px;
      padding: 0;
      margin: 0 0 15px 0;
      text-align: center;
      color: #333;
      font-weight: 300;
    }
    .frame {
      width: 700px;
      margin: 50px auto auto auto;
      background-color: #FFF;
      box-shadow: #000 3px 3px 2px;
      border-radius: 10px;
      padding: 20px;
      text-align: center;
    }
    
  3. 除了 CSS 文件外,HTML 页面还包含了一个 JavaScript 文件。创建一个名为recipe-9.js的 JavaScript 文件,并将其保存在与 HTML 和 CSS 文件相同的目录中。将以下 jQuery 代码添加到此文件中:

    $(function(){
      $('#user-table').on("click", ".delete", function(){
        var response = confirm("Are you sure you want to delete this user?");
        if (response) {
          $(this).parent().parent().fadeOut().remove();
        }
      });
    });
    
  4. 在网页浏览器中打开recipe-9.html,你将看到一个简单的用户管理界面。点击任何条目旁边的删除按钮将提示你确认是否要删除。当用户点击确定时,该特定用户的条目将淡出并从 DOM 中移除。

工作原理...

这个示例也有一些基本的 HTML 和 CSS 代码,不需要解释。相反,让我们专注于 jQuery 代码。

我们所有的 jQuery 代码都包装在$(function(){});中,这是 jQuery 的加载函数,允许我们在页面加载时执行。我们将点击事件处理程序附加到用户表,并监听任何具有delete类的元素的点击,如下所示。从 HTML 代码中,您将知道这些元素是delete按钮。

$('#user-table').on("click", ".delete", function(){

});

在此事件处理程序的回调函数内部,我们使用原生 JavaScript 函数confirm()并将其输出分配给response变量。这将向用户显示一个弹出窗口,其中包含消息确定要删除此用户吗?。如果用户点击确定,则response变量将等于true。如果他们点击取消,它将是false。通过使用这个response变量,我们可以确定他们是否想要继续删除用户。如果是,我们可以从 DOM 中移除表格行。

要删除表格行,我们首先需要选择它。我们可以引用$(this),它是被点击的项目(在本例中是按钮),然后选择其父级的父级,即tr表。这是使用以下代码完成的:

$(this).parent().parent().fadeOut().remove();

然后我们使用fadeOut()函数应用效果,并使用remove()函数从 DOM 中删除元素。

还有更多...

这种简单的用户界面通常会与服务器端调用结合使用,这些调用还会从数据库中删除用户输入。回顾一下第三章,使用 jQuery 和 AJAX 加载和操作动态内容,看看如何使用 jQuery 和 AJAX 完成这项任务。

另请参阅

  • 淡入淡出元素

第五章:表单处理

在本章中,我们将探讨如何创建具有动画、验证和用户反馈的健壮而引人入胜的网络表单。我们将涵盖:

  • 实施基本表单验证

  • 添加数字验证

  • 添加信用卡号验证

  • 添加日期验证

  • 添加电子邮件地址验证

  • 实施实时表单验证

  • 添加密码强度指示器

  • 添加反垃圾邮件措施

  • 实施输入字符限制

介绍

收集用户数据是许多网站和网络应用程序的基本功能,从简单的数据收集技术,如注册或登录信息,到更复杂的情景,如付款或账单信息。重要的是只收集来自用户的相关和完整信息。为了确保这一点,Web 开发人员必须对所有数据输入进行验证。在执行数据完整性的同时提供良好的用户体验也很重要。这可以通过向用户提供有关其数据可能引起的任何验证错误的有用反馈来实现。本章将向您展示如何创建一个引人入胜的网络表单,同时保持高质量的用户体验。

非常重要的一点是,任何 JavaScript 或 jQuery 验证都容易被用户操纵。JavaScript 和 jQuery 位于 Web 浏览器中,所以用户可以轻松修改代码以绕过任何客户端验证技术。这意味着不能完全依赖客户端验证来防止用户提交无效数据。在客户端进行的任何验证都必须在服务器上进行复制,服务器不容易被用户操纵。

我们使用客户端验证来提高用户体验。因此,用户不需要等待服务器响应。

实施基本表单验证

在最基本的表单验证级别上,您需要能够阻止用户提交空值。本教程将为本章的第 1 至 8 个配方提供用于网络表单的 HTML 和 CSS 代码。

准备工作

使用您喜欢的文本编辑器或 IDE,在易于访问的位置创建一个空白的 HTML 页面,并将此文件保存为recipe-1.html。确保您已将最新版本的 jQuery 下载到与此 HTML 文件相同的位置。

这个 HTML 页面将成为本章大部分内容的基础,请在完成本教程后记得保存它。

如何做...

通过执行以下步骤学习如何使用 jQuery 实现基本表单验证:

  1. 将以下 HTML 代码添加到index.html中。确保更改包含 jQuery 库的 JavaScript 的源位置,指向您计算机上下载的 jQuery 的最新版本所在位置。

    <!DOCTYPE html>
    <html >
    <head>
       <title>Chapter 5 :: Recipe 1</title>
       <link type="text/css" media="screen" rel="stylesheet" href="styles.css" />
       <script src="img/jquery.min.js"></script>
       <script src="img/validation.js"></script>
    </head>
    <body>
       <form id="webForm" method="POST">
          <div class="header">
             <h1>Register</h1>
          </div>
          <div class="input-frame">
             <label for="firstName">First Name:</label>
             <input name="firstName" id="firstName" type="text" class="required" />
          </div>
          <div class="input-frame">
             <label for="lastName">Last Name:</label>
             <input name="lastName" id="lastName" type="text" class="required" />
          </div>
          <div class="input-frame">
             <label for="email">Email:</label>
             <input name="email" id="email" type="text" class="required email" />
          </div>
          <div class="input-frame">
             <label for="number">Telephone:</label>
             <input name="number" id="number" type="text" class="number" />
          </div>
          <div class="input-frame">
             <label for="dob">Date of Birth:</label>
             <input name="dob" id="dob" type="text" class="required date" placeholder="DD/MM/YYYY"/>
          </div>
          <div class="input-frame">
             <label for="creditCard">Credit Card #:</label>
             <input name="creditCard" id="creditCard" type="text" class="required credit-card" />
          </div>
          <div class="input-frame">
             <label for="password">Password:</label>
             <input name="password" id="password" type="password" class="required" />
          </div>
          <div class="input-frame">
             <label for="confirmPassword">Confirm Password:</label>
                <input name="confirmPassword" id="confirmPassword" type="password" class="required" />
          </div>
          <div class="actions">
             <button class="submit-btn">Submit</button>
          </div>
       </form>
    </body>
    </html>
    
  2. 在同一目录下创建名为styles.css的 CSS 文件,并添加以下 CSS 代码以为我们的 HTML 页面和表单添加样式:

    @import url(http://fonts.googleapis.com/css?family=Ubuntu);
    body {
       background-color: #FFF;
       font-family: 'Ubuntu', sans-serif;
    }
    form {
       width: 500px;
       padding: 20px;
       background-color: #333;
       border-radius: 5px;
       margin: 10px auto auto auto;
       color: #747474;
       border: solid 2px #000;
    }
    form label {
       font-size: 14px;
       line-height: 30px;
       width: 27%;
       display: inline-block;
       text-align: right;
    }
    .input-frame {
       clear: both;
       margin-bottom: 25px;
       position: relative;
    }
    form input {
       height: 30px;
       width: 330px;
       margin-left: 10px;
       background-color: #191919;
       border: solid 1px #404040;
       padding-left: 10px;
       color: #DB7400;
    }
    form input:hover {
       background-color: #262626;
    }
    form input:focus {
       border-color: #DB7400;
    }
    form .header {
       margin: -20px -20px 25px -20px;
       padding: 10px 10px 10px 20px;
       position: relative;
       background-color: #DB7400;
       border-top-left-radius: 4px;
       border-top-right-radius: 4px;
    }
    form .header h1 {
       line-height: 50px;
       margin: 0px;
       padding: 0px;
       color: #FFF;
       font-weight: normal;
    }
    .actions {
       text-align: right;
    }
    .submit-btn {
       background-color: #DB7400;
       border: solid 1px #000;
       border-radius: 5px;
       color: #FFF;
       padding: 10px 20px 10px 20px;
       text-decoration: none;
       cursor: pointer;
    }
    .error input {
       border-color: red;
    }
    .error-data {
       color: red;
       font-size: 11px;
       position: absolute;
       bottom: -15px;
       left: 30%;
    }
    
  3. 除了 jQuery 库外,先前的 HTML 页面还使用了另一个 JavaScript 文件。在保存index.html文件的目录中创建一个空白的 JavaScript 文件。将该文件保存为validation.js,并添加以下 JavaScript 代码:

    $(function(){
       $('.submit-btn').click(function(event){
          //Prevent form submission
          event.preventDefault();
          var inputs = $('input');
          var isError = false;
          //Remove old errors
          $('.input-frame').removeClass('error');
          $('.error-data').remove();
          for (var i = 0; i < inputs.length; i++) {
             var input = inputs[i];
             if ($(input).hasClass('required') && !validateRequired($(input).val())) {
                addErrorData($(input), "This is a required field");
                isError = true;
             }
    
          }
          if (isError === false) {
             //No errors, submit the form
             $('#webForm').submit();
          }
       });
    });
    
    function validateRequired(value) {
       if (value == "") return false;
       return true;
    }
    
    function addErrorData(element, error) {
       element.parent().addClass("error");
       element.after("<div class='error-data'>" + error + "</div>");
    }
    
  4. 在网络浏览器中打开index.html,您应该会看到一个类似下面截图的表单:如何操作…

  5. 如果您单击提交按钮提交一个空表单,将会在必填字段下方显示错误消息。

工作原理…

现在,让我们详细了解之前执行的步骤。

HTML

HTML 创建了一个包含各种字段的网络表单,这些字段将接受一系列数据输入,包括文本、出生日期和信用卡号码。该页面构成了本章大部分内容的基础。每个输入元素都被赋予了不同的类,具体取决于它们需要什么类型的验证。对于本示例,我们的 JavaScript 只会查看required类,该类表示必填字段,因此不能为空。其他类已添加到输入字段中,例如datenumber,这些类将在本章后续示例中使用。

CSS

已添加基本 CSS 以创建吸引人的网络表单。CSS 代码为输入字段添加样式,使其与表单本身融为一体,并添加了悬停效果。还使用了谷歌 Web 字体 Ubuntu 来改善表单的外观。

jQuery

jQuery 代码的第一部分被包裹在$(function(){});中,这将确保代码在页面加载时执行。在这个包装器内部,我们将点击事件处理程序附加到表单提交按钮,如下所示:

$(function(){
    $('.submit-btn').click(function(event){
        //Prevent form submission
        event.preventDefault();

    });
});

由于我们希望根据是否提供了有效数据来处理表单提交,所以我们使用event.preventDefault();来最初阻止表单提交,从而允许我们首先执行验证,如下所示:

var inputs = $('input');
var isError = false;

preventDefault代码之后,声明了一个inputs变量,用于保存页面内所有输入元素,使用$('input')来选择它们。此外,我们创建了一个isError变量,并将其设置为false。这将是一个标志,用于确定我们的验证代码是否在表单中发现了错误。这些变量声明如上所示。通过inputs变量的长度,我们能够循环遍历页面上的所有输入。我们为每个迭代的输入创建一个输入变量,该变量可用于使用 jQuery 对当前输入元素执行操作。使用以下代码完成此操作:

for (var i = 0; i < inputs.length; i++) {
var input = inputs[i];
}

在输入变量被声明并分配了当前输入后,使用以下代码从元素中移除任何先前的错误类或数据:

$(input).parent().removeClass('error');
$(input).next('.error-data').remove();

第一行代码从输入框的父元素(.input-frame)中移除了error类,该类将为输入元素添加红色边框。第二行代码会移除在输入数据验证检查确定该输入数据无效时在输入框下方显示的错误信息。

接下来,使用 jQuery 的hasClass()函数来确定当前输入元素是否具有required类。如果当前元素确实具有这个类,我们需要执行所需的验证以确保该字段包含数据。我们在if语句内调用validateRequired()函数,并通过当前输入的值,如下所示:

if ($(input).hasClass('required') && !validateRequired($(input).val())) {
addErrorData($(input), "This is a required field");
   isError = true;
}

我们使用感叹号 ! 前置调用validateRequired()函数来检查是否该函数的结果等于false;因此,如果当前输入具有required类且validateRequired()返回false,则当前输入的值无效。如果是这种情况,我们在if语句内调用addErrorData()函数,并传递当前输入和错误消息,该消息将显示在输入框下方。我们还将isError变量设置为true,以便在之后的代码中我们将知道发生了验证错误。

JavaScript 的for循环将对页面上选择的每个输入元素重复执行这些步骤。for循环完成后,我们检查isError标志是否仍然设置为false。如果是,我们使用 jQuery 手动提交表单,如下所示:

if (isError === false) {
   //No errors, submit the form
   $('#webForm').submit();
}

请注意,运算符===用于比较isError的变量类型(即Boolean)及其值。在 JavaScript 文件的底部,我们声明了之前在脚本中调用的两个函数。第一个函数validateRequired()简单地获取输入值并检查它是否为空。如果值为空,函数返回false,表示验证失败;否则,函数返回true。可以编码如下:

function validateRequired(value) {
    if (value == "") return false;
    return true;
}

使用的第二个函数是addErrorData()函数,它接受当前输入和错误消息。它使用 jQuery 的addClass()函数将错误类添加到输入的父级,这将使用 CSS 在输入元素上显示红色边框。然后,它使用 jQuery 的after()函数将一个<div>元素插入到 DOM 中,在当前输入字段下方显示指定的错误消息,如下所示:

function validateRequired(value) {
   if (value == "") return false;
   return true;
}
function addErrorData(element, error) {
   element.parent().addClass("error");
   element.after("<div class='error-data'>" + error + "</div>");
}

还有更多内容...

这个结构使我们能够轻松地为我们的 Web 表单添加附加的验证。因为 JavaScript 正在迭代表单中所有的输入字段,我们可以轻松地检查附加的类,比如datenumbercredit-card,并调用额外的函数来提供替代验证。本章其他的示例将详细讨论附加的验证类型,并将这些函数添加到当前的validation.js文件中。

另请参阅

  • 实施输入字符限制

添加数字验证

当从用户那里收集数据时,有许多情况下您只想允许表单字段中的数字。例如,这可能是电话号码、PIN 码或邮政编码等。本配方将向您展示如何验证前一个配方中创建的表单中的电话号码字段。

准备工作

确保您已经完成了上一个配方,并且有相同的文件可用。在您选择的文本编辑器或 IDE 中打开validation.js

如何做…

通过执行以下步骤将数字验证添加到前一个配方中创建的表单中:

  1. validation.js更新如下,添加valdiateNumber()函数并在for循环内部添加额外的hasClass('number')检查:

    $(function(){
       $('.submit-btn').click(function(event){
          //Prevent form submission
          event.preventDefault();
          var inputs = $('input');
          var isError = false;
          //Remove old errors
          $('.input-frame').removeClass('error');
          $('.error-data').remove();
          for (var i = 0; i < inputs.length; i++) {
             var input = inputs[i];
    
             if ($(input).hasClass('required') && !validateRequired($(input).val())) {
                   addErrorData($(input), "This is a required field");
                   isError = true;
                }
    /* Code for this recipe */
             if ($(input).hasClass('number') && !validateNumber($(input).val())) {
                   addErrorData($(input), "This field can only contain numbers");
                   isError = true;
                }
    /* --- */
    
          }
          if (isError === false) {
             //No errors, submit the form
             $('#webForm').submit();
          }
       });
    });
    
    function validateRequired(value) {
       if (value == "") return false;
       return true;
    }
    
    /* Code for this recipe */
    function validateNumber(value) {
       if (value != "") {
          return !isNaN(parseInt(value, 10)) && isFinite(value);
          //isFinite, in case letter is on the end
       }
       return true;
    }
    /* --- */
    function addErrorData(element, error) {
       element.parent().addClass("error");
       element.after("<div class='error-data'>" + error + "</div>");
    } 
    
  2. 在 Web 浏览器中打开index.html,在电话号码字段中输入除了有效整数以外的内容,然后单击提交按钮。您将看到一个类似以下截图的表单:如何做…

工作原理…

首先,我们在validation.js的主for循环中添加了额外的if语句,以检查当前输入字段是否具有number类,如下所示:

if ($(input).hasClass('number') && !validateNumber($(input).val())) {
   addErrorData($(input), "This field can only contain numbers");
   isError = true;
}

如果是这样,此输入值需要验证为数字。为此,在if语句内联调用validateNumber函数:

function validateNumber(value) {
   if (value != "") {
      return !isNaN(parseInt(value, 10)) && isFinite(value);
      //isFinite, in case letter is on the end
   }
   return true;
}

此函数将当前输入字段的值作为参数。它首先检查值是否为空。如果是,我们就不需要在这里执行任何验证,因为这是由本章第一个配方中的validateRequired()函数处理的。

如果有值需要验证,在return语句上执行一系列操作。首先,该值被解析为整数并传递给isNaN()函数。JavaScript 的isNaN()函数简单地检查提供的值是否为NaNNot a Number)。在 JavaScript 中,如果尝试将一个值解析为整数,并且该值实际上不是整数,则会得到NaN值。return语句的第一部分是确保提供的值是有效的整数。然而,这并不阻止用户输入无效字符。如果用户输入12345ABCDparseInt函数将忽略ABCD,只解析12345,因此验证将通过。为了防止这种情况,我们还使用isFinite函数,如果提供12345ABCD,则返回false

另请参阅

  • 添加信用卡号码验证

添加信用卡号码验证

数字验证可能足以验证信用卡号码;然而,使用正则表达式,可以检查数字组合以匹配 Visa、MasterCard、American Express 等信用卡号码。

准备工作

确保您已经打开并准备修改本章前两个配方中的validation.js

如何做…

使用 jQuery 执行以下逐步说明,为信用卡号提供表单输入验证:

  1. 更新validation.js以添加信用卡验证函数和在输入字段上进行额外的类检查:

    $(function(){
       $('.submit-btn').click(function(event){
          //Prevent form submission
          event.preventDefault();
          var inputs = $('input');
          var isError = false;
          for (var i = 0; i < inputs.length; i++) {
    
    // -- JavaScript from previous two recipes hidden            
    
             if ($(input).hasClass('credit-card') && !validateCreditCard($(input).val())) {
                addErrorData($(input), "Invalid credit card number");
                isError = true;
             }
    
          }
    // -- JavaScript from previous two recipes hidden
       });
    });
    
    // -- JavaScript from previous two recipes hidden
    
    function validateCreditCard(value) {
       if (value != "") {
          return /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/.test(value);
       }
       return true;
    }
    // -- JavaScript from previous two recipes hidden
    } 
    
  2. 打开index.html,输入无效的信用卡号。你将看到表单中呈现以下错误信息:操作步骤…

运作原理…

要添加信用卡验证,与前两个示例一样,在主for循环中添加额外的检查来查找输入元素上的credit-card类,如下所示:

if ($(input).hasClass('credit-card') && !validateCreditCard($(input).val())) {
   addErrorData($(input), "Invalid credit card number");
   isError = true;
}

此处还添加了validateCreditCard函数,该函数使用正则表达式验证输入值,如下所示:

function validateCreditCard(value) {
   if (value != "") {
      return /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/.test(value);
   }
   return true;
}

此函数的第一部分确定提供的值是否为空。如果不为空,函数将执行进一步的验证;否则,它将返回true。大多数信用卡号以前缀开头,这使我们能够在数值验证之上添加额外的验证。此函数中使用的正则表达式将允许 Visa、MasterCard、American Express、Diners Club、Discover 和 JCB 卡。

也可以参考

  • 添加数字验证

添加日期验证

日期是常见的数据项,用户能够轻松地在您的 Web 表单中输入日期非常重要。通常,您会使用包含日期验证的日期选择器来提供简单的输入方法。本示例向您展示如何手动验证英国格式的日期(即DD/MM/YYYY)。日期选择器在第九章中进行了讨论,jQuery UI,使用流行的 jQuery UI 框架。有关更多信息,请参阅本示例的也可以参考部分。

准备工作

继续本章前几个示例的趋势,确保你已经打开并准备修改validation.js,并且已经完成了前三个示例。

操作步骤…

通过以下简单的步骤为您的 Web 表单添加日期验证:

  1. 更新validation.js以添加附加的日期验证函数和在主for循环内进行类检查,如下所示:

    $(function(){
       $('.submit-btn').click(function(event){
    
    // -- JavaScript from previous three recipes hidden
    
          for (var i = 0; i < inputs.length; i++) {
    
    // -- JavaScript from previous three recipes hidden
    
             if ($(input).hasClass('date') && !validateDate($(input).val())) {
                addErrorData($(input), "Invalid date provided");
                isError = true;
             }
    
             // -- JavaScript from previous three recipes hidden
    
          }
          // -- JavaScript from previous three recipes hidden    });
    });
    
    // -- JavaScript from previous three recipes hidden
    
    function validateDate(value) {
       if (value != "") {
          if (/^\d{2}([.\/-])\d{2}\1\d{4}$/.test(value)) {
             // Remove leading zeros
             value = value.replace(/0*(\d*)/gi,"$1");
             var dateValues = value.split(/[\.|\/|-]/);
             // Correct the month value as month index starts at 0 now 1 (e.g. 0 = Jan, 1 = Feb)
             dateValues[1]--;
             var date = new Date(dateValues[2], dateValues[1], dateValues[0]);
             if (
                date.getDate() == dateValues[0] && date.getMonth() == dateValues[1] &&
                date.getFullYear() == dateValues[2]
                ) {
                return true;
             }
          }
          return false;
       } else {
          return true;
       }
    }
    // -- JavaScript from previous three recipes hidden
    
  2. 在 Web 浏览器中打开index.html,输入一个无效的日期,并点击提交以生成无效日期错误,如下图所示:操作步骤…

运作原理…

再次,在主for循环中添加一个额外的类检查,以查看当前输入是否需要应用日期验证。如果需要,将调用validateDate()函数。

就像其他验证函数一样,我们首先检查值是否为空。如果不为空,则可以验证该值。使用正则表达式来确定提供的字符串值是否是有效的日期格式,如下所示:

if (/^\d{2}([.\/-])\d{2}\1\d{4}$/.test(value)) {

如果提供的值以斜杠、连字符或句点分隔,并且前两部分由两个数字组成,最后一部分由四个数字组成,则此测试将通过。这将确保提供的值是DD/MM/YYYY,符合要求。

如果此测试通过,则下一步是删除所有前导零,以便将提供的日期字符串转换为 JavaScript 的日期对象(例如,08-08-1989 将变为 8-8-1989)。相同的代码如下所示:

value = value.replace(/0*(\d*)/gi,"$1");

之后,创建一个数组,将日期字符串分割为-/ 或:

var dateValues = value.split(/[\.|\/|-]/);

现在,可以使用这些日期值来创建 JavaScript 日期对象并测试其有效性。在此之前,我们必须转换月份值。JavaScript 月份从0开始,而我们的用户将从1开始。例如,用户将使用1表示一月,2表示二月,依此类推,而 JavaScript 使用0表示一月,1表示二月,依此类推。为此,我们只需从提供的日期值中减去1,如下所示:

dateValues[1]--;

这样做后,就可以创建 JavaScript 日期对象并检查结果是否与输入日期匹配,从而证明其有效性:

var date = new Date(dateValues[2], dateValues[1], dateValues[0]);
if (
   date.getDate() == dateValues[0] &&
   date.getMonth() == dateValues[1] &&
   date.getFullYear() == dateValues[2]
) {
   return true;
}

另请参阅

  • 在 第九章 的 快速向输入框添加日期选择器界面 配方中,jQuery UI

添加电子邮件地址验证

电子邮件地址验证是网络上最常见的验证类型之一。大多数人会认为有效的电子邮件地址只包含字母数字字符,除了@符号和句点。虽然大多数电子邮件地址通常是这种格式,但实际上有效的电子邮件地址可能包含各种其他字符。本文将向您展示如何将电子邮件验证添加到我们在过去四个配方中使用的 Web 表单中。

如何执行…

通过执行以下说明,创建可以反复使用的电子邮件验证:

  1. validation.jsfor 循环中添加额外的 hasClass 检查和 if 语句,如下所示:

    if ($(input).hasClass('email') && !validateEmail($($(input)).val())) {
       addErrorData($(input), "Invalid email address provided");
       isError = true;
    }
    
  2. validation.js 末尾添加以下 validateEmail() 函数:

    function validateEmail(value) {
       if (value != "") {
          return /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:a-z0-9?\.)+a-z0-9?/i.test(value);
       }
       return true;
    }
    
  3. 在网络浏览器中打开 index.html,输入一个无效的电子邮件地址,并提交表单。您将以与其他类型验证错误相同的方式收到适当的错误提示。

工作原理…

然而简单的电子邮件验证函数包含一个复杂的正则表达式,用于将电子邮件地址验证为 RFC 5322 标准的实用版本,该版本由 www.regular-expressions.info/email.html 提供。

validateEmail() 函数的第一部分检查是否有值可验证。如果有,它将使用复杂的正则表达式测试字符串值的有效性,并相应地返回truefalse

最后,与其他验证函数一样,主for循环中有一个类检查,用于确定哪些输入需要对电子邮件地址进行验证。如果这些输入字段未通过验证,则会在屏幕上提供相应的错误输出。

还有更多…

重要的是要理解,此电子邮件验证方法仅验证语法,以减少用户提供的垃圾数据量。要真正验证电子邮件地址,您必须实际发送电子邮件以验证其是否存在并准备接收电子邮件。

实现实时表单验证

对于用户在网页表单中输入时即时获取验证错误的反馈非常有用。如果您同时执行客户端验证和服务器端验证,那么这可以轻松实现,因为您不需要每次用户在输入时发送请求到服务器,您可以在客户端内完成所有操作。再次强调,相同的数据在服务器端进行额外验证非常重要。然后可以在用户提交表单后将服务器端验证结果反馈给网页表单。

准备工作

本示例将调整作为前五个示例的一部分创建的客户端验证。确保您在此之前已经完成了这些示例。

如何做…

通过执行以下步骤为用户提供实时验证:

  1. 首先,我们需要将for循环中的所有类检查移到它们自己的函数中,以便它们可以被重复使用。将执行requiredemailnumberdatecredit-cardhasClass检查的所有if语句移动到一个名为doValidation()的函数中,如下所示:

    // --- Hidden JavaScript from previous recipes
    
    function doValidation(input) {
       //Remove old errors
       $(input).parent().removeClass('error');
       $(input).next('.error-data').remove();
       if ($(input).hasClass('required') && !validateRequired($(input).val())) {
          addErrorData($(input), "This is a required field");
       }
       if ($(input).hasClass('email') && !validateEmail($($(input)).val())) {
          addErrorData($(input), "Invalid email address provided");
       }
       if ($(input).hasClass('number') && !validateNumber($(input).val())) {
          addErrorData($(input), "This field can only contain numbers");
       }
       if ($(input).hasClass('date') && !validateDate($(input).val())) {
          addErrorData($(input), "Invalid date provided");
       }
       if ($(input).hasClass('credit-card') && !validateCreditCard($(input).val())) {
          addErrorData($(input), "Invalid credit card number");
       }
    }
    
    // --- Hidden JavaScript
    
  2. 现在,我们需要更新主for循环以使用此函数,以便当用户单击提交按钮时仍执行表单验证,如下所示:

    for (var i = 0; i < inputs.length; i++) {
       var input = inputs[i];
       doValidation(input);
    }
    
  3. for循环后更新isError检查,以使用另一种方法来确定是否存在错误,以便仍然可以提交表单,如下所示:

    if ($('.error-data').length == 0) {
       //No errors, submit the form
       $('#webForm').submit();
    }
    
  4. 要对用户正在输入的字段执行验证,我们需要在keyup事件上调用doValidation()函数。将以下代码添加到$(function(){});块中,以将keyup事件处理程序附加到每个表单输入:

    $('input').on("keyup", function(){
       doValidation($(this));
    });
    
  5. 在 Web 浏览器中打开index.html,在电子邮件字段中开始输入,您将在输入时提供适当的错误消息,直到输入有效的电子邮件地址。

工作原理…

将之前的验证代码适应为为用户提供实时验证非常容易。将主验证触发器移动到另一个函数意味着可以重复使用代码而无需重复。包含这些触发器的函数接受一个参数,即它需要执行验证检查的输入。仍然使用for循环提供此输入,如下所示:

for (var i = 0; i < inputs.length; i++) {
   var input = inputs[i];
   doValidation(input);
}

不再依赖doValidation函数返回isError值,我们直接查看 DOM,通过查找带有error-data类的任何元素来查看屏幕上是否显示了任何错误,如下所示:

if ($('.error-data').length == 0) {
   //No errors, submit the form
   $('#webForm').submit();
}

如果没有错误,则如前所述手动提交表单。

为了提供实时验证,使用以下 jQuery 代码为每个表单输入附加一个keyup事件处理程序:

$('input').on("keyup", function(){
   doValidation($(this));
});

on()方法的回调函数将在用户在输入字段内按下并释放键时每次执行。然后可以使用$(this),它引用触发事件的输入,从而为doValidation()函数提供所需的输入对象来执行验证检查。

添加密码强度指示器

用户喜欢创建一个非常简单的密码,如 cat、john 或甚至 password,以便记住。然而,大多数人,特别是 Web 开发人员,知道这些类型的密码太不安全了,并且使用技术如字典攻击非常容易从加密数据库中解密出来。例如,密码强度指示器对于引导用户使用更复杂的密码非常有用。

准备工作

为了能够验证密码强度,我们需要创建一些规则供我们的代码使用。关于最佳密码类型有很多在线信息,但没有硬性规定。我们将为密码打分,根据以下每个规则得分一分:

  • 长度超过六个字符

  • 长度超过八个字符

  • 同时包含大写和小写字符

  • 至少包含一个数字

  • 它包含以下符号之一:@$!&^

此处的配方将在过去六个配方中创建的 Web 表单中添加密码强度指示器。在开始此步骤之前,请确保您已经获取了这些配方中的代码。

如何做…

为 Web 表单创建一个有效的密码强度指示器,需执行以下每个步骤:

  1. 更新index.html,为密码表单元素添加一些额外的类,并添加一些额外的 HTML,这将创建密码强度指示器,如下所示:

    // --- ADDITIONAL HTML HIDDEN
    <div class="input-frame">
    <label for="password">Password:</label>
    <input name="password" id="password" type="password" class="required password" />
    <div class="password-strength">
       <div class="inner"></div>
       <div class="text"></div>
    </div>
    </div>
    <div class="input-frame">
    <label for="confirmPassword">Confirm Password:</label>
    <input name="confirmPassword" id="confirmPassword" type="password" class="confirm-password" />
    </div>
    // --- ADDITIONAL HTML HIDDEN
    
  2. 将以下样式添加到styles.css的末尾,以将强度指示器定位在密码字段下方。这些样式还将允许强度指示器作为显示密码强度百分比的加载条。

    .password-strength {
       position: absolute;
       width: 150px;
       height: 20px;
       left: 69%;
       top: 35px;
       line-height: 20px;
       border: solid 1px #191919;
    }
    .password-strength .inner {
       position: absolute;
       left: 0;
       top: 0;
    }
    .password-strength .text {
       font-size: 11px;
       color: #FFF;
       text-align: center;
       position: relative;
       z-index: 10;
    }
    
  3. validatePasswords()函数添加到validation.js的末尾,用于确保输入了两个密码并确保它们匹配,如下所示:

    // --- HIDDEN JAVASCRIPT
    function validatePasswords(value) {
       var password = $('.password').val();
       if (value == "") {
          return "Both passwords are required";
       } else if (value != password) {
          return "Passwords do not match";
       }
       return true;
    }
    
  4. 将以下代码添加到doValidation()函数的末尾,以在confirm-password输入上运行validatePasswords()函数:

    function doValidation(input) {
    // --- HIDDEN JAVASCRIPT
    if ($(input).hasClass('confirm-password')) {
       var result = validatePasswords($(input).val());
          if (result != true) {
             addErrorData($(input), result);
          }
       }
    }
    
  5. validation.js 中的 $(function(){}); 块内添加以下 keyup 事件处理程序,以在用户在第一个密码字段中输入时评分密码强度:

    $('.password').on("keyup", function(){
       var score = 0;
       var password = $('.password');
       var passwordAgain = $('.confirm-password');
       //Remove any old errors for the password fields
       password.parent().removeClass('error');
       password.next('.error-data').remove();
       passwordAgain.parent().removeClass('error');
       passwordAgain.next('.error-data').remove();
       //Password is greater than 6 characters
       if (password.val().length > 6) {
          score++;
       }
       //Password is greater than 8 characters
       if (password.val().length > 8) {
          score++;
       }
       //Password has both uppercase and lowercase characters
       if (/(?=.*[A-Z])(?=.*[a-z])/.test(password.val())) {
          score++;
       }
       //Password has at least one number
       if (/(?=.*[0-9])/.test(password.val())) {
          score++;
       }
       //Password has at least one symbol (@$!&^) character
       if (/@|\$|\!|&|\^/.test(password.val())) {
          score++;
       }
       var fill = (100 - ((score * 2) * 10));
       var percent = (100 - fill);
       var level,
       colour;
       switch (score) {
       case 0:
       case 1:
       level = "Weak";
       colour = "green";
       break;
       case 2:
       case 3:
       level = "Medium";
       colour = "orange";
       break;
       case 4:
       level = "Strong";
       colour = "red";
       break;
       case 5:
       level = "Excellent";
       colour = "purple";
       break;
       }
       $('.password-strength .inner').css('right', fill + "%").css('background-color', colour);
       $('.password-strength .text').html(level + " (" + percent + "%)");
       });
    
  6. 在 Web 浏览器中打开 index.html,您会看到在第一个密码字段下方出现了一个额外的黑色框。开始输入密码,这个字段会在您输入时提供有关密码强度的信息。如下截图所示:

工作原理...

指示器本身的 HTML 具有 inner 元素和 text 元素。text 元素由 jQuery 用于显示基于输入密码的计算得分的密码强度和百分比。inner 元素用于形成彩色条。根据计算得分,jQuery 用于更改 inner 元素的颜色和定位,从而创建加载条效果,如前述截图所示。

使用的 CSS 需要很少的解释,因为它提供了基本的样式和定位。inner 元素具有绝对位置,以便在不同百分比下填充 password-strength 元素。text 分区具有设置了 z-index 参数,以确保文本始终显示在 inner 元素之上。

validatePasswords 函数是作为本篇配方的一部分创建的,它简单地为我们的应用程序添加了基本的密码验证。它检查确认密码字段是否已填写,并且该值是否与第一个密码字段匹配。在 doValdiation 函数中添加了额外的检查,以确保此验证与早期配方中创建的其他验证方法一起应用。

为了在用户在密码字段中输入时更新密码强度指示器,使用与 实施实时表单验证 配方中使用的相同方法,即使用 keyup 事件。使用 jQuery on() 函数将事件处理程序附加到 password 字段,如下所示:

$('.password').on("keyup", function(){
});

用于计算得分并更新 password-strength HTML 元素的代码随后放置在此事件处理程序的回调函数中。此代码的第一部分是删除密码字段当前显示的任何错误。

之后,有一系列的 if 语句,用于根据在本篇配方开始时定义的规则验证密码。首先是密码长度的基本验证,如下所示:

//Password is greater than 6 characters
if (password.val().length > 6) {
   score++;
}
//Password is greater than 8 characters
if (password.val().length > 8) {
   score++;
}

每次满足验证条件时,使用 score++ 将 score 变量递增 1

更复杂的规则使用正则表达式来确定密码值是否符合额外得分点的要求,如下所示:

//Password has both uppercase and lowercase characters
if (/(?=.*[A-Z])(?=.*[a-z])/.test(password.val())) {
   score++;
}
//Password has at least one number
if (/(?=.*[0-9])/.test(password.val())) {
   score++;
}
//Password has at least one symbol (@$!&^) character
if (/@|\$|\!|&|\^/.test(password.val())) {
   score++;
}

在考虑了五条规则后,最终分数用于计算填充值。填充值是需要从强度指示器右侧填充的inner元素的百分比。这允许我们创建加载条效果。除了填充值,还计算出一个普通百分比,以与强度级别文字一起显示,如下所示:

var fill = (100 - ((score * 2) * 10));
var percent = (100 - fill);

之后,分数值再次被用来确定inner元素的背景颜色和强度级别文字,如下所示:

var level,
colour;
switch (score) {
case 0:
case 1:
   level = "Weak";
   colour = "green";
break;
case 2:
case 3:
   level = "Medium";
   colour = "orange";
   break;
case 4:
   level = "Strong";
   colour = "red";
break;
case 5:
   level = "Excellent";
   colour = "purple";
break;
}

最后,使用 jQuery password-strength,HTML 代码更新为获取的信息,以向用户显示结果,如下所示:

$('.password-strength .inner').css('right', fill + "%").css('background-color', colour);
$('.password-strength .text').html(level + " (" + percent + "%)");

还有更多…

这段代码应该很容易调整,这样你就可以添加自己关于密码强度的规则。在网上有很多讨论和资源可以告诉你一个强密码应该是什么样子的。

另请参阅

  • 实现实时表单验证

添加反垃圾邮件措施

大多数网页开发者都会知道,如果你的网站上有联系表单或任何类型的网页表单公开可用,就会有网页机器人提交和大量垃圾邮件。在过去的七个配方中,我们一直在创建仅使用 JavaScript 的网页表单来阻挡大多数网页机器人,但随着浏览器自动化和网页机器人变得更加聪明,向你的网页表单添加反垃圾邮件措施仍然很重要。

准备工作

确保你已经完成了最后七个配方,并且代码随时可用。记住,如果你只想使用代码而不完全理解它是如何工作的,跳到本章末尾的它是如何工作的...部分,获取所有内容。

如何去做…

通过执行以下每个步骤,向你的网页表单添加简单的反垃圾邮件措施:

  1. 更新index.html,在标记为确认密码的输入下添加一个额外的表单输入,如下所示:

    <!-- HIDDEN HTML CODE -->
    <div class="input-frame">
       <label>Confirm Password:</label>
       <input type="password" class="confirm-password" />
    </div>
    <div class="input-frame">
       <label>Enter the number <span class="anti-spam-number"></span>:</label>
       <input type="text" class="required anti-spam-input" />
    </div>
    <!-- HIDDEN HTML CODE -->
    
  2. 使用 JavaScript,在validation.js顶部使用以下代码生成一个介于1100之间的随机数:

    var spamNumber = Math.floor(Math.random() * (100 - 1 + 1)) + 1;
    $(function(){
    // --- HIDDEN JAVASCRIPT CODE
    
  3. $(function(){}); jQuery 区块的最后,添加以下代码,以更新 HTML 的anti-spam-number span 元素为随机数字:

    // --- HIDDEN JAVASCRIPT CODE
    $('.anti-spam-number').html(spamNumber);
    });
    
  4. doValidation()函数的末尾添加以下附加验证检查:

    if ($(input).hasClass('anti-spam-input') && !validateAntiSpam($(input).val())) {
       addErrorData($(input), "Incorrect Anti-Spam answer");
    }
    
  5. 最后,在validation.js的末尾,添加validateAntiSpam()函数,之前的代码调用该函数:

    // --- HIDDEN JAVASCRIPT CODE
    function validateAntiSpam(value) {
       if (value != "") {
          if (parseInt(value)!= spamNumber) return false;
       }
       return true;
    }
    
  6. 在 web 浏览器中打开index.html,你会看到额外的反垃圾邮件表单输入字段。每次刷新页面,它会要求你输入不同的数字。

它是如何工作的…

通过将spamNumber全局变量声明在任何函数之外,它可供整个 JavaScript 文件使用。在每次页面加载时,生成一个介于1100之间的新数字,这样网页机器人就不能存储答案并提交表单。在 HTML 代码中,有一个具有类anti-spam-numberspan元素,使用以下代码在页面加载时更新为随机数字:

$('.anti-spam-number').html(spamNumber);

这将确保用户被告知输入正确的数字。我们创建了一个额外的验证函数,名为validateAntiSpam,并从doValidation()函数中调用所有具有anti-spam-input类的输入。然后,这将使用全局可用的spamNumber变量验证用户输入的数字,如下所示:

function validateAntiSpam(value) {
   if (value != "") {
      if (parseInt(value)!= spamNumber) return false;
   }
   return true;
}

请注意,将输入解析为整数以确保数字之间的比较。如果值不匹配,这个函数将返回false,以便doValidation()函数可以为用户在屏幕上创建适当的错误消息。

还有更多…

这种客户端垃圾邮件验证不能完全信赖。它对一般网页机器人有效,但不能对直接针对你的网站的机器人起作用。如果有人想要为你的网站编写一个特定的机器人脚本,那么绕过这个 JavaScript 并不是一个困难的过程。如果你觉得这是可能的,那么必须使用更极端的服务器端垃圾邮件预防方法。

在互联网上有许多有效的防垃圾邮件方法可以免费获得。最流行的是 CAPTCHA。最流行的 CAPTCHA 之一是谷歌在www.google.com/recaptcha上免费提供的。

另请参阅

  • 添加密码强度指示器

实现输入字符限制

到目前为止,本章中的所有示例都集中在输入验证和向用户提供适当反馈的方面。有些情况下,最好是阻止用户根本不输入无效的字符。通常不会使用这种方法,因为对于一些用户来说这可能会很令人困惑;例如,如果他们不被告知为什么不能输入。这种方法适用的情况是登录表单。如果你知道你的注册系统不允许用户名中含有,你就知道用户输入是错误的,因此阻止输入是可以接受的。这个示例提供了一种方法,可以防止用户在输入字段中输入非字母数字字符。

准备工作

这个示例不使用前八个示例中的代码;不过,CSS 代码中有相似之处。完成这个示例,你将需要三个文件。在存储最新版本的 jQuery 的同一目录中创建recipe-9.htmlrecipe-9.jsrecipe-9.css

如何做…

使用 jQuery 来防止用户通过以下步骤在文本输入中输入无效的章节:

  1. 将以下 HTML 代码添加到recipe-9.html中。这将创建一个基本的登录表单,并包括另外两个文件以及 jQuery 库:

    <!DOCTYPE html>
    <html >
    <head>
       <title>Chapter 5 :: Recipe 7</title>
       <link type="text/css" media="screen" rel="stylesheet" href="recipe-9.css" />
       <script src="img/jquery.min.js"></script>
       <script src="img/recipe-9.js"></script>
    </head>
    <body>
    <form id="webForm" method="POST">
       <div class="header">
          <h1>Register</h1>
       </div>
       <div class="input-frame">
          <label for="username">Username:</label>
          <input name="username" id="username" type="text" class="username" />
       </div>
       <div class="input-frame">
          <label for="password">Password:</label>
          <input name="password" id="password" type="text" class="required" />
       </div>
       <div class="actions">
          <button class="submit-btn">Submit</button>
       </div>
    </form>
    </body>
    </html>
    
  2. 将以下 CSS 代码添加到recipe-9.css中,为登录表单添加样式:

    @import url(http://fonts.googleapis.com/css?family=Ubuntu);
    body {
       background-color: #FFF;
       font-family: 'Ubuntu', sans-serif;
    }
    form {
       width: 500px;
       margin: 10px auto auto auto;
       padding: 20px;
       background-color: #333;
       border-radius: 5px;
       color: #747474;
       border: solid 2px #000;
    }
    form label {
       font-size: 14px;
       line-height: 30px;
       padding-bottom: 8px;
       width: 140px;
       display: inline-block;
       text-align: right;
    }
    .input-frame {
       clear: both;
       margin-bottom: 25px;
       position: relative;
    }
    form input {
       height: 30px;
       width: 330px;
       margin-left: 10px;
       background-color: #191919;
       border: solid 1px #404040;
       padding-left: 10px;
       color: #DB7400;
    }
    form input:hover {
       background-color: #262626;
    }
    form input:focus {
       border-color: #DB7400;
    }
    form .header {
       margin: -20px -20px 25px -20px;
       padding: 10px 10px 10px 20px;
       position: relative;
       background-color: #DB7400;
       border-top-left-radius: 4px;
       border-top-right-radius: 4px;
    }
    form .header h1 {
       line-height: 50px;
       margin: 0;
       padding: 0;
       color: #FFF;
       font-weight: normal;
    }
    .actions {
       text-align: right;
    }
    .submit-btn {
       background-color: #DB7400;
       border: solid 1px #000;
       border-radius: 5px;
       color: #FFF;
       padding: 10px 20px 10px 20px;
       text-decoration: none;
       cursor: pointer;
    }
    
  3. 将以下 JavaScript 代码添加到recipe-9.js中,以监视username字段上的用户输入,并确保不输入非字母数字字符:

    $(function(){
        $('.username').on("keypress", function(event){
            //Get key press character code
            var key = String.fromCharCode(event.which);
            if (/[^a-zA-Z\d\s:]/.test(key)) {
                event.preventDefault();
                return false;
            }
        });
    });
    
  4. 在 Web 浏览器中打开 recipe-9.html 并尝试在 username 字段中输入非字母数字字符(例如,$)。你会发现它不会被放置在字段中。

工作原理…

页面加载时将键按下事件处理程序附加到 username 字段。此事件处理程序的回调函数有一个参数,即 event 对象。此 event 对象提供对用户按下的键的键码的访问。当 username 字段具有焦点并且用户按下键时,将执行回调函数。

首先,String.fromCharCode(event.which); 用于获取按下键的字符串值;例如,DH4。然后使用正则表达式来确定该字符是否是字母数字字符。如果不是,则使用以下代码阻止该字符输入到表单字段中:

if (/[^a-zA-Z\d\s:]/.test(key)) {
   event.preventDefault();
   return false;
}

更多内容…

确保此示例中使用的事件是 keypress 事件。如果使用了替代事件,如 keydown,可能无法达到预期的结果。如果使用 keydown 事件,当用户按下 Shift + 4 来输入 $ 符号时,keydown 事件将以 4 而不是 $ 提供其事件处理程序,因此未通过验证。

第六章:用户界面

在本章中,我们将涵盖以下主题:

  • 操纵元素的 CSS

  • 创建一个新闻滚动条

  • 创建固定元素

  • 实现平滑滚动

  • 创建一个动态目录表

  • 创建基本的拖放功能

  • 创建一个动态动画树形菜单

  • 创建一个手风琴内容滑块

  • 创建标签式内容

  • 创建一个模态框弹出窗口

  • 创建一个可拖动的内容弹出窗口

介绍

jQuery 赋予开发人员轻松创建复杂用户界面元素的能力。正因为如此,有大量的 jQuery 插件允许开发人员快速将这些界面添加到其网站中。另外,jQuery 的 UI 框架还拥有许多热门界面元素,如手风琴、表格内容、模态框等。如果您想了解如何在自己的网站上使用 jQuery UI,请直接跳转至第九章,jQuery UI。本章将专注于从头开始开发一些这些常见的 UI 元素,提供无限的定制性,并让您了解其他插件的工作原理。

操纵元素的 CSS

jQuery 允许开发者直接访问 DOM 元素的 CSS 属性。这为您基于 JavaScript 中的数据轻松改变应用程序的外观和感觉提供了一种简单的方式。本教程将向您展示如何在各种元素中操纵 DOM CSS。

准备工作

对于这个教程,您将需要三个文件。使用您选择的编辑器,在与最新版本的 jQuery 库相同的目录中创建recipe-1.htmlrecipe-1.jsrecipe-1.css

如何做…

在您刚刚创建的三个文件中,打开每个文件进行编辑,并执行以下步骤:

  1. 将以下 HTML 代码添加到recipe-1.html;确保更改包含 jQuery 库的 JavaScript 的源位置,将其指向您计算机上下载的最新版本的 jQuery:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 6 :: Recipe 1</title>
        <link href="recipe-1.css" rel="stylesheet" 
              type="text/css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/recipe-1.js"></script>
    </head>
    <body>
        <div class="header">
            <h1>ALTER ELEMENT CSS WITH JQUERY</h1>
        </div>
        <div class="content-frame">
            <div class="left">
                <h1>SOME TITLE HERE</h1>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                <h2>SOME KIND OF SUBTITLE HERE</h2>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
            </div>
            <div class="right">
                <h3>TITLE COLOUR</h3>
                <select class="title-colour">
                    <option value="#">Default</option>
                    <option value="red">Red</option>
                    <option value="green">Green</option>
                    <option value="orange">Orange</option>
                    <option value="blue">Blue</option>
                </select>
                <h3>PARAGRAPH SIZE</h3>
                <select class="p-size">
                    <option value="#">Default</option>
                    <option value="10px">10px</option>
                    <option value="15px">15px</option>
                    <option value="20px">20px</option>
                    <option value="25px">25px</option>
                </select>
            </div>
        </div>
    </body>
    </html>
    
  2. 将以下 CSS 代码添加到recipe-1.css

    body {
        margin: 0;
        background-color: #5dace7;
    }
    .header {
        height: 150px;
        background-color: #0174cd;
    }
    .header h1 {
        margin: 0 50px 0 50px;
        padding: 0;
        line-height: 100px;
        font-size: 40px;
        color: #FFFFFF;
    }
    .content-frame {
        margin: -50px 50px 0 50px;
        background-color: #FFFFFF;
        border-radius: 10px;
        min-height: 500px;
        position: relative;
    }
    .content-frame .left {
        margin-right: 20%;
        padding: 20px;
    }
    .content-frame .left h1 {
        margin: 0;
    }
    .content-frame .right {
        width: 16%;
        padding: 2%;
        position: absolute;
        top: 0;
        right: 0;
        background-color: #F1F1F1;
        border-top-right-radius: 10px;
        border-bottom-right-radius: 10px;
    }
    .content-frame .right h3 {
        margin: 0;
        line-height: 30px;
        color: #333333;
    }
    .content-frame .right select {
        width: 100%;
    }
    
  3. 将以下 jQuery 代码添加到recipe-1.js中,以为 HTML 代码中的 select 下拉框添加功能:

    $(function(){
        $('.title-colour').on("change", function(){
            var colour = $(this).val();
            if (colour == "#") {
                colour = "";
            }
            $('h1, h2').css("color", colour);
        });
        $('.p-size').on("change", function(){
            var size = $(this).val();
            if (size == "#") {
                size = "";
            }
            $('p').css("font-size", size);
        });
    });
    
  4. 在 web 浏览器中打开recipe-1.html,您应该会看到以下简单的网页:如何做…

  5. 使用右侧的下拉菜单来修改标题和段落元素的 CSS。

它是如何工作的…

HTML 创建了一个基本的网页,提供这样的元素,以便它们的 CSS 可以被 jQuery 操纵,并提供一个简单的界面来启动这些更改。recipe-1.css中的 CSS 代码添加了基本的样式来创建我们的网页布局。

要更改元素的 CSS,将change事件处理程序附加到两个 select 下拉框,使用它们各自的类名:

$(function(){
   $('.title-colour').on("change", function(){

});
$('.p-size').on("change", function(){

});
});

这将允许我们在用户更改标题颜色 (title-colour) 或段落大小 (p-size) 下拉菜单的值时执行一些代码。使用 $(this).val(),可以获取所选选项的值,如下面的代码片段所示:

$(function(){
    $('.title-colour').on("change", function(){
        var colour = $(this).val();
        if (colour == "#") {
            colour = "";
        }
        $('h1, h2').css("color", colour);
    });
    $('.p-size').on("change", function(){
        var size = $(this).val();
        if (size == "#") {
            size = "";
        }
        $('p').css("font-size", size);
    });
});

使用 coloursize 变量(它们保存了各自下拉菜单中选定的值),我们确定默认选项是否已被选中,使用其值 #。如果已选择,则我们将 coloursize 值设置为空,允许用户将操纵的 CSS 重置为默认值。

如果选择了除默认选项之外的选项,则该值将与 jQuery 的 css() 函数中的相应 CSS 选项一起使用,如下面的代码片段中所示:

$(function(){
    $('.title-colour').on("change", function(){
        var colour = $(this).val();
        if (colour == "#") colour = "";
        $('h1, h2').css("color", colour);
    });
    $('.p-size').on("change", function(){
        var size = $(this).val();
        if (size == "#") size = "";
        $('p').css("font-size", size);
    });
});

创建一个新闻滚动条

本教程将向您展示如何创建一个带有停止/暂停功能的简单新闻滚动条。新闻滚动条是在小空间中显示大量信息(如推文、引用语或一般新闻项目)的绝佳方式。

准备工作

再次,您需要创建三个文件。在与最新版本的 jQuery 相同的目录中创建 recipe-2.htmlrecipe-2.cssrecipe-2.js

如何操作…

按照以下逐步说明创建一个动画新闻滚动条:

  1. 将以下 HTML 代码添加到 recipe-2.html 中,以创建一个简单的网页和我们的滚动条内容:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 6 :: Recipe 2</title>
        <link href="recipe-2.css" rel="stylesheet" type="text/css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/recipe-2.js"></script>
    </head>
    <body>
    <div class="header">
        <h1>CONTENT TICKER</h1>
    </div>
    <div class="content-frame">
        <ul id="ticker">
            <li>Learn from yesterday, live for today, hope for tomorrow. The important thing is not to stop questioning</li>
            <li>Try not to become a man of success, but rather try to become a man of value</li>
            <li>Logic will get you from A to B. Imagination will take you everywhere</li>
            <li>Reality is merely an illusion, albeit a very persistent one</li>
        </ul>
    </div>
    </body>
    </html>
    
  2. 将以下简单的 CSS 添加到 recipe-2.css 中,为我们的网页添加样式:

    body {
        margin: 0;
        background-color: #5dace7;
    }
    .header {
        height: 130px;
        background-color: #0174cd;
    }
    .header h1 {
        margin: 0 50px 0 50px;
        padding: 0;
        line-height: 100px;
        font-size: 40px;
        color: #FFFFFF;
    }
    .content-frame {
        margin: -30px 50px 0 50px;
        background-color: #FFFFFF;
        border-radius: 10px;
        height: 50px;
        position: relative;
        padding: 0 20px 0 20px;
        overflow: hidden;
    }
    .content-frame ul {
        list-style: none;
        margin: 0;
        padding: 0;
    }
    .content-frame ul li {
        line-height: 50px;
    }
    
  3. 将以下 jQuery 代码添加到 recipe-2.js 中,使我们的滚动条生效:

    var tick = null;
    var interval = 2000;
    $(function(){
        tick = setInterval(function(){
            ticker()
        }, interval);
        $('.content-frame').on("mouseover", function(){
            clearInterval(tick);
        });
        $('.content-frame').on("mouseout", function(){
            tick = setInterval(function(){
                ticker()
            }, interval);
        });
    });
    function ticker() {
        $('#ticker li:first-child').slideUp(function(){
            $(this).appendTo($('#ticker')).slideDown();
        });
    }
    
  4. 在网络浏览器中打开 recipe-2.html 将呈现一个简单的网页和一个动画滚动条,每两秒显示爱因斯坦的不同引用语。

工作原理…

由于 HTML 和 CSS 代码非常简单,因此唯一需要解释的是 jQuery 代码。请注意,HTML 网页包含一个无序列表元素,其中包含四条爱因斯坦的引用语,位于名为 content-frame 的 division 元素内。content-frame 元素的 overflow 属性设置为 hidden,以便一次只显示一个引用语。

recipe-2.js 文件的顶部声明了两个变量:tickintervaltick 变量是 JavaScript 的 setInterval() 函数将要声明的地方。JavaScript 的 setInterval() 函数允许我们指定一个函数和一个间隔。然后,指定的函数将在指定的间隔内再次调用。这使我们能够循环遍历新闻滚动条内容。

通过在 JavaScript 文件顶部声明 tick 变量,我们可以在以后的某个时间点停止间隔以添加暂停功能。interval 变量只是保存我们希望 setInterval() 函数在再次调用指定函数之前等待的毫秒数:

var tick = null;
var interval = 2000;
$(function(){

});

在 jQuery 的加载函数内部,我们将tick变量分配给setInterval()函数,指定函数再次调用,然后使用interval变量设置间隔持续时间,如以下代码段所示:

$(function(){
    tick = setInterval(function(){
        ticker();
    }, interval);
});

要添加停止/启动功能,根据用户将鼠标悬停在滚动条上时停止滚动并在将鼠标移开时重新启动滚动的要求,我们需要为content-frame部分元素附加两个事件处理程序,如下所示:

$(function(){
    tick = setInterval(function(){
        ticker()
    }, interval);
    $('.content-frame').on("mouseover", function(){
        clearInterval(tick);
    });
    $('.content-frame').on("mouseout", function(){
        tick = setInterval(function(){
            ticker()
        }, interval);
    });
});

mouseover事件处理程序使用 JavaScript 的clearInterval()函数,并将tick变量作为参数传递。当用户将鼠标悬停在content-frame元素上时,这将阻止setInterval()函数再次调用ticker()函数。在mouseout事件的回调函数中,使用相同的setInterval()函数重新声明tick变量,重新初始化新闻滚动条并再次启动它。

最后,还有ticker()函数本身。此函数使用 jQuery 的slideUp()函数将第一个列表元素向上滑动。这提供了下一个元素进入视图的效果。然后,它使用appendTo()将使用slideUp()函数隐藏的元素移动到滚动条列表的末尾。最后,它使用slideDown()将此元素再次滑动下来,以便在最终再次移动到列表顶部时准备显示。如以下代码段所示:

function ticker() {
    $('#ticker li:first-child').slideUp(function(){
        $(this).appendTo($('#ticker')).slideDown();
    });
}

更多内容…

可以以任何你喜欢的方式采用启动和停止功能,例如,使用启动和停止按钮,或者甚至一个单独的暂停按钮,以便更明显地表明可以暂停滚动。本示例中使用的方法的好处是,链接通常会显示在滚动内容中。当用户试图点击滚动内容中的链接时,滚动将停止,允许他们点击链接,而不是在他们点击之前链接就移开。

另请参阅

  • 创建动态目录

创建固定元素

固定元素是页面元素,在用户滚动时会固定在浏览器中的位置。固定元素用于始终保持内容在用户视线内。这些内容可以是导航、重要信息,甚至是广告。本示例将展示如何创建固定元素,并且使用 jQuery 在用户滚动到页面上某一点时激活它们。

准备工作

使用你喜欢的编辑器,在与你的 jQuery 库相同的目录下创建三个文件,分别命名为recipe-3.htmlrecipe-3.cssrecipe-3.js

如何做…

对于每个新创建的文件,执行以下步骤:

  1. 将以下 HTML 代码添加到recipe-3.html中;它创建了一个长网页,可以滚动,并且一个div元素,其中包含一些重要内容需要始终保持在用户视线内:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 6 :: Recipe 3</title>
        <link href="recipe-3.css" rel="stylesheet" type="text/css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/recipe-3.js"></script>
    </head>
    <body>
    <div class="header">
        <h1>STICKY ELEMENTS RECIPE</h1>
    </div>
    <div class="content-frame">
        <div class="left">
            <h1>STICKY ELEMENTS</h1>
            <p>Sticky elements are great to keep important content within the users view, such as share buttons, navigation and also table of contents.</p>
            <p>Scroll down this page and when you are about to go past the important content on the right hand side, it will start to follow you down the screen.</p>
        </div>
        <div class="right">
            <ul>
                <li><a href="#">Navigation Item 1</a></li>
                <li><a href="#">Navigation Item 2</a></li>
                <li><a href="#">Navigation Item 3</a></li>
                <li><a href="#">Navigation Item 4</a></li>
                <li><a href="#">Navigation Item 5</a></li>
                <li><a href="#">Navigation Item 6</a></li>
            </ul>
            <div class="important">
                <p>Here is some important content.</p>
            </div>
        </div>
    </div>
    </body>
    </html>
    
  2. 为了给这个页面添加样式,将以下 CSS 代码添加到 recipe-3.css 文件中;代码中还包含一个 sticky 类,在用户滚动页面时会被 jQuery 应用到重要元素上:

    @import url(http://fonts.googleapis.com/css?family=Ubuntu);
    body {
        margin: 0;
        background-color: #5dace7;
        font-family: 'Ubuntu', sans-serif;
    }
    .header {
        height: 150px;
        background-color: #0174cd;
    }
    .header h1 {
        width: 1000px;
        margin: auto;
        padding: 0;
        line-height: 100px;
        font-size: 40px;
        color: #FFFFFF;
    }
    .content-frame {
        margin: -50px auto auto auto;
        width: 1000px;
        background-color: #FFFFFF;
        border-radius: 10px;
        min-height: 1300px;
        position: relative;
    }
    .content-frame .left {
        margin-right: 240px;
        padding: 20px;
    }
    .content-frame .left h1 {
        margin: 0;
    }
    .content-frame .right {
        width: 200px;
        padding: 10px;
        position: absolute;
        top: 0;
        right: 0;
        background-color: #F1F1F1;
        border-top-right-radius: 10px;
        border-bottom-right-radius: 10px;
    }
    .content-frame .right .important {
        border: solid 1px #CCCCCC;
        text-align: center;
        width: 200px;
    }
    .sticky {
        position: fixed;
        top: 10px;
    }
    
  3. 最后,将以下 jQuery 代码添加到 recipe-3.js 中,当用户试图滚过时,将激活固定元素:

    var importantOrigin = {};
    $(function(){
        importantOrigin = $('.important').offset();
        $(window).scroll(function(){
            sticky();
        });
    });
    function sticky() {
        var _important = $('.important');
        var scrollPosition = $('body, html').scrollTop();
        if (importantOrigin.top < scrollPosition) {
            _important.addClass("sticky");
        } else {
            _important.removeClass("sticky");
        }
    }
    

工作原理...

recipe-3.js 的顶部,有一个名为 importantOrigin 的变量,它将用于存储重要部分元素的原始位置。在 jQuery 的加载块中,使用 $('.important').offset() 获取重要元素的顶部和左侧位置,并将这些值存储在先前创建的 importantOrigin 变量中。如下面的代码片段所示:

var importantOrigin = {};
$(function(){
    importantOrigin = $('.important').offset();
    $(window).scroll(function(){
        sticky();
    });
});

jQuery 的 scroll() 函数用于在用户滚动页面时执行 sticky() 方法:

function sticky() {
    var _important = $('.important');
    var scrollPosition = $('body, html').scrollTop();
    if (importantOrigin.top < scrollPosition) {
        _important.addClass("sticky");
    } else {
        _important.removeClass("sticky");
    }
}

sticky() 方法使用 $('body, html').scrollTop() 获取页面的当前垂直位置,然后将其与重要元素的顶部位置进行比较。如果用户滚过了重要元素,则使用 addClass() 方法将 sticky CSS 类应用于重要元素:

.sticky {
    position: fixed;
    top: 10px;
}

如果页面的当前垂直位置低于 sticky 元素的顶部,则使用 removeClass()sticky 类移除,将重要元素恢复到其原始状态。在 CSS 中使用 position: fixed;,可以使元素固定在页面的某一点。使用 jQuery 条件性地应用此 CSS,我们可以控制何时应用元素固定,因为通常直到用户滚动过元素,使其不再在屏幕上可见,才希望这样做。

还有更多...

有一个流行的 jQuery 插件叫做 sticky.js,可以在 stickyjs.com/ 找到。该插件使用了您在本文档中学到的相同原理,并将所有功能打包成插件,以便于重用。

参见

  • 创建一个动态目录表

实现平滑滚动

锚点链接用于导航到页面的不同部分,使用户能够轻松地跳过他们不感兴趣的信息,直接进入感兴趣的部分。然而,当屏幕上有大量文本数据时,在这些不同部分之间跳转通常会让用户感到困惑。使用平滑滚动并将屏幕动画地缓慢向上或向下移动到所选部分,用户可以更容易地可视化自己导航到的位置,而不会感到迷失方向。

准备工作

只需创建三个标准的配方文件,recipe-4.htmlrecipe-4.cssrecipe-4.js,并将它们保存到与最新版本的 jQuery 库相同的目录中。

实现方法...

执行以下简单步骤,为网站或网页添加平滑滚动效果:

  1. 通过将以下 HTML 代码添加到 recipe-4.html 文件中,可以创建一个较长的网页:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 6 :: Recipe 4</title>
        <link href="recipe-4.css" rel="stylesheet" type="text/css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/recipe-4.js"></script>
    </head>
    <body>
    <div class="header">
        <h1 id="top">SMOOTH SCROLLING RECIPE</h1>
    </div>
    <div class="content-frame">
        <div class="left">
            <h2 id="one">SECTION 1 <a href="#top" class="top-link">[TOP]</a></h2>
            <div class="section"></div>
            <h2 id="two">SECTION 2 <a href="#top" class="top-link">[TOP]</a></h2>
            <div class="section"></div>
            <h2 id="three">SECTION 3 <a href="#top" class="top-link">[TOP]</a></h2>
            <div class="section"></div>
            <h2 id="four">SECTION 4 <a href="#top" class="top-link">[TOP]</a></h2>
            <div class="section"></div>
        </div>
        <div class="right">
            <h2>NAVIGATION</h2>
            <ul>
                <li><a href="#one">SECTION ONE</a></li>
                <li><a href="#two">SECTION TWO</a></li>
                <li><a href="#three">SECTION THREE</a></li>
                <li><a href="#four">SECTION FOUR</a></li>
                <li><a href="http://www.google.com" target="_blank">EXTERNAL LINK</a></li>
                <li><a href="#">EMPTY LINK</a></li>
            </ul>
        </div>
    </div>
    </body>
    </html>
    
  2. 通过将以下 CSS 代码添加到recipe-4.css中(此文件在前面的 HTML 页面中已经包含)来为这个页面添加样式:

    @import url(http://fonts.googleapis.com/css?family=Ubuntu);
    body {
        margin: 0;
        background-color: #5dace7;
        font-family: 'Ubuntu', sans-serif;
    }
    .header {
        height: 150px;
        background-color: #0174cd;
    }
    .header h1 {
        width: 1000px;
        margin: auto;
        padding: 0;
        line-height: 100px;
        font-size: 40px;
        color: #FFFFFF;
    }
    .content-frame {
        margin: -50px auto auto auto;
        width: 1000px;
        background-color: #FFFFFF;
        border-radius: 10px;
        min-height: 1300px;
        position: relative;
    }
    .content-frame .left {
        margin-right: 240px;
        padding: 20px;
    }
    .content-frame .left h1 {
        margin: 0;
    }
    .content-frame .right {
        width: 200px;
        padding: 10px;
        position: absolute;
        top: 0; 
        right: 0;
        background-color: #F1F1F1;
        border-top-right-radius: 10px;
        border-bottom-right-radius: 10px;
    }
    .content-frame .right h2 {
        margin: 0;
        padding: 0;
    }
    .section {
        height: 400px;
        background-color: #CCCCCC;
        margin-bottom: 20px;
    }
    .top-link {
        width: 50px;
        text-align: right;
        float: right;
        font-size: 12px;
    }
    
  3. 将以下 jQuery 代码添加到recipe-4.js以捕捉锚点元素点击并提供平滑滚动效果:

    $(function(){
        $('a[href*=#]:not([href=#])').click(function(){
            if (this.hash.length > 0) {
                $('body, html').animate({
                    scrollTop: $(this.hash).offset().top
                }, 1000);
            }
            return false;
        });
    });
    

工作原理…

jQuery 代码首先将click事件处理程序附加到某些锚点元素上:

$(function(){
    $('a[href*=#]:not([href=#])').click(function(){

    });
});

前面的代码将仅将click事件处理程序附加到其href属性中具有哈希(#)的锚点。还使用:not([href=#]),以便不会将事件处理程序附加到其href属性只有一个哈希的锚点。现在,我们可以指定要执行的代码,以便在页面上导航到其他部分的链接。空白和外部链接将被忽略并像往常一样运行。

click事件处理程序的callback()函数内,我们可以使用this.hash来检索点击的锚点元素的href属性中的哈希值。如果锚点链接到#two,我们会收到字符串值"#two"。使用this.hash.length,我们可以确保值是有效的,并且我们可以继续提供平滑滚动动画:

$(function(){
    $('a[href*=#]:not([href=#])').click(function(){
        if (this.hash.length > 0) {

        }
        return false;
    });
});

this.hash.lengthif语句内,我们使用 jQuery 的animate()函数如下来动画和滚动用户到锚点目标的位置:

$('body, html').animate({
   scrollTop: $(this.hash).offset().top
}, 1000);

scrollTop参数是动画应该滚动到的位置。我们通过使用$(this.hash)选择目标元素,然后使用 jQuery 的offset()函数获取其顶部位置。

最后,在this.hash.lengthif语句之后返回false,以防止点击事件的默认操作。如果去掉return false,在动画开始之前会出现屏幕闪烁,因为点击事件的默认操作(将用户发送到链接的部分)发生在动画开始之前。

另见

  • 创建一个动态目录

创建一个动态目录

目录是让用户快速找到他们正在寻找的内容部分的常见方式。使用 jQuery,可以根据页面上的 HTML 标题元素动态创建目录。这对于博客文章或其他拥有许多不同内容页面的网站非常有用。

准备工作

创建recipe-5.htmlrecipe-5.cssrecipe-5.js,并像以前一样都准备好进行编辑。

如何做…

创建了必需的文件之后,按照以下步骤创建一个动态目录:

  1. 使用以下 HTML 代码创建一个基本网页,并将其添加到recipe-5.html中:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 6 :: Recipe 5</title>
        <link href="recipe-5.css" rel="stylesheet" type="text/css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/recipe-5.js"></script>
    </head>
    <body>
    </body>
    </html>
    
  2. 将以下 HTML 代码添加到刚刚添加的 body 标签内的 recipe-5.html 中;这将创建一个带有分节内容和有序列表元素的页面,可以填充内容:

    <div class="header">
        <h1>DYNAMIC TABLE OF CONTENTS</h1>
    </div>
    <div class="content-frame">
        <div class="left">
            <h1 id="one">MAIN HEADING</h1>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
            <h2 id="two">SUBTITLE</h2>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
            <h3 id="three">SUB-SUBTITLE</h3>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
            <h2 id="four">SUBTITLE</h2>
            <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
            <h3 id="five">SUB-SUBTITLE</h3>
            <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
            <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
            <h4 id="six">SUB-SUB-SUBTITLE</h4>
            <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
        </div>
        <div class="right">
            <h2>CONTENTS</h2>
            <ol class="contents"></ol>
        </div>
    </div>
    
  3. 将以下 CSS 添加到recipe-5.css以向此页面添加基本样式。这段 CSS 代码再次与本章前两个示例中的代码非常相似:

    @import url(http://fonts.googleapis.com/css?family=Ubuntu);
    body {
        margin: 0;
        background-color: #5dace7;
        font-family: 'Ubuntu', sans-serif;
    }
    .header {
        height: 150px;
        background-color: #0174cd;
    }
    .header h1 {
        width: 1000px;
        margin: auto;
        padding: 0;
        line-height: 100px;
        font-size: 40px;
        color: #FFFFFF;
    }
    .content-frame {
        margin: -50px auto auto auto;
        width: 1000px;
        background-color: #FFFFFF;
        border-radius: 10px;
        min-height: 1300px;
        position: relative;
    }
    .content-frame .left {
        margin-right: 240px;
        padding: 20px;
    }
    .content-frame .left h1 {
        margin: 0;
    }
    .content-frame .right {
        width: 200px;
        padding: 10px;
        position: absolute;
        top: 0;
        bottom: 0;
        right: 0;
        background-color: #F1F1F1;
        border-top-right-radius: 10px;
        border-bottom-right-radius: 10px;
    }
    .content-frame .right h2 {
        margin: 0;
        padding: 0;
    }
    
  4. 将以下 jQuery 代码添加到recipe-5.js中,它将根据我们刚刚创建的 HTML 页面中的标题部分填充有序列表:

    $(function(){
        var _contents = $('.content-frame .left');
        var _headers = _contents.find("h1, h2, h3, h4");
        _headers.each(function(index, value){
            var _header = $(value);
            var level = parseInt(_header.context.localName.replace("h", ""));
            if (typeof _header.attr("id") != "undefined") {
                var listItem = $("<li><a href='#" + _header.attr("id") + "'>" + _header.html() + "</a></li>");
            } else {
                var listItem = $("<li>" + _header.html() + "</li>");
            }
            listItem.css("padding-left", (level * 5));
            $('.contents').append($(listItem));
        });
    });
    
  5. 在网页中打开recipe-5.html将向您展示内容在屏幕左侧,动态生成的内容列表在右侧,如下截图所示:如何做…

它是如何运行的...

HTML 代码提供了一个包含由h1h2h3h4标签标头的各种部分以及一个空的有序列表元素的内容窗格。

我们的 jQuery 代码首先选择内容部分,然后使用 jQuery find()函数找到其中的所有标题元素,并指定h1, h2, h3, h4作为唯一参数。这将创建一个找到的元素数组,并将它们存储在_headers数组中,如下代码片段所示:

$(function(){
    var _contents = $('.content-frame .left');
    var _headers = _contents.find("h1, h2, h3, h4");
// --- HIDDEN CODE
});

然后使用 jQuery each()函数,可以遍历找到的所有标题元素并构建目录。首先声明本地变量_header,并将当前标题元素存储在此变量中。

为了能够缩进目录中的子节,使用户更容易看到内容结构,代码需要确定当前标题的级别:h1为顶级,h5为底级。使用_header.context.localName,我们可以获取标题元素的标签(例如,h1)并使用 JavaScript 的replace()删除"h"。然后,我们可以使用parseInt()将剩余值转换为整数。我们得到一个值,可以用来确定标题元素的级别。这个过程在以下代码片段中显示:

$(function(){
    var _contents = $('.content-frame .left');
    var _headers = _contents.find("h1, h2, h3, h4");
    _headers.each(function(index, value){
        var _header = $(value);
        var level = parseInt(_header.context.localName.replace("h", ""));
        // --- HIDDEN CODE
    });
});

现在我们可以创建列表元素,并将其插入有序列表中。为了将目录中的项目链接到内容的适当部分,我们需要检查标题元素是否有我们可以链接到的 ID。如果有,我们通过执行以下代码创建带有链接的列表元素;否则,我们通过执行以下代码创建基本列表元素:

$(function(){
    var _contents = $('.content-frame .left');
    var _headers = _contents.find("h1, h2, h3, h4");
    _headers.each(function(index, value){
        var _header = $(value);
        var level = parseInt(_header.context.localName.replace("h", ""));
        if (typeof _header.attr("id") != "undefined") {
            var listItem = $("<li><a href='#" + _header.attr("id") + "'>" + _header.html() + "</a></li>");
        } else {
            var listItem = $("<li>" + _header.html() + "</li>");
        }
        listItem.css("padding-left", (level * 5));
        $('.contents').append($(listItem));
    });
});

最后,创建完列表项后,使用css()函数和level变量添加所需的缩进填充,并将创建的列表项附加到内容的有序列表中。

还有更多...

您可以将此配方与实现平滑滚动创建粘性元素配方结合使用,迫使目录随用户向下滚动页面并为更好的用户体验提供滚动动画。

参见

  • 创建粘性元素

  • 实现平滑滚动

创建基本的拖放功能

通过向网站添加拖放元素,可以创建有趣且直观的界面。jQuery UI 带有内置插件,用于拖放界面。本产品介绍将向您展示如何创建基本的拖放功能,而无需使用任何插件,从而为您扩展代码提供自由和理解。

准备工作

创建一个名为recipe-6.html的空白 HTML 页面,并将recipe-6.cssrecipe-6.js文件放在与最新版本 jQuery 库相同的目录中。

如何做…

按照以下分步说明执行以下操作完成此步骤:

  1. 将以下 HTML 代码添加到recipe-6.html中,在容器div中创建一个基本的 HTML 页面,其中包含三个draggable元素:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 6 :: Recipe 6</title>
        <link href="recipe-6.css" rel="stylesheet" type="text/css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/recipe-6.js"></script>
    </head>
    <body>
        <div class="container">
            <div class="draggable"></div>
            <div class="draggable"></div>
            <div class="draggable"></div>
        </div>
    </body>
    </html>
    
  2. 将以下 CSS 代码添加到recipe-6.css中,为 HTML 页面和draggable元素添加样式:

    .container {
        width: 800px;
        height: 500px;
        border: solid 2px #333333;
        margin: 20px auto auto auto;
    }
    .draggable {
        width: 120px;
        height: 120px;
        margin: 10px;
        background-color: darkred;
           cursor: pointer;
    }
    .draggable.dragging {
        box-shadow: 5px 5px 5px #CCC;
    }
    
  3. 将以下 jQuery 代码插入recipe-6.js中,为draggable元素应用拖放功能:

    $(function(){
        $('.draggable').on("mousedown", function(){
           $(this).addClass('dragging');
        }).on("mousemove mouseout", function(event){
                if ($(this).hasClass("dragging")) {
                    //Get the parents position
                    var parentPosition = $(this).parent().offset();
    
                    //Don't allow the draggable element to go over the parent's left and right
                    var left = (event.pageX - ($(this).width() / 2));
                    var parentRight = parentPosition.left + $(this).parent().width();
                   if (left > (parentRight - $(this).width())){
                        left = (parentRight - $(this).width());
                    } else if(left <= parentPosition.left) {
                        left = parentPosition.left;
                    }
    
                    //Don't allow the draggable element to go over the parent's top and bottom
                    var top = (event.pageY - ($(this).height() / 2));
                    var parentBottom = parentPosition.top + $(this).parent().height();
                    if (top > (parentBottom - $(this).height())) {
                        top = (parentBottom - $(this).height());
                    } else if (top <= parentPosition.top) {
                        top = parentPosition.top;
                    }
    
                    //Set new position
                    $(this).css({
                        top: top + "px",
                        left: left + "px",
                        position: "absolute"
                    });
                }
        }).on("mouseup", function(){
            $(this).removeClass('dragging');
        });
    });
    
  4. 在 Web 浏览器中打开recipe-6.html并单击其中一个红色框。这将向元素应用dragging CSS 类,允许您在页面内的框划分中移动它。

运作原理…

HTML 页面提供一个充当draggable元素容器的div元素。frame元素内有三个额外的div元素。这三个元素具有draggable类,jQuery 将使用这个类应用拖放功能。

配方中使用的 CSS 代码在frame元素上创建边框,并为draggable元素设置高度、宽度和背景颜色。还有一个dragging类,当移动draggable元素时,会为其应用阴影。

在 jQuery 代码本身中,使用一系列鼠标事件来创建拖放功能。使用 jQuery 的on()函数将不同的事件处理程序应用于draggable元素。应用在draggable元素上的第一个事件处理程序是mousedown事件,如下所示:

$('.draggable').on("mousedown", function(){
       $(this).addClass('dragging');
})

这只是向刚刚被点击的元素(mousedown)添加dragging类。

接下来要绑定的事件处理程序是mousemovemouseout事件。这允许我们根据用户在点击选定元素的同时移动鼠标指针时,根据鼠标位置更新点击元素的位置。我们还针对用户移动太快并将鼠标指针移出选定的draggable框时使用相同的代码来处理mouseout事件。由于相同的代码附加到mouseout事件上,框的位置将被更新为鼠标的位置。

.on("mousemove mouseout", function(event){
            if ($(this).hasClass("dragging")) {
                //Get the parents position
                var parentPosition = $(this).parent().offset();

                //Don't allow the draggable element to over the parent's left and right
                var left = (event.pageX - ($(this).width() / 2));
                var parentRight = parentPosition.left + $(this).parent().width();
                if (left > (parentRight - $(this).width())) {
                    left = (parentRight - $(this).width());
                } else if(left <= parentPosition.left) {
                    left = parentPosition.left;
                }

                //Don't allow the draggable element to go over the parent's top and bottom
                var top = (event.pageY - ($(this).height() / 2));
                var parentBottom = parentPosition.top + $(this).parent().height();
                if (top > (parentBottom - $(this).height())) {
                    top = (parentBottom - $(this).height());
                } else if (top <= parentPosition.top) {
                    top = parentPosition.top;
                }

                //Set new position
                $(this).css({
                    top: top + "px",
                    left: left + "px",
                    position: "absolute"
                });
            }
    })

这两个事件的回调函数是添加主要功能的地方。这段代码看起来很复杂,但一旦我们将它分解开来,就很容易理解。首要的是,除非点击的元素有dragging类,否则什么也不会发生。这是通过以下if语句来实现的,它检查dragging类:

if ($(this).hasClass("dragging")) {
   //MAIN FUNCTIONALITY HERE
}

在这个if语句内,首先获取了点击元素的父元素位置(frame元素),这样我们就可以计算出draggable元素的边界:

var parentPosition = $(this).parent().offset();

下一块代码查看了点击元素的位置,并确定了它是否小于frame元素的左侧位置或大于容器元素的右侧位置。如果是其中一个,dragging元素的位置被设置为边界限制,而不是鼠标指针的位置,从而阻止用户能够将元素拖到容器元素的左右边界之外:

//Don't allow the draggable element to over the parent's left and right
var left = (event.pageX - ($(this).width() / 2));
var parentRight = parentPosition.left + $(this).parent().width();
if (left > (parentRight - $(this).width())) {
left = (parentRight - $(this).width());
} else if(left <= parentPosition.left) {
left = parentPosition.left;
}

如果draggable元素的位置不在边界上方,那么它的位置将被更新为鼠标指针的左侧位置减去dragging元素的宽度,以便在拖动时鼠标指针始终在元素的中心。

接下来,相同的逻辑应用于顶部和底部的边界:

//Don't allow the draggable element to go over the parent's top and bottom
var top = (event.pageY - ($(this).height() / 2));
var parentBottom = parentPosition.top + $(this).parent().height();
if (top > (parentBottom - $(this).height())) {
    top = (parentBottom - $(this).height());
} else if (top <= parentPosition.top) {
    top = parentPosition.top;
}

最后,现在draggable元素的新顶部和左侧位置已经计算出来,知道它是鼠标指针的位置减去draggable元素的宽度/高度除以二或边界限制,就可以使用 jQuery CSS 函数应用这些位置,并同时将 CSSposition属性设置为absolute

//Set new position
$(this).css({
top: top + "px",
left: left + "px",
position: "absolute"
});

最后,使用了最后一个事件——mouseup事件——当用户释放鼠标指针时触发,这时将从dragging元素中移除dragging CSS 类:

.on("mouseup", function(){
        $(this).removeClass('dragging');
});

另请参见

  • 创建一个可拖动的内容弹出窗口

创建一个动态的动画树状菜单

树状菜单是在有限的空间内显示大量信息并允许用户选择他们希望看到的信息的好方法。这个配方将向你展示如何基于一组 JSON 对象动态创建具有上下滑动效果的树状菜单。

准备工作

为了这个配方创建recipe-7.htmlrecipe-7.jsrecipe-7.css,并确保它们保存在与 jQuery 的最新版本相同的目录中。

如何操作…

为了创建一个动态的动画树状菜单,请确保您完成以下所有指示:

  1. recipe-7.html中添加以下 HTML 代码,以创建此配方所需的基本网页:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 6 :: Recipe 7</title>
        <link href="recipe-7.css" rel="stylesheet" type="text/css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/recipe-7.js"></script>
    </head>
    <body>
    <div class="container">
        <div class="list-container"></div>
    </div>
    </body>
    </html>
    
  2. recipe-7.css中添加以下样式:

    .list-container {
        width: 800px;
        margin: 20px auto auto auto;
    }
    ul {
        margin: 0;
        padding: 0;
        list-style: none;
    }
    ul li {
        line-height: 25px;
        margin: 5px 0 5px 0;
        position: relative;
        padding: 0 0 0 5px;
        color: #666;
    }
    ul li a {
        display: block;
        background-color: #333;
        padding: 0 0 0 30px;
        margin-left: -5px;
        text-decoration: none;
        color: #FFF;
    }
    .arrow {
        position: absolute;
        width: 20px;
        height: 20px;
        left: 5px;
        top: 2px;
    }
    .right-arrow {
        width: 0;
        height: 0;
        border-top: 10px solid transparent;
        border-bottom: 10px solid transparent;
        border-left: 10px solid white;
    }
    .down-arrow {
        width: 0;
        border-left: 10px solid transparent;
        border-right: 10px solid transparent;
        border-top: 10px solid white;
        top: 7px;
    }
    .list-bg {
        background-color: #F1F1F1;
    }
    
  3. recipe-7.js中添加以下 jQuery 代码,该代码提供了创建动态树菜单的数据和功能:

    var tree = [
        {
            name: "Fastolph Bolger",
            children: []
        },
        {
            name: "Laura Grubb",
            children: [
                {
                    name: "Bungo",
                    children: [
                        {
                            name: "Bilbo",
                            children: []
                        }
                    ]
                },
                {
                    name: "Belba",
                    children: []
                },
                {
                    name: "Longo",
                    children: [
                        {
                            name: "Otho Sackville-Baggins",
                            children: [
                                {
                                    name: "Lotho",
                                    children: []
                                }
                            ]
                        }
                    ]
                }
            ]
        },
        {
            name: "Ponto",
            children: [
                {
                    name: "Rosa",
                    children: [
                        {
                            name: "Peregrin Took",
                            children: []
                        }
                    ]
                }
            ]
        }
    ];
    $(function(){
        var list = createList(tree, 1);
        $('.list-container').html(list);
        $(document).on('click', '.show-children', function(){
            $(this).next('ul').slideToggle();
            $(this).find('.right-arrow').toggleClass('down-arrow');
        });
    });
    
    function createList(children, level) {
        var style = "margin-left: " + (10 * level) + "px;"
        if (level > 1) {
            style += "display: none;";
        }
        var list = "<ul style='" + style + "'>";
        level++;
        for (var i = 0; i < children.length; i++) {
            if (children[i].children.length > 0) {
                list += "<li><a href='javascript:void(0)' class='show-children'><div class='arrow right-arrow'></div> " + children[i].name + "</a>";
                list += createList(children[i].children, level);
                list += "</li>";
            } else {
                list += "<li class='list-bg'>" + children[i].name + "</li>";
            }
        }
        list += "</ul>";
        return list;
    }
    
  4. 在 web 浏览器中打开recipe-7.html并单击突出显示的列表项,以展开具有子项的列表,如下图所示:如何操作…

如何运作…

HTML 代码仅包含有效 HTML 页面和list-container分区元素的基本元素,jQuery 代码将使用该元素在创建后将列表 HTML 插入其中。CSS 代码包含基本列表样式以及一些样式以创建右箭头和向下箭头,如上一个屏幕截图所示。

JavaScript 代码的第一部分是一个对象数组,代表了一个家族谱系。家族谱中的每个人都可以有子女,并且树的深度没有限制。

jQuery 代码的主要功能在createList()函数中。此函数接受两个参数:对象数组(子女)和当前列表级别。在此函数内,根据level的值计算了一些内联样式。如果当前的level值不是1,这意味着当前级别不是最顶层级别,则列表默认隐藏。还根据级别应用左边距,以便每个较低级别时,列表都会向右移动,以创建您在应用程序中看到的典型树视图。创建一个list变量,并将无序列表元素的 HTML 添加到其中。接下来,循环遍历提供的每个对象,并为每个对象创建一个列表项。检查对象的children属性的长度以确定当前对象是否具有子女。如果有子女,则将链接和右箭头添加到列表中。然后,递归调用createList()函数,传入更新后的级别和当前对象自己的子女。此函数将返回一个填充有对象自己的子女的无序列表的 HTML。这将在树变量中的每个对象中发生,直到完全创建列表。然后,使用$('.list-container').html(list);将列表插入到 DOM 中,并将在页面上可见。

因为除了顶级项目之外的所有项目都是隐藏的,所以需要将click事件处理程序附加到每个具有子女的项目上,如下所示:

$(document).on('click', '.show-children', function(){
        $(this).next('ul').slideToggle();
        $(this).find('.right-arrow').toggleClass('down-arrow');
});

一个单独的事件将监听任何具有show-children类的元素上的点击,并附加到文档上。当这些项目中的一个被点击时,slideToggle()函数将用于下一个无序列表元素(子女列表)以将其上下滑动。当子女列表打开时,toggleClass()函数也会用于arrow元素以使箭头向下指。

还有更多...

此示例使用静态 JavaScript 数组,但可以轻松地改为从 Web 服务器加载一组 JSON 对象。

另请参阅

  • 创建手风琴内容滑块

  • 创建选项卡内容

创建一个手风琴内容滑块

折叠内容允许用户轻松地跳过内容。有许多提供折叠功能的 jQuery 插件。但是,本示例将向您展示如何从头开始创建一个简单且吸引人的 jQuery 折叠内容滑块。

准备工作

在与 jQuery 库相同的目录中创建recipe-8.htmlrecipe-8.cssrecipe-8.js

如何做……

使用您新创建的文件,按照以下逐步说明完成操作:

  1. 将以下 HTML 代码添加到recipe-8.html中,以创建一个包含折叠和内容的基本网页:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 6 :: Recipe 8</title>
        <link href="recipe-8.css" rel="stylesheet" type="text/css" />
        <script src="img/jquery.min.js"script>
        <script src="img/recipe-8.js"></script>
    </head>
    <body>
    <div class="container">
        <div class="accordion">
            <section>
                <a href="#" class="header"><div class='arrow right-arrow down-arrow'></div> Section 1</a>
                <div class="content">
                    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                </div>
            </section>
            <section>
                <a href="#" class="header"><div class='arrow right-arrow'></div> Section 2</a>
                <div class="content">
                    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                </div>
            </section>
            <section>
                <a href="#" class="header"><div class='arrow right-arrow'></div> Section 3</a>
                <div class="content">
                    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                </div>
            </section>
        </div>
    </div>
    </body>
    </html>
    
  2. 将以下 CSS 代码添加到recipe-8.css中,以为折叠添加样式:

    .container {
        width: 800px;
        margin: 20px auto auto auto;
    }
    .accordion section a.header {
        display: block;
        line-height: 30px;
        /* fallback */
        background-color: #333333;
        background-repeat: repeat-x;
        /* Safari 4-5, Chrome 1-9 */
        background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#666666), to(#333333));
        /* Safari 5.1, Chrome 10+ */
        background: -webkit-linear-gradient(top, #666666, #333333);
        /* Firefox 3.6+ */
        background: -moz-linear-gradient(top, #666666, #333333);
        /* IE 10 */
        background: -ms-linear-gradient(top, #666666, #333333);
        /* Opera 11.10+ */
        background: -o-linear-gradient(top, #666666, #333333);
        padding: 0 10px 0 30px;
        position: relative;
        text-decoration: none;
        color: #FFFFFF;
        border-radius: 5px;
    }
    .accordion section .content {
        padding: 10px;
        margin: 0 3px 0 3px;
        background-color: #F1F1F1;
        color: #333333;
    }
    
    .accordion section .content p {
        margin-top: 0;
    }
    
    .arrow {
        position: absolute;
        width: 20px;
        height: 20px;
        left: 10px;
        top: 5px;
    }
    .right-arrow {
        width: 0;
        height: 0;
        border-top: 10px solid transparent;
        border-bottom: 10px solid transparent;
        border-left: 10px solid white;
    }
    .down-arrow {
        width: 0;
        border-left: 10px solid transparent;
        border-right: 10px solid transparent;
        border-top: 10px solid white;
        top: 10px;
        left: 6px;
    }
    
  3. 将以下 jQuery 代码添加到recipe-8.js中,以启动折叠内容滑块的操作:

    $(function(){
        //Hide all accordion content except the first one
        $('.accordion section:not(:first-child) .content').hide();
        $(document).on("click", ".accordion a.header", function(){
            var _contents = $('.accordion section .content');
            var _currentContent = $(this).parent().find('.content');
            for (var i = 0; i < _contents.length; i++) {
                var content = $(_contents[i]);
                //Only slide the element up if its not the currently selected element
                if (content[0] != _currentContent[0]) {
                    content.slideUp();
                    content.parent().find('.right-arrow').removeClass('down-arrow');
                }
            }
            _currentContent.slideDown();
            _currentContent.parent().find('.right-arrow').addClass('down-arrow');
        });
    });
    
  4. 在网络浏览器中打开recipe-8.html,您将看到以下截图中显示的交互式折叠内容滑块:

它是如何工作的……

此示例中使用的 HTML 代码创建了一个包含主要折叠标记的基本网页。有一个包含多个部分的主折叠部分元素。每个部分都包含一个带有类header的锚标签和一个包含折叠内容的内容部分元素。jQuery 代码使用头部锚元素根据用户点击的锚元素来隐藏和显示内容部分。

CSS 代码非常简单,为折叠添加了基本样式。与前一个示例一样,我们使用 CSS 中的右箭头和下箭头来指示某个部分是否打开或关闭。我们还使用 CSS3 渐变将渐变背景添加到折叠标题中。

由于 jQuery 的性质,我们能够仅使用 18 行 JavaScript 创建整个折叠。 jQuery 代码的第一部分隐藏了除第一个以外的所有折叠内容部分:

$('.accordion .section:not(:first-child) .content').hide();

然后,将一个click事件处理程序附加到文档上,以监听折叠内容标题的点击,如下面的代码片段所示:

$(document).on("click", ".accordion a.header", function(){
});

在此事件的回调函数内部,我们选择所有折叠内容部分,并获取属于当前点击的标题元素的部分:

var _contents = $('.accordion .section .content');
var _currentContent = $(this).parent().find('.content');

选定折叠部分时,我们只想显示其中一个。为此,循环遍历以下代码中的所有内容部分以隐藏它们,除了所选部分:

for (var i = 0; i < _contents.length; i++) {
var content = $(_contents[i]);
//Only slide the element up if it's not the currently selected element
if (content[0] != _currentContent[0]) {
     content.slideUp();
     content.parent().find('.right-arrow').removeClass('down-arrow');
}
}

使用 jQuery 的slideUp()函数,我们可以隐藏带有滑动效果的元素。标题中的箭头也更改为右箭头,表示内容尚未展开。

最后,扩展所选的内容部分,并添加向下箭头以指示内容已展开,如下代码所示:

_currentContent.slideDown();
_currentContent.parent().find('.right-arrow').addClass('down-arrow');

另请参阅

  • 创建动态动画树菜单

  • 创建选项卡内容

创建选项卡内容

类似于手风琴,选项卡式内容是在单个页面上显示大量信息的另一种好方法,允许用户跳转到对他们重要的部分。与前一示例类似,有许多提供此功能的 jQuery 插件。本示例将向您展示如何从头开始创建此功能,使您更深入地了解这些类型的用户界面的内部工作原理。

准备工作

在与 jQuery 库相同的目录中创建用于示例的常规文件,recipe-9.htmlrecipe-9.cssrecipe-9.js

如何做…

按照以下逐步说明完成所有步骤:

  1. 使用以下 HTML 代码在recipe-9.html中创建一个基本的网页:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 6 :: Recipe 9</title>
        <link href="recipe-9.css" rel="stylesheet" type="text/css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/recipe-9.js"></script>
    </head>
    <body>
    </body>
    </html>
    
  2. 在您刚创建的 HTML 页面的body标签中,添加以下 HTML 代码以创建选项卡式内容:

    <div class="container">
        <div class="tabs">
            <ul class="tab-nav">
                <li><a href="#section1" class="active">Section 1</a></li><li><a href="#section2">Section 2</a></li><li><a href="#section3">Section 3</a></li>
            </ul>
            <div class="tab-content">
                <div class="section" id="section1">
                    <p><strong>Section 1 content...</strong></p>
                    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                </div>
                <div class="section" id="section2">
                    <p><strong>Section 2 content...</strong></p>
                    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                </div>
                <div class="section" id="section3">
                    <p><strong>Section 3 content...</strong></p>
                    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                </div>
            </div>
        </div>
    </div>
    
  3. 打开recipe-9.css,添加以下 CSS 代码以样式化选项卡式内容,并在页面加载时显示第一组内容:

    .container {
        width: 800px;
        margin: 20px auto auto auto;
    }
    .tabs .tab-nav {
        margin: 0;
        padding: 0;
        list-style: none;
        background-color: #E1E1E1;
        border-top-right-radius: 5px;
        border-top-left-radius: 5px;
    }
    .tabs .tab-nav li {
        display: inline-block;
    }
    .tabs .tab-nav li a {
        display: block;
        text-decoration: none;
        text-align: center;
        line-height: 50px;
        color: #FFF;
        background-color: #333;
        padding: 0 20px 0 20px;
        border-right: solid 1px #5c5c5c;
    }
    .tabs .tab-nav li a:hover, .tabs .tab-nav li a.active {
        background-color: #5c5c5c;
    }
    .tabs .tab-nav li:first-child a {
        border-top-left-radius: 5px;
    }
    .tabs .tab-nav li:last-child a {
        border-top-right-radius: 5px;
        border-right: none;
    }
    .tabs .section {
        padding: 10px;
        background-color: #F1F1F1;
        border-bottom-right-radius: 5px;
        border-bottom-left-radius: 5px;
    }
    .tabs .section p {
        margin-top: 0;
    }
    
    .tabs .section:not(:first-child) {
        display: none;
    }
    
  4. recipe-9.js中插入以下 jQuery 代码:

    $(function(){
        $(document).on("click", ".tabs .tab-nav a", function(){
            var contentId = this.hash;
            $('.tab-nav a').removeClass("active");
            $(this).addClass("active");
            $('.tab-content .section').hide();
            $(contentId).fadeIn();
        });
    });
    
  5. 在 Web 浏览器中打开recipe-9.html,单击部分选项卡以在内容部分之间切换。

工作原理…

这是一个快速简单的示例,但却具有强大的结果。此示例中的 HTML 代码创建了包含导航和内容的选项卡部分。每个内容分区元素都有一个与导航中的链接相对应的 ID。例如,要链接到section1内容,需要在导航中有一个相应的链接链接到#content1,如下所示:<a href='#content1'>标题在此</a>。这使得 jQuery 知道在点击选项卡时要显示哪个内容部分。

此示例中的 CSS 非常简单,无需进一步解释。

仅用了九行 JavaScript,这是一个非常简单的示例。jQuery 代码将点击事件处理程序附加到文档主体,监听对选项卡导航的点击。当点击其中一个选项卡时,将从锚哈希中收集内容部分 ID,如下所示:

$(document).on("click", ".tabs .tab-nav a", function(){
        var contentId = this.hash;
});

接下来,从所有选项卡导航项中删除活动类,并将其添加到点击的项目中。此类用于通过 CSS 更改背景颜色来显示当前活动的选项卡,如下所示:

$('.tab-nav a').removeClass("active");
$(this).addClass("active");

最后,隐藏所有内容部分,然后使用最近获取的选定选项卡的内容 ID,使用fadeIn()函数使所选内容可见,当内容出现时应用动画:

$('.tab-content .section').hide();
$(contentId).fadeIn();

还有更多…

此示例使用了 jQuery 提供的淡入动画来显示所选内容。通过回顾第四章中的内容,使用 jQuery 效果添加吸引人的视觉效果,你可以使用该章节中描述的任何效果和动画来显示和隐藏此示例中的内容。

创建一个模态弹出框

模态是网页内的一个弹出窗口,覆盖在所有其他内容之上,引起读者的注意。模态通常是基于用户交互而打开的,例如点击按钮。本示例将展示如何创建一个简单的模态,该模态在按下按钮时打开,并可以在模态内部关闭。

准备工作

再次,在开始此示例之前,创建 recipe-10.htmlrecipe-10.cssrecipe-10.js,确保最新版本的 jQuery 可用于与这些文件相同的目录中。

如何实现…

执行以下步骤创建模态弹出框:

  1. 将以下 HTML 添加到 recipe-10.html 中,以创建一个基本的网页和构建模态弹出框的代码:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 6 :: Recipe 10</title>
        <link href="recipe-10.css" rel="stylesheet" type="text/css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/recipe-10.js"></script>
    </head>
    <body>
        <button class="openModal">Open Modal</button>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        <div class="modal">
            <div class="modal-header">
                <h3>Modal Header Text <a class="close-modal" href="#">&times;</a></h3>
            </div>
            <div class="modal-body">
                <p>This is some modal content text.</p>
            </div>
            <div class="modal-footer">
                <button class="modalOK close-modal">OK</button>
            </div>
        </div>
        <div class="modal-backdrop"></div>
    </body>
    </html>
    
  2. 将以下 CSS 代码添加到 recipe-10.css 中,以样式化模态框并允许其覆盖页面上的所有其他内容:

    .modal-backdrop {
        background-color: rgba(0, 0, 0, 0.61);
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        display: none;
    }
    .modal {
        width: 500px;
        position: absolute;
        top: 25%;
        z-index: 1020;
        background-color: #FFF;
        border-radius: 6px;
        display: none;
    }
    .modal-header {
        background-color: #333;
        color: #FFF;
        border-top-right-radius: 5px;
        border-top-left-radius: 5px;
    }
    .modal-header h3 {
        margin: 0;
        padding: 0 10px 0 10px;
        line-height: 40px;
    }
    .modal-header h3 .close-modal {
        float: right;
        text-decoration: none;
        color: #FFF;
    }
    .modal-footer {
        background-color: #F1F1F1;
        padding: 0 10px 0 10px;
        line-height: 40px;
        text-align: right;
        border-bottom-right-radius: 5px;
        border-bottom-left-radius: 5px;
        border-top: solid 1px #CCC;
    }
    .modal-body {
        padding: 0 10px 0 10px;
    }
    
  3. 将以下 jQuery 代码添加到 recipe-10.js 中,以打开模态、将其居中并允许用户关闭它:

    $(function(){
        modalPosition();
        $(window).resize(function(){
            modalPosition();
        });
        $('.openModal').click(function(){
            $('.modal, .modal-backdrop').fadeIn('fast');
        });
        $('.close-modal').click(function(){
            $('.modal, .modal-backdrop').fadeOut('fast');
        });
    });
    function modalPosition() {
        var width = $('.modal').width();
        var pageWidth = $(window).width();
        var x = (pageWidth / 2) - (width / 2);
        $('.modal').css({left: x + "px"});
    }
    
  4. 在 Web 浏览器中打开 recipe-10.html,然后点击 打开模态框 按钮。你将会看到如下截图中显示的模态弹出框:如何实现…

如何运作…

HTML 创建了基本的网页和创建模态的代码。模态本身包含一个主模态容器、一个标题、一个主体和一个页脚。页脚包含操作,本例中是 确定 按钮,标题包含标题和关闭按钮,主体包含模态内容。

CSS 应用了绝对定位样式到模态,使其可以自由移动到页面上而不受其他内容的干扰。为了创建模态背景,其位置被设置为 absolute,其左、右、上和下位置被设置为 0,使其可以扩展并覆盖整个页面。模态和其背景元素上设置了 z-index 值,确保它们始终位于其他内容之上,并且模态位于背景之上。

jQuery 代码将点击事件处理程序应用于模态打开按钮和任何具有 close-modal 类的元素。使用 jQuery 提供的 fadeIn()fadeOut() 函数来显示模态。对这两个函数都传递了 fast 参数,以加快动画速度。

此外,jQuery 代码用于计算模态的左侧位置,使其始终位于屏幕中心。当页面加载时和当浏览器窗口大小调整时,调用 modalPosition() 函数如下:

$(function(){
   modalPosition();
   $(window).resize(function(){
    modalPosition();
});
});

这样可以确保无论用户如何改变窗口的宽度,模态都将保持在浏览器窗口的中心。

modalPosition() 函数使用模态的宽度和浏览器窗口的宽度来计算模态的左侧位置。然后,该函数使用 jQuery 的 css() 函数将此值设置为模态的位置。

更多内容…

Twitter Bootstrap 是一个非常受欢迎的 HTML 框架,它带有一个非常出色的模态框实现,可以立即使用。现在你已经了解了模态框的工作原理,你可以受益于 Twitter Bootstrap 提供的完整解决方案。

另请参见

  • 创建一个可拖动的内容弹出框

创建一个可拖动的内容弹出框

可拖动的内容弹出框类似于模态窗口。然而,它可以被用户移动,不会带有背景来引起用户的注意,可以让他们同时查看其他内容。这个教程将适配前一个教程中使用的模态框代码和本章前面看到的 创建基本的拖放功能 教程中的 jQuery 代码。

准备就绪

即使我们将重用之前章节中的代码,也确保你已经创建并准备好recipe-11.htmlrecipe-11.cssrecipe-11.js

如何做…

执行以下步骤:

  1. 将以下 HTML 代码添加到recipe-11.html中,以创建一个模态框和一个基本的网页:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 6 :: Recipe 11</title>
        <link href="recipe-11.css" rel="stylesheet" type="text/css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/recipe-11.js"></script>
    </head>
    <body>
    <button class="openModal">Open Modal</button>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
    <div class="modal draggable">
        <div class="modal-header">
            <h3>Modal Header Text <a class="close-modal" href="#">&times;</a></h3>
        </div>
        <div class="modal-body">
            <p>This is some modal content text.</p>
        </div>
        <div class="modal-footer">
            <button class="modalOK close-modal">OK</button>
        </div>
    </div>
    </body>
    </html>
    
  2. 将以下 CSS 代码添加到recipe-11.css中以样式化模态框:

    .modal {
        width: 500px;
        position: absolute;
        top: 25%;
        z-index: 600;
        background-color: #FFF;
        border-radius: 6px;
        display: none;
        box-shadow: 3px 3px 5px #CCC;
    }
    .modal-header {
        background-color: #333;
        color: #FFF;
        border-top-right-radius: 5px;
        border-top-left-radius: 5px;
    }
    .modal-header h3 {
        margin: 0;
        padding: 0 10px 0 10px;
        line-height: 40px;
    }
    .modal-header h3 .close-modal {
        float: right;
        text-decoration: none;
        color: #FFF;
    }
    .modal-footer {
        background-color: #F1F1F1;
        padding: 0 10px 0 10px;
        line-height: 40px;
        text-align: right;
        border-bottom-right-radius: 5px;
        border-bottom-left-radius: 5px;
        border-top: solid 1px #CCC;
    }
    .modal-body {
        padding: 0 10px 0 10px;
    }
    
  3. 将以下 jQuery 代码插入recipe-11.js中,以允许打开、关闭和拖动模态框:

    $(function(){
        modalPosition();
        $('.openModal').click(function(){
            $('.modal, .modal-backdrop').fadeIn('fast');
        });
        $('.close-modal').click(function(){
            $('.modal, .modal-backdrop').fadeOut('fast');
        });
        $('.draggable').on("mousedown", function(){
            $(this).addClass('dragging');
        }).on("mousemove mouseout", function(event){
            if ($(this).hasClass("dragging")) {
                //Don't allow the draggable element to go over the parent's left and right
                var left = (event.pageX - ($(this).width() / 2));
                if (left > ($(window).width() - $(this).width())) {
                    left = ($(window).width() - $(this).width());
                } else if(left <= 0) {
                    left = 0;
                }
                //Don't allow the draggable element to go over the parent's top and bottom
                var top = (event.pageY - ($(this).height() / 2));
                if (top > ($(window).height() - $(this).height())) {
                    top = ($(window).height() - $(this).height());
                } else if (top <= 0) {
                    top = 0;
                }
                //Set new position
                $(this).css({
                    top: top + "px",
                    left: left + "px",
                    position: "absolute"
                });
            }
        }).on("mouseup", function(){
            $(this).removeClass('dragging');
        });
    });
    function modalPosition() {
        var width = $('.modal').width();
        var pageWidth = $(window).width();
        var x = (pageWidth / 2) - (width / 2);
        $('.modal').css({left: x + "px"});
    }
    
  4. 在 Web 浏览器中打开recipe-11.html,并像在前一个教程中一样点击打开模态框按钮。然后你将看到同样的模态弹出框,没有背景,可以清楚地看到页面的其他内容。你还可以通过点击和拖动鼠标指针来在页面上移动模态框。

工作原理...

之前的一些适配过的食谱已经详细解释了模态框和draggable元素的工作原理,因此在本节中不会重复介绍。

与前一个模态框食谱的 HTML 的主要区别是没有模态背景,而模态元素具有额外的draggable类,这是 jQuery 用于对元素应用拖放功能的。

CSS 仍然非常相似,只是背景的代码已被移除,并且使用 CSS box-shadow属性向模态框添加了阴影。

jQuery 使用与前一个模态框教程相同的代码,只是移除了窗口调整大小事件处理程序。这个事件处理程序被移除,因为模态框可以被用户移动,所以没有必要保持模态框处于页面中心。modalPosition()函数只在页面加载时被调用,这样当首次打开模态框时,它就处于页面的中心位置。

从基本的拖放食谱中使用的代码非常相似,唯一的区别是不再使用draggable元素的父元素作为边界,而是使用浏览器窗口。这消除了一些复杂性,因为我们知道窗口的左右位置始终是0

另请参见

  • 创建基本的拖放功能

  • 创建一个模态弹出框

第七章:用户界面动画

在本章中,我们将介绍以下主题:

  • 创建一个动态登录表单

  • 添加照片放大功能

  • 创建一个动态内容滑块

  • 背景图像动画

  • 创建一个动态导航菜单

介绍

使用 jQuery,可以通过引人注目的动画增强常见的用户界面元素。这些动画可以为任何网站或 Web 应用程序提供交互式操作,从而提升用户体验。本章将向您展示如何使用现代动画创建一些流行的用户界面,您可以在新项目或当前网站中使用这些动画。

创建一个动画登录表单

登录表单是许多网站和 Web 应用程序的主要入口点——第一印象至关重要。使用 jQuery 动画,我们可以创建一个在打开、关闭和出现错误时都会进行动画处理的登录表单,从而创造出通过动画加强的高品质用户体验。

此示例需要支持 PHP 的 Web 服务器。这个服务器可以托管在云中或一个简单的本地开发服务器上。在开始本示例之前,请确保您已经完成了这个设置。

准备工作

在与最新版本的 jQuery 库相同的目录中创建 recipe-1.htmlrecipe-1.jsrecipe.css。因为我们正在创建一个登录表单,所以我们还需要一个 PHP 脚本来发布我们的登录数据。在 Web 服务器的 Web 根目录内创建一个名为 index.php 的 PHP 文件,并添加以下代码:

$response = new stdClass;
$response->success = false;
$response->error = "Username and password must be provided";
if (isset($_POST['username']) && isset($_POST['password'])) {
   $username = $_POST['username'];
   $password = $_POST['password'];
   if ($username == "MyUsername" && $password == "MyPassword") {
      $response->success = true;
   } else {
      $response->error = "Incorrect login credentials";
   }
}
header("Content-type: application/json; charset=UTF-8");
echo json_encode($response);

在实际实现中,PHP 脚本将对用户的凭据进行验证,并与数据库记录进行比对。为了保持这个示例简单,并专注于 jQuery 代码,我们的 PHP 代码仅对用户提交的用户名和密码进行字符串比较,分别为 MyUsernameMyPassword

操作步骤…

要创建使用上述 PHP 脚本的动画登录表单,请按照以下逐步说明操作:

  1. 将以下 HTML 代码添加到 recipe-1.html 中,创建登录表单和打开它的按钮:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Chapter 7 :: Recipe 1</title>
       <link href="recipe-1.css" rel="stylesheet" type="text/css" />
       <script src="img/jquery.min.js"></script>
       <script src="img/recipe-1.js"></script>
    </head>
    <body>
       <button class="open-login">Open Login Box</button>
       <div class="login-frame">
          <div class="login-box">
             <div class="login-msg">Please login below</div>
             <div class="form-group">
                <label class="form-label">Username:</label>
                <input type="text" class="form-control" id="username" />
             </div>
             <div class="form-group">
                <label class="form-label">Password:</label>
                <input type="text" class="form-control" id="password" />
             </div>
             <div class="login-actions">
                <button class="btn login-btn">Login</button>
                <button class="btn close-login">Cancel</button>
             </div>
          </div>
       </div>
    </body>
    </html>
    
  2. 将以下 CSS 代码添加到 recipe-1.css 中,为网页添加基本样式:

    .login-frame {
       position: absolute;
       top: 0;
       bottom: 0;
       left: 0;
       right: 0;
       display: none;
    }
    .login-box {
       width: 400px;
       height: 165px;
       padding: 20px;
       margin: auto;
       top: -165px;
       box-shadow: 0 0 10px #CCC;
       border-radius: 5px;
       position: relative;
    }
    .form-group {
       margin-bottom: 10px;
    }
    .form-group .form-control {
       margin-left: 55px;
       width: 275px;
       height: 30px;
       padding: 0 5px 0 5px;
       font-size: 16px;
       border-radius: 5px;
       border: solid 1px #CCCCCC;
       color: #999;
    }
    .form-group .form-label {
       width: 50px;
       font-size: 18px;
       display: block;
       float: left;
       line-height: 30px;
       padding-left: 5px;
       color: #333;
    }
    .login-msg {
       border: solid 1px #bce8f1;
       text-align: center;
       line-height: 30px;
       margin-bottom: 10px;
       border-radius: 5px;
       color: rgba(58, 135, 173, 0.90);
       background-color: rgba(217, 237, 247, 0.99);
    }
    .login-msg.success {
       color: rgba(70, 136, 71, 0.96);
       background-color: rgba(223, 240, 216, 0.97);
       border-color: rgba(214, 233, 198, 0.98);
    }
    .login-msg.error {
       color: rgba(185, 74, 72, 0.98);
       background-color: rgba(242, 222, 222, 0.98);
       border-color: rgba(238, 211, 215, 0.98);
    }
    .login-actions {
       text-align: right;
    }
    .btn {
       height: 40px;
       width: 100px;
       display: inline-block;
       padding: 6px 12px;
       margin-bottom: 0;
       font-size: 14px;
       text-align: center;
       white-space: nowrap;
       vertical-align: middle;
       cursor: pointer;
       border: 1px solid transparent;
       border-radius: 4px;
    }
    
    .login-btn {
       color: #ffffff;
       background-color: #5cb85c;
       border-color: #4cae4c;
    }
    .login-btn:hover {
       background-color: #458a45;
    }
    .close-login {
       color: #ffffff;
       background-color: #d2322d;
       border-color: #ac2925;
    }
    .close-login:hover {
       background-color: #ac2c2c;
    }
    
  3. 将以下 jQuery 代码添加到 recipe-1.js 中,以允许用户打开和使用登录表单:

    $(function(){
       $(document).on('click', '.open-login', function(){
          $('.login-frame').fadeIn(500);
          $('.login-box').animate({'top' : '50px'}, 500);
       });
       $(document).on('click', '.close-login', function(){
          $('.login-box').animate({'top' : '-165px'}, 500);
          $('.login-frame').fadeOut(500);
       });
       $(document).on('click', '.login-btn', function(){
          var username = $('#username').val();
          var password = $('#password').val();
          $.ajax({
             url: '/index.php',
             type: 'POST',
             data: {
                'username': username,
                'password': password
             },
             success: function(response) {
                var _loginMsg = $('.login-msg');
                if (response.success) {
                   _loginMsg.addClass("success").removeClass("error");
                   _loginMsg.html("Login was successful!");
                } else {
                   _loginMsg.addClass("error").removeClass("success");
                   _loginMsg.html(response.error);
                   $('.login-box')
                   .animate({ left: -25 }, 20)
                   .animate({ left: 0 }, 60)
                   .animate({ left: 25 }, 20)
                   .animate({ left: 0 }, 60);
                }
             }
          });
       });
    });
    
  4. 在 Web 浏览器中打开 recipe-1.html,单击 打开登录框 按钮,您将看到以下截图中显示的界面:操作步骤

工作原理…

允许用户拥有帐户并登录到这些帐户的网站通常会在主导航的某个地方提供一个登录按钮。本教程中的 HTML 代码创建了一个非常基本的网页,只有一个按钮来表示用户可以访问登录表单的位置。HTML 代码还提供了基本的登录表单,默认情况下使用 CSS 隐藏。CSS 代码提供了登录表单的定位以及登录错误和表单按钮的样式。除了最初隐藏登录表单的 CSS 之外,它还将登录表单的顶部位置的值设置为负数,将登录表单强制移出页面。这样我们就可以创建滑入动画,将登录框带入用户的视野。

jQuery 代码的第一部分创建了一个点击事件处理程序,用于监听登录按钮的点击,如下所示:

$(document).on('click', '.open-login', function(){
   $('.login-frame').fadeIn(500);
   $('.login-box').animate({'top' : '50px'}, 500);
});

当用户点击具有open-login类的按钮时,使用 jQuery 的fadeIn()函数来淡入隐藏的登录表单,使用animate()函数将登录表单移动到屏幕上,创建滑入效果。

创建了一个点击事件处理程序,用于监听点击close-login按钮的事件,然后触发反向动画,淡出登录框并将其移出屏幕,如下所示:

$(document).on('click', '.close-login', function(){
   $('.login-box').animate({'top' : '-165px'}, 500);
   $('.login-frame').fadeOut(500);
});

注意

两个动画函数的持续时间都设置为 500 毫秒,允许淡入和位置动画同时开始和结束。

本教程的主要功能放在登录按钮的点击事件处理程序的回调函数中;如下所示:

$(document).on('click', '.login-btn', function(){
   // -- HIDDEN CODE --
});

这个点击事件处理程序监听登录按钮的点击,获取输入数据并将其提交给我们在本教程开始时创建的 PHP 脚本。首先,从表单中收集用户名和密码,并存储在usernamepassword变量中,如下所示:

var username = $('#username').val();
var password = $('#password').val();

这些数据然后通过 jQuery 的内置 AJAX 功能发送到 PHP 脚本:

$.ajax({
   url: 'http://localhost:8003/index.php',
   type: 'POST',
   data: {
      'username': username,
      'password': password
   },
   success: function(response) {
   // --- HIDDEN CODE
   }
});

上面的代码通过指定 PHP 文件的 URL 并将type参数设置为POST来创建一个 AJAX POST请求。还提供了一个数据对象,其中包含来自表单的信息。

success参数指定了一个回调函数;这个函数在 PHP 脚本成功响应时被调用,如下所示:

success: function(response) {
   var _loginMsg = $('.login-msg');
   if (response.success) {
      // -- HIDDEN CODE
   } else {                         
      // -- HIDDEN CODE
   }

通过创建我们的 PHP 代码,我们知道响应将包含一个成功值,要么是true要么是false。如果成功值是false,则会有一个错误消息与之相配。还有一种 AJAX 请求可能会失败;这是由服务器错误引起的,例如500 文件未找到。为了处理这些错误,应该使用 jQuery AJAX .fail()函数。更多信息请参阅api.jquery.com/jquery.ajax/

在成功的回调函数中,我们选择login-msg元素,该元素将用于在屏幕上打印任何消息。评估由 PHP 脚本提供的成功值以确定登录是否成功。

如果登录成功,login-msg元素将被更新,其中包含通知用户登录成功的消息,并添加success类以使消息元素呈绿色,如下所示:

_loginMsg.addClass("success").removeClass("error");
_loginMsg.html("Login was successful!");

removeClass()函数用于确保error类不作为任何先前登录尝试的遗留物存在。在实际情况下,您可能希望将用户重定向到网站的会员区域。这段代码可以被替换为执行此操作;请参阅本配方的还有更多...部分。

如果登录尝试失败,则向login-msg元素添加了error类,并附有 PHP 脚本的消息。我们使用response.error来检索此数据。还使用一系列动画函数将登录框从左到右移动,以创建摇晃效果,强调错误给用户的重要性;如下所示:

_loginMsg.addClass("error").removeClass("success");
_loginMsg.html(response.error);
$('.login-box')
   .animate({ left: -25 }, 20)
   .animate({ left: 0 }, 60)
   .animate({ left: 25 }, 20)
   .animate({ left: 0 }, 60);
}

还有更多...

如果需要,jQuery 回调的成功登录部分可以轻松替换为重定向用户的操作。可以使用以下代码的原生 JavaScript 代码将用户发送到所需页面,将/memebers.php替换为适当的 URL,如下所示:

window.location.href = "/members.php";

请参阅

  • 第五章,表单处理

添加照片缩放

照片缩放是一个很棒的效果,可以在许多界面中使用,以增加对照片库或产品页面的额外用户交互,使用户可以清晰地看到较小的图像。这个配方将向您展示如何将照片缩放效果添加到列表中的四张图片中。

准备工作

在这个配方中,你需要四张图片。确保它们的宽度不超过800 px,高度不超过600 px。一旦收集到将在这个配方中使用的四张图片,请在与这些图片和 jQuery 库相同的目录中创建recipe-2.htmlrecipe-2.cssrecipe-2.js

如何做...

执行以下说明以将缩放效果添加到您选择的图像中:

  1. 将以下 HTML 代码添加到recipe-2.html中;确保更新与您选择的图像对应的图像引用:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Chapter 7 :: Recipe 2</title>
       <link href="recipe-2.css" rel="stylesheet" type="text/css" />
       <script src="img/jquery.min.js"></script>
       <script src="img/recipe-2.js"></script>
    </head>
    <body>
       <div class="container">
          <ul class="photos">
             <li><img src="img/recipe-2-1.jpg" alt="Countryside 1" /></li>
             <li><img src="img/recipe-2-2.jpg" alt="Countryside 2" /></li>
             <li><img src="img/recipe-2-3.jpg" alt="Countryside 3" /></li>
             <li><img src="img/recipe-2-4.jpg" alt="Countryside 4" /></li>
          </ul>
       </div>
    </body>
    </html>
    
  2. 将以下 CSS 代码添加到recipe-2.css中以样式化和定位图像:

    body {
       background-color: #333;
    }
    .container {
       width: 600px;
       height: 600px;
       margin: 50px auto auto auto;
    }
    .photos {
       list-style: none;
       margin: 0;
       padding: 0;
    }
    .photos li {
       display: inline-block;
       width: 290px;
       height: 250px;
       background-color: #E1E1E1;
       margin: 0 5px 5px 0;
       overflow: hidden;
       position: relative;
          cursor: pointer;
    }
    .photos li img {
       top: -50%;
       left: -50%;
       position: absolute;
       opacity: 0.5;
    }
    
  3. 将以下 jQuery 代码添加到recipe-2.js中,以在用户将鼠标悬停在图像上时为图像添加照片缩放动画:

    var images = [];
    $(function(){
       $(document).on("mouseover", ".photos li", function(){
          var _image = $(this).find('img');
          _image.finish();
          images[$(this).index()] = {
             width: _image.width(),
             height: _image.height()
          };
          _image.animate({
             width: '290px',
             height: '250px',
             top: 0,
             left: 0,
             opacity: 1.0
          });
       }).on("mouseout", ".photos li", function(){
          var _image = $(this).find('img');
          _image.finish();
          _image.animate({
             width: images[$(this).index()].width + "px",
             height: images[$(this).index()].height + "px",
             top: '-50%',
             left: '-50%',
             opacity: 0.5
          });
       });
    });
    
  4. 在网页浏览器中打开recipe-2.html,将鼠标悬停在四张图像之一上,即可看到缩放动画,如下所示:执行方法...

它是如何工作的...

本配方中的 HTML 代码非常基本,只是创建一个带有类名container的 division 元素,该元素在页面上使用 CSS 居中。在 frame division 内部,有一个无序列表元素,它有四个子元素,每个子元素都包含一个图像。

CSS 代码从无序列表中删除任何边距和填充,将其子项设置为内联显示,并将每个子元素的溢出属性设置为hidden。这样做是为了让我们最初加载比列表元素大的图像而不显示任何溢出,以提供放大的效果。

CSS 代码还将图像的顶部和左侧位置设置为-50%,以使它们居中在列表元素内。图像的不透明度也设置为0.5,以防止图像最初显眼。

在 jQuery 代码的开头,声明了一个images变量,用于存储稍后可以在代码中重复使用的图像数据。在 jQuery 的加载块内,将两个事件处理程序附加到文档上,以监听照片列表元素上的mouseovermouseout事件,如下所示:

$(document).on("mouseover", ".photos li", function(){
   // --  HIDDEN CODE
}).on("mouseout", ".photos li", function(){
   // -- HIDDEN CODE
});

mouseover事件处理程序内,使用$(this).find('img')来查找鼠标悬停的列表元素内的图像。选定了此图像后,使用$(this).index()将其大小存储在images变量中,如下所示:

images[$(this).index()] = {
   width: _image.width(),
   height: _image.height()
};

然后,使用 jQuery 的animate()函数,将图像的宽度和高度设置为与列表元素的大小相匹配,以创建缩小效果。其顶部和左侧位置也设置为0,覆盖了 CSS 中设置的-50%位置,以确保图像填满列表元素的 100%。图像的不透明度设置为1(即 100%),以便悬停和放大的图像在其他图像中突出显示。此代码如下所示:

_image.animate({
   width: '290px',
   height: '250px',
   top: 0,
   left: 0,
   opacity: 1.0
});

mouseout事件处理程序内,先前讨论的动画使用存储的图像信息有效地被反转,并将图像重置回鼠标悬停前的位置,执行如下:

var _image = $(this).find('img');
_image.finish();
_image.animate({
   width: images[$(this).index()].width + "px",
   height: images[$(this).index()].height + "px",
   top: '-50%',
   left: '-50%',
   opacity: 0.5
});

在上述代码中,可以看到使用$(this).index()引用了images数组,以获取图像的原始高度和宽度。再次将其顶部和左侧位置设置为-50%,使其在列表元素内居中。

注意

在事件处理程序回调中都使用_image.finish();来完成任何当前动画。这可以防止用户快速切换图像时出现奇怪的结果。

另请参阅

  • 创建一个动画导航菜单

创建一个动画内容滑块

您可能已经意识到,在线有一整片 jQuery 内容滑块插件、教程和可下载脚本的森林,其中大部分内容都可以免费使用。内容滑块非常受欢迎,因为它们是向用户展示重要内容(如图像、新闻和促销活动)的一种非常吸引人和引人注目的方式。本篇文章将向您展示如何使用 jQuery 轻松创建内容滑块。本篇食谱中使用的滑块将允许您使用 CSS 轻松自定义其外观和感觉,以使其符合您自己的需求。

准备工作

在与您的 jQuery 库相同的目录中创建通常的配方文件:recipe-3.htmlrecipe-3.cssrecipe-3.js

如何操作...

执行以下逐步说明以创建引人入胜的内容滑块:

  1. 将以下 HTML 代码添加到 recipe-3.html,其中包括基本网页和内容滑块的结构:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Chapter 7 :: Recipe 3</title>
       <link href="recipe-3.css" rel="stylesheet" type="text/css" />
       <script src="img/jquery.min.js"></script>
       <script src="img/recipe-3.js"></script>
    </head>
    <body>
       <div class="slider-frame">
          <ul class="slider-content">
             <li>
                <h1>Section 1</h1>
                <p>Some content for section one.</p>
             </li>
             <li>
                <h1>Section 2</h1>
                <p>Some content for section two.</p>
             </li>
             <li>
                <h1>Section 3</h1>
                <p>Some content for section three.</p>
             </li>
             <li>
                <h1>Section 4</h1>
                <p>Some content for section four.</p>
             </li>
          </ul>
          <ul class="slider-nav"></ul>
       </div>
    </body>
    </html>
    
  2. recipe-3.css 中添加以下 CSS 代码以添加基本样式并定位内容滑块:

    .slider-frame {
       width: 600px;
       height: 250px;
       margin: 50px auto auto auto;
       overflow: hidden;
       position: relative;
    }
    .slider-content {
       margin: 0;
       padding: 0;
       list-style: none;
       position: relative;
    }
    .slider-content li {
       float: left;
       width: 600px;
       height: 250px;
       background-color: #E1E1E1;
    }
    .slider-content li h1 {
       margin: 10px;
    }
    .slider-content li p {
       margin: 10px;
    }
    .slider-nav {
       list-style: none;
       padding: 0;
       margin: 0;
       height: 35px;
       position: absolute;
       bottom: 0;
       left: 0;
       right: 0;
       text-align: center;
    }
    .slider-nav li {
       display: inline-block;
       margin-right: 5px;
    }
    .slider-nav li a {
       display: block;
       color: #FFF;
       text-decoration: none;
       border-radius: 30px;
       background-color: #333;
       width: 25px;
       height: 25px;
       text-align: center;
       line-height: 25px;
    }
    .slider-nav li a:hover {
       background-color: #000;
    }
    .slider-nav li a.active {
       background-color: #FFF;
       color: #333;
    }
    
  3. recipe-3.js 中添加以下 jQuery 代码,以允许用户在内容幻灯片之间切换:

    $(function(){
       var _sliderContent = $('.slider-content li');
       for (var i = 0; i < _sliderContent.length; i++) {
          $('.slider-nav').append("<li><a href='#" + i + "' " + ((i == 0) ? "class='active'" : "") + ">" + (i + 1) + "</a></li>");    
       }
       $('.slider-content').width((600 * _sliderContent.length) + "px");
       $(document).on("click", ".slider-nav li a", function(){
          var index = this.hash.replace("#", "");
          $(".slider-nav li a").removeClass("active");
          $(this).addClass("active");
          $('.slider-content').animate({
             left: -(index * 600) + "px"
          });
       });
    });
    

工作原理...

滑块内容是一个无序列表,其子元素包含要在每个幻灯片中显示的内容。在内容列表下面是另一个无序列表元素,jQuery 将动态填充该元素,以创建每个幻灯片之间的导航。

此配方中的 CSS 代码用于定位滑块框架并设置其静态宽度和高度。将滑块框架的溢出值设置为 hidden,以便一次只能看到一个幻灯片。将滑块内容列表项元素设置为 float left,以便以行内方式显示它们,从而可以使用 jQuery 动画将它们移入视图中。

jQuery 代码的第一部分选择所有滑块内容子元素并将它们存储在一个局部变量中。对于每个滑块内容列表元素,都会创建一个导航列表项并将其附加到 slider-nav 无序列表中,该列表项链接到滑块内容的索引,如下代码所示;还将 active 类添加到第一个导航锚点:

var _sliderContent = $('.slider-content li');
for (var i = 0; i < _sliderContent.length; i++) {
   $('.slider-nav').append("<li><a href='#" + i + "' " + ((i == 0) ? "class='active'" : "") + ">" + (i + 1) + "</a></li>");
}

为了使滑块内容项能够与彼此一起浮动,需要使 slider-content 无序列表元素足够宽。由于 CSS 代码无法知道滑块有多少个幻灯片,因此使用 jQuery 计算内容项的数量,然后将此值乘以滑块的宽度,使用 jQuery width() 函数将此结果应用于 slider-content 元素,如下所示:

$('.slider-content').width((600 * _sliderContent.length) + "px");

执行上述代码将确保 slider-content 无序列表元素的宽度足够,以允许每个列表元素的行内定位。

jQuery 代码的最后部分将点击事件处理程序附加到文档,以便监听滑块导航上的点击。当用户点击导航元素之一时,将调用此处理程序的回调函数如下所示:

$(document).on("click", ".slider-nav li a", function(){
   var index = this.hash.replace("#", "");
   $(".slider-nav li a").removeClass("active");
   $(this).addClass("active");
   $('.slider-content').animate({
      left: -(index * 600) + "px"
   });
});

在回调函数中,使用 var index = this.hash.replace("#", ""); 检索点击链接的哈希值,这将导致幻灯片的索引整数。利用这个值,可以使用 jQuery 的 animate() 函数在 slider-content 无序列表元素上设置负左位置;这将使幻灯片内容动画显示所选幻灯片。removeClass() 函数用于从导航列表中的所有锚元素中移除 active 类。然后,使用 addClassactive 类添加到点击的元素上。这将向用户指示已选择导航中的哪个幻灯片,因为它会比其他导航项的颜色浅。

还有更多…

许多流行的 jQuery 内容滑块都有一个 auto 模式,其中每个内容幻灯片都会自动循环,无需任何用户交互。可以通过在示例中添加更多的 jQuery 代码轻松实现这一点。如果想要此功能,请将以下 jQuery 代码添加到 recipe-3.js$(function(){}); 块的底部:

var count = 0;
setInterval(function(){
   if (count >= _sliderContent.length) count = 0;
   $('.slider-content').animate({
      left: -(count * 600) + "px"
   });
   $(".slider-nav li a").removeClass("active");
   $(".slider-nav li").find("a[href='#" + count + "']").addClass("active");
   count++;
}, 3000);

使用原生 JavaScript 函数 setInterval(),可以连续执行指定间隔的函数。在上述示例中,指定的函数将在每 3000 毫秒后执行。

在上述代码中,声明了一个 count 变量来跟踪当前幻灯片。在提供给 setInterval 的函数内部,如果已达到可用幻灯片的最大数量,则将 count 值设置为 0。然后,jQuery 动画函数与单击事件处理程序的方式相同,用于将下一个内容幻灯片动画显示出来。再次使用 $(".slider-nav li a").removeClass("active"); 从所有导航锚点中移除 active 类,然后使用 $(".slider-nav li").find("a[href='#" + count + "']").addClass("active"); 仅将类添加到链接到下一个内容幻灯片的元素上。最后,增加计数,以便下一次迭代将下一个内容幻灯片动画显示出来。

还值得一提的是,每次调用 jQuery 的 append() 函数时,DOM 都会重新绘制。如果使用 append() 函数添加了许多项目,例如在这个示例中,这可能会导致应用程序变慢。避免这种情况的一种简单方法是通过创建要添加的所有列表元素的字符串,并在循环后包含单个 append() 函数。

另见

  • 动画背景图

动画背景图

全屏图像背景可以为任何网站提供非常吸引人的闪屏。本示例将向您展示如何使用 jQuery 动态更改网站的背景图像。

准备工作

在与 jQuery 库相同的目录中创建 recipe-4.htmlrecipe-4.cssrecipe-4.js。对于此示例,您还需要一组将用作背景图像的图像。找到三到四个大图像(最大尺寸为 1280 x 1024 像素),并将它们保存在您刚刚创建的三个文件相同的目录中。

实施方法如下:

打开并准备编辑刚刚创建的三个文件。

  1. 将以下 HTML 代码添加到 recipe-4.html 中,以创建基本的网页和用于容纳背景图像和文本的元素:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Chapter 7 :: Recipe 4</title>
       <link href="recipe-4.css" rel="stylesheet" type="text/css" />
       <script src="img/jquery.min.js"></script>
       <script src="img/recipe-4.js"></script>
    </head>
    <body>
       <div class="background"></div>
       <div class="text-frame">
          <div class="text-inner">
             <h1>BACKGROUND IMAGE ANIMATION</h1>
             <p>This recipe shows you how to alternate the background image of an element using jQuery animations.</p>
          </div>
       </div>
    </body>
    </html>
    
  2. 将以下 CSS 代码添加到 recipe-4.css 中,将基本样式应用于新创建的网页;确保更新图像引用以与您选择的图像之一相对应:

    body {
       background-color: #333;
    }
    .background {
       background: url(recipe-4-1.jpg)  no-repeat center center fixed;
       -webkit-background-size: cover;
       -moz-background-size: cover;
       -o-background-size: cover;
       background-size: cover;
       position: absolute;
       top: 0;
       bottom: 0;
       left: 0;
       right: 0;
    }
    .text-frame {
       position: absolute;
       top: 0;
       bottom: 0;
       left: 0;
       right: 0;
    }
    .text-inner {
       width: 600px;
       margin: 15% auto auto auto;
       background-color: rgba(0, 0, 0, 0.78);
       padding: 20px;
       color: #E1E1E1;
       border-radius: 5px;
    }
    .text-inner h1 {
       margin: 0;
       padding: 0;
    }
    .text-inner p {
       font-size: 22px;
       line-height: 30px;
       margin: 5px 0 5px 0;
       color: #CCC;
    }
    
  3. 将以下 jQuery 代码添加到 recipe-4.js 中,以激活刚刚添加到 recipe-4.htmlbackground 分割元素中的背景动画:

    var _images = ['recipe-4-1.jpg', 'recipe-4-2.jpg', 'recipe-4-3.jpg'];
    var index = 1;
    $(function(){
       setInterval(function(){
          if (index >= _images.length) index = 0;
          $('.background').animate({
             opacity: 0
          }, 1500, function(){
             $(this).css({
                'background-image': "url('" + _images[index] + "')"
             }).animate({
                opacity: 1
             }, 1500);
             index++;
          });
       }, 6000);
    });
    
  4. recipe-4.js 开头的 _images 数组中更新文件名,使其与您为此示例选择的图像文件名匹配。

工作原理如下:

这个示例创建的基本网页主要分为两个部分。首先是一个具有 background 类的分割元素,它被制作成填满整个屏幕,并使用所选的图像作为背景。其次,有一个 text-frame 分割元素,简单地将一些文本浮动在屏幕中央。

recipe-4.css 中的 CSS 代码将背景元素的位置设置为 absolute,并将其左、右、底部和顶部位置设置为 0,强制其填满整个屏幕。然后使用以下代码设置其背景属性:

background: url(recipe-4-1.jpg)  no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;

背景选项将其中一个所选图像设置为其初始背景,并确保其居中和固定。使用 background-size 属性确保背景图像始终填满 background 分割元素的 100%。

使用类似的 CSS 确保 text-frame 元素填满屏幕,并使用百分比和自动边距,使包含文本的 text-inner 元素在垂直和水平方向上居中。

recipe-4.js 开头的 _images 数组保存了对所选背景图像的引用。index 变量用于跟踪当前显示的背景图像。在 jQuery 加载函数内部,声明 setInterval 来执行一组动画,以在六秒钟内更改背景图像。这类似于上一个示例的 There's more... 部分。

因为 jQuery 的animate()函数不支持直接对背景图像进行动画处理,所以我们必须提供一个变通方法。在setInterval()函数中,将animate()函数用于背景元素的不透明度,以将元素淡出。然后,通过为 jQuery 的animate()函数指定回调,一旦动画完成,就使用 jQuery 的css()函数修改背景元素的background-image属性。使用css(),更改背景图像,然后再次使用animate()函数将不透明度更改回1,以淡入元素。通过引用_images数组的索引值,可以在setInterval()函数的每次迭代中选择不同的背景图像,如下所示:

$(this).css({
   'background-image': "url('" + _images[index] + "')"
}).animate({
   opacity: 1
}, 1500);
index++;

一旦最后一个动画完成,索引值将增加一,以确保下一次迭代显示不同的图像。

另请参阅

  • 创建一个动画内容滑块

创建动画导航菜单

您的网站导航允许访问者轻松找到托管在您网站上的内容。为用户提供一个既有趣又交互式的导航菜单,并且易于使用,可以给他们留下深刻的印象。本秘诀向您展示了如何创建一个现代动画导航菜单。

准备工作

在与最新版本的 jQuery 库相同的目录中创建recipe-5.htmlrecipe-5.cssrecipe-5.js

操作方法…

执行以下所有步骤,为任何站点创建一个独特和现代的动画导航菜单:

  1. recipe-5.html中添加以下 HTML,以创建基本网页,并包括新创建的文件以及 jQuery 库:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Chapter 7 :: Recipe 5</title>
       <link href="recipe-5.css" rel="stylesheet" type="text/css" />
       <script src="img/jquery.min.js"></script>
       <script src="img/recipe-5.js"></script>
    </head>
    <body>
    </body>
    </html>
    
  2. recipe-5.html中身体标签的 HTML 代码中,添加以下代码来创建导航菜单的结构:

    <div class="container">
       <ul class="navigation">
          <li>
             <a href="#" class="link-base">
                <div class="link-content">
                   <div class="nav-item">HOME</div>
                   <div class="nav-item hover">HOME</div>
                </div>
             </a>
          </li>
          <li>
             <a href="#" class="link-base">
                <div class="link-content">
                   <div class="nav-item">ABOUT <div class="down-arrow"></div></div>
                   <div class="nav-item hover">ABOUT <div class="down-arrow"></div></div>
                </div>
             </a>
             <ul class="sub-nav">
                <li>
                   <a href="#">
                      <div class="sub-link-content">
                         <div class="sub-nav-item">SECTION 1</div>
                         <div class="sub-nav-item hover">SECTION 1</div>
                        </div>
                     </a>
                  </li>
               <li>
                   <a href="#">
                      <div class="sub-link-content">
                         <div class="sub-nav-item">SECTION 2</div>
                         <div class="sub-nav-item hover">SECTION 2</div>
                      </div>
                   </a>
                </li>
                <li>
                   <a href="#">
                      <div class="sub-link-content">
                         <div class="sub-nav-item">SECTION 3</div>
                         <div class="sub-nav-item hover">SECTION 3</div>
                      </div>
                   </a>
                </li>
             </ul></li>
          <li>
             <a href="#" class="link-base">
                <div class="link-content">
                   <div class="nav-item">CONTACT</div>
                   <div class="nav-item hover">CONTACT</div>
                </div>
             </a>
          </li>
       </ul>
    </div>
    
  3. 添加以下 CSS 代码到recipe-5.css,为导航菜单和网页提供基本样式:

    .container {
       width: 800px;
       margin: 100px auto auto auto;
    }
    .navigation {
       margin: 0;
       padding: 0;
       list-style: none;
       background-color: #333;
       height: 50px;
    }
    .navigation li {
       float: left;
       position: relative;
    }
    .navigation li a {
       display: block;
       text-align: center;
       color: #FFF;
       text-decoration: none;
       overflow: hidden;
       height: 50px;
    }
    .navigation li a .nav-item {
       line-height: 50px;
       padding: 0 15px 0 15px;
       height: 50px;
    }
    .navigation li a .nav-item.hover {
       background-color: #ff3600;
    }
    .sub-nav {
       list-style: none;
       margin: 0;
       padding: 50px 0 0 0;
       opacity: 0;
       position: absolute;
       top: 0;
       left: -10000px;
       opacity: 0;
    }
    .sub-nav li {
       display: block;
       height: 40px;
    }
    .sub-nav li a {
       display: block;
       width: 120px;
       height: 40px;
       line-height: 40px;
       text-align: center;
       color: #FFF;
       background-color: #333333;
    }
    .sub-nav li a .sub-link-content {
       width: 240px;
    }
    .sub-nav li a .sub-nav-item {
       float: left;
       width: 120px;
    }
    .sub-nav li a .sub-nav-item.hover {
       background-color: #ff3600;
    }
    .down-arrow {
       width: 0;
       border-left: 7px solid transparent;
       border-right: 7px solid transparent;
       border-top: 7px solid white;
       display: inline-block;
       vertical-align: middle;
       margin: -5px 0 0 5px;
    }
    
  4. 要根据用户交互将动画添加到导航菜单,将以下 jQuery 代码添加到recipe-5.js中:

    $(function(){
       //Base navigation
       $(document).on("mouseenter", "ul.navigation li a.link-base", function(){
          $(this).find(".link-content").stop().animate({
             marginTop: -50
          }, 200, function(){
             $(this).parent().parent().find('.sub-nav').css({
               left: 0
            }).animate({
               opacity: 1
            });
          });
       }).on("mouseleave", "ul.navigation li a", function(){
          //Only reverse the animation if this link doesn't have a sub menu
          if ($(this).parent().find('.sub-nav').length == 0) {
             $(this).find(".link-content").stop().animate({
                marginTop: 0
            }, 200);
          }
       }).on("mouseleave", "ul.navigation li .sub-nav", function(){
          $(this).animate({
             opacity: 0
          }, 200, function(){
             $(this).css({
                left: -10000
           });
             //When the mouse leaves the sub menu, also reverse the base link animation
             $(this).parent().find('.link-content').stop().animate({
                marginTop: 0
             }, 200);
          });
       }).on("mouseenter", "ul.sub-nav li a", function(){
          $(this).find(".sub-link-content").stop().animate({
             marginLeft: -120
          }, 200);
       }).on("mouseleave", "ul.navigation li a", function(){
          $(this).find(".sub-link-content").stop().animate({
             marginLeft: 0
          }, 200);
       });
    });
    
  5. 在 Web 浏览器中打开recipe-5.html,您将看到一个简单的导航菜单。在关于项目上悬停将会启动动画,并向您呈现相关的子菜单,如下面的屏幕截图所示:操作方法…

运行原理…

当我们逐步分解时,本秘诀的代码将很容易理解。用于创建导航菜单的 HTML 代码具有一个带有 class frame的分区元素,它作为菜单容器来控制宽度和位置。

菜单本身由带有导航类的无序列表元素组成。在这个列表中,有多个作为菜单页面链接的锚的一级列表元素。

每个这些一级链接都有一个包含两个nav-item分区元素的link-content容器元素。使用 CSS 将其中两个nav-item元素进行不同的样式设置,可以使我们创建下拉动画,因为我们一次只显示其中一个。

about一级导航项也有一个子菜单。为了实现这一点,列表项包含另一个具有sub-nav类的无序列表。使用 CSS,当子菜单可见时,将此子导航元素放置在原始的一级页面链接上,以便鼠标指针不会离开该区域。这样,我们可以保持原始链接处于悬停状态,并且子菜单保持打开状态,直到用户的鼠标完全离开子菜单。

子菜单页面链接的结构与它们包含两个相同文本的一级链接相同。这样做是为了让我们能够创建类似的悬停动画。

recipe-5.js中,第一部分将mouseenter事件处理程序附加到文档上,以查找鼠标指针是否进入导航的一级链接之一,如下所示:

$(document).on("mouseenter", "ul.navigation li a.link-base", function(){
   $(this).find(".link-content").stop().animate({
      marginTop: -50
   }, 200, function(){
      $(this).parent().parent().find('.sub-nav').css({
      left: 0
   }).animate({
      opacity: 1
      });
   });
})

当发生这种情况时,将在链接的link-content子元素上使用animate()函数,将其顶部边距设置为-50。这将使第二个nav-item类移入具有 CSS 橙色背景的视图中。在 200 毫秒后,动画完成时,将调用额外的回调函数。

这将执行代码以打开当前悬停项目包含的任何子菜单。首先使用css()函数将子菜单的左侧位置设置为0,将其带到屏幕上,然后使用animate()函数将元素的不透明度设置为1,将图像淡入视图中。子菜单元素最初使用左侧位置-10000放置在屏幕外,以便它们不会妨碍用户可能在页面上执行的任何点击操作。

第二个事件处理程序是针对mouseleave事件的。此事件处理程序检查最近设置为left的顶级链接是否具有子菜单,使用if($(this).parent().find('.sub-nav').length == 0)。如果没有,悬停动画将被恢复,将link-content元素的顶部边距设为0。这样,我们可以在用户浏览子菜单时保持悬停状态处于活动状态。

下一个事件处理程序是另一个mouseleave事件处理程序,它处理用户离开子菜单,如下所示:

.on("mouseleave", "ul.navigation li .sub-nav", function(){
   $(this).animate({
      opacity: 0
   }, 200, function(){
      $(this).css({
      left: -10000
   });
   //When the mouse leaves the sub menu, also reverse the base link animation
   $(this).parent().find('.link-content').stop().animate({
      marginTop: 0
      }, 200);
   });
})

一旦用户的鼠标离开了子菜单,就会使用animate()函数将子菜单的不透明度设为0,使其淡出。然后,在完成了 200 毫秒的动画后,使用css()函数将子菜单移到屏幕外-10000 像素的位置。最后,使用find()来选择第一级link-content元素,将原始的悬停动画恢复,将菜单放回休眠状态。

文档附加了两个额外的事件处理程序。额外的mouseentermouseleave事件用于为子菜单项创建悬停动画。与一级导航菜单相同的代码和技术被使用,只是改变了左边距而不是顶边距,以使sub-link-content元素从左到右进行动画,而不是从上到下。

亦参见

  • 创建一个动态内容滑块

  • 动画背景图片

第八章:理解插件开发

在本章中,我们将涵盖以下主题:

  • 创建一个插件模板

  • 创建一个工具提示插件

  • 构建内容和图像滑块插件

  • 创建一个 RSS 订阅阅读器插件

  • 从头开始编写一个图像裁剪插件

介绍

jQuery 插件允许开发人员编写可在任何 jQuery 项目中快速重用的可移植代码。作为本书的一部分,我们已经创建了许多功能,您可能希望在多个项目中使用。通过创建具有所需功能的 jQuery 插件,您可以抽象出这些功能的复杂性,并使其简单地包含在您需要的任何地方。

在开始本章之前,请创建一个名为chapter8的易于访问的目录。在此文件夹中,添加最新版本的 jQuery 库,该库将在本章中使用。

创建一个插件模板

多年来,创建 jQuery 插件已经变得非常流行,有许多关于插件创建最佳实践的文章和在线讨论。这些文章中的许多都深入讨论了如何创建一个插件模板,该模板可用作任何 jQuery 插件的起点。本配方将向您展示如何创建自己的 jQuery 插件模板,该模板将在本章中使用。

准备就绪

在前面创建的chapter8文件夹内,创建一个名为jquery.plugin-template.js的 JavaScript 文件。

如何做…

要创建一个基本的插件模板,该模板将成为本章中使用的所有插件的基础,请将以下代码添加到jquery.plugin-template.js中:

;(function ($) {

    var name = 'pluginName';
    Plugin.prototype = {
        defaults: {

        }
    };

    // The actual plugin constructor
    function Plugin(element, options) {
        var $scope = this;
        $scope.$element = $(element);
        $scope.element = element;
        $scope.options = $.extend({}, this.defaults, options);
        $scope.init = function () {

        }
    }

    $.fn[name] = function (options) {
        return this.each(function () {
            new Plugin(this, options).init();
        });
    }
})(jQuery);

它是如何工作的…

在 jQuery 网站上阅读插件文档(learn.jquery.com/plugins/basic-plugin-creation/) ,以查看一组指南和最佳实践。

在本配方中创建的插件使用简单的概念和最佳实践来创建一个轻量级的插件模板。 Addy Osmani 撰写了一篇很受欢迎的文章(coding.smashingmagazine.com/2011/10/11/essential-jquery-plugin-patterns/) ,其中提供了关于插件编写的深入见解,同时遵循这些推荐的最佳实践。

看看我们的插件模板,首先要注意的是文档开头的分号。这是为了确保任何之前包含的插件或脚本都已正确关闭。

为了符合 jQuery 的作者建议,整个插件被包裹在一个立即调用的函数表达式IIFE)中,以为插件提供范围。jQuery 作为本地变量$提供给 IIFE,以允许开发人员以通常的方式引用 jQuery 库而不会发生冲突。

在插件构造函数中,声明了一个$scope变量,以便清楚地表示插件的范围。然后将插件正在初始化的元素分配给插件的范围,以及任何提供的插件选项。使用 jQuery 的extend()函数将defaults对象与options对象合并,覆盖可能在options中提供的任何默认值。最后,将init()函数添加到插件的范围,这是您将放置插件初始化代码的地方,如下所示:

$.fn[name] = function (options) {
   return this.each(function () {
      new Plugin(this, options).init();
   });
}

上述代码使得插件可用,就像任何其他使用指定插件名称(($('.element').pluginName();)的 jQuery 对象方法一样。使用this.each(),它将为插件初始化的每个元素创建一个新的插件实例,并调用插件的init()函数。

创建一个提示框插件

提示框是向用户展示关于他们正在使用的 UI 的其他信息的一种流行方式。本步骤将向您展示如何创建自己的基本提示框插件,您可以在所有项目中轻松使用。

准备工作

复制jquery.plugin-template.js文件,并创建jquery.tooltip.js,它将成为此步骤的插件文件。在与插件文件和 jQuery 库相同的目录中创建recipe-2.htmlrecipe-2.js

如何做…

要创建一个简单的提示框插件和示例网页,请执行以下步骤:

  1. recipe-2.html中添加以下 HTML 代码,创建一个非常简单的网页,网页中的元素可以有一个提示框。

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 8 :: Recipe 2</title>
        <script src="img/jquery.min.js"></script>
        <script src="img/jquery.tooltip.js"></script>
        <script src="img/recipe-2.js"></script>
    </head>
    <body>
    <p><input type="text" class="hasTooltip" data-title="This is a tooltip on an input box" /></p>
    <p><a href="http://www.google.com/" target="_blank" class="hasTooltip" title="External link to http://www.google.com/">Google.com</a></p>
    <button class="hasTooltip" data-title="A button with a tooltip">Button</button>
    </body>
    </html>
    
  2. jquery.tooltip.js的顶部,更新name变量,并将插件默认设置更改如下:

    var name = 'tooltip';
    Plugin.prototype = {
    defaults: {
                'height': 30,
                'fadeInDelay': 200
    }
    };
    
  3. 使用以下代码更新$scope.init()函数:

    $scope.init = function() {
    $scope._text = (typeof $scope.$element.data('title') != "undefined") ? $scope.$element.data('title') : $scope.$element.prop("title");
                //Only display the tooltip if a title has been specified
                if (typeof $scope._text != "undefined") {
                    var $html = $("<div class='tooltip-frame'>"
                        +   "<div class='tooltip-arrow'></div>"
                        +   "<div class='tooltip-text'>" + $scope._text + "</div>"
                        + "</div>");
    
                    $html.css({
                        'position': 'absolute',
                        'text-align': 'center',
                        'height': $scope.options.height,
                        'line-height': $scope.options.height + "px",
                        'left': $scope.$element.offset().left + $scope.$element.outerWidth() + 15,
                        'top': $scope.$element.offset().top + ($scope.$element.outerHeight() / 2) - ($scope.options.height / 2),
                        'background-color': 'rgba(0, 0, 0, 0.81)',
                        'color': '#FFF',
                        'padding': '0 10px 0 10px',
                        'border-radius': '5px',
                        'opact': 'none'
                    }).find('.tooltip-arrow').css({
                            'width': 0,
                            'height': 0,
                            'border-top': '10px solid transparent',
                            'border-bottom': '10px solid transparent',
                            'border-right': '10px solid rgba(0, 0, 0, 0.81)',
                            'position': 'absolute',
                            'left': '-10px',
                            'top': (($scope.options.height / 2) - 10)
                        });
    
                    $scope.$element.on("mouseover", function(){
                        $html.fadeIn($scope.options.fadeInDelay);
                        $scope.$element.after($html);
                    }).on("mouseout", function(){
                        $html.remove();
                    });
                }
            }
    
  4. 将以下 jQuery 代码添加到recipe-2.js中,为所有具有hasTooltip类的 HTML 元素初始化提示框插件:

    $(function(){
        $('.hasTooltip').tooltip();
    });
    
  5. 在 Web 浏览器中打开recipe-2.html,将鼠标悬停在屏幕上的一个元素上,以查看提示框出现。

它是如何工作的…

作为此步骤的一部分创建的 HTML 页面仅用于提供可以附加提示框的一些元素。

对插件模板的第一个更改是设置默认设置。在这种情况下,我们设置了提示框的高度和淡入动画持续时间。您可以通过将这些功能添加到此处的默认设置中,引入自己的其他功能。

当为每个选定的元素初始化插件时,将调用init()函数,该函数包含此插件的大部分逻辑。

插件模板使得元素的“jQueryfied”版本通过$scope.$element可用。我们可以使用prop()data()函数来检查元素上是否指定了标题,并将其存储在$scope._text中,这将被用作提示框的文本。

然后将检查此变量,以确保有可用的文本来显示。如果没有文本,我们将不显示提示框。

如果 $scope._text 被定义,我们使用以下代码创建工具提示 HTML:

var $html = $("<div class='tooltip-frame'>"
       +   "<div class='tooltip-arrow'></div>"
       +   "<div class='tooltip-text'>" + $scope._text + "</div>"
       + "</div>");

var 语句很重要,以确保为每个选定的元素创建一个新的工具提示元素。通过将 HTML 代码包装在 $() 内,我们可以在将其插入到 DOM 中之前在此元素上使用 jQuery 函数。工具提示的 HTML 代码添加了标题文本并创建了一个将显示左箭头的元素。

使用 jQuery 的 css() 函数,一系列 CSS 样式被应用于新创建的 HTML 代码,以定位和样式化工具提示。工具提示的左侧和顶部位置是使用将显示工具提示的选定元素的偏移量、宽度和高度来计算的。请注意,使用 outerWidth()outerHeight() 函数而不是 width()/height() 函数,以包含填充和边框并返回尺寸。

jQuery 的 find() 函数也与 css() 函数一起使用,用于向左箭头添加样式。

最后,两个事件侦听器被附加到选定的元素上,以便当用户的鼠标移动到元素上时显示工具提示,并在用户的鼠标移出时移除工具提示。fadeIn() 函数从 defaults 对象中取得 duration 参数,当初始化工具提示插件时可以被覆盖。

要为所有具有 hasTooltip 类的元素初始化工具提示插件,将以下 jQuery 代码添加到 recipe-2.js

$(function(){
    $('.hasTooltip').tooltip();
});

在这里,你可以覆盖默认设置,例如,使用以下代码:

$(function(){
    $('.hasTooltip').tooltip({
       'height': 50,
          'fadeInDelay': 500              
    });
});

这还不是全部...

这个配方提供了一个非常基本的工具提示插件。你可以在此基础上扩展很多额外的功能,比如定位,并允许插件用户指定工具提示在哪个事件上打开。

构建内容和图片滑块插件

在第七章中,用户界面动画,你看到了如何使用 jQuery 创建一个简单的内容滑块。本配方将向你展示如何将该配方转换为一个可重用的 jQuery 插件,还可以向滑块添加图片。你不需要阅读前一个配方来完成这个,但建议你这样做,以便更好地理解代码的工作原理。

准备工作

复制 jquery.plugin-template.js 文件并将其重命名为 jquery.slider.js,它将成为此配方的插件。你还需要找到一张宽度为 600 像素、高度为 250 像素的图片,将其用于滑块。最后,在 jquery.slider.js 文件和 jQuery 库相同目录下创建 recipe-3.htmlslider.cssrecipe-3.js

如何做...

执行以下步骤来创建您的图片和内容滑块插件:

  1. 将以下 HTML 添加到 recipe-3.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 8 :: Recipe 3</title>
        <link href="slider.css" rel="stylesheet" type="text/css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/jquery.slider.js"></script>
        <script src="img/recipe-3.js"></script>
    </head>
    <body>
    <div class="mySlider">
        <div>Slider Content 1</div>
        <img src="img/british-countryside.jpg" />
        <div>Slider Content 3</div>
        <div>Slider Content 4</div>
    </div>
    </body>
    </html>
    
  2. jquery.slider.js 的顶部,将插件名称更新为 slider,并将默认设置如下:

    var name = 'slider';
    Plugin.prototype = {
       defaults: {
          width: 600,
          height: 250
    }
    };
    
  3. 更新插件的 $scope.init() 函数如下所示:

    $scope.init = function () {
    $scope.$element.addClass("slider-frame").css({
       width: $scope.options.width,
       height: $scope.options.height
    });
    $scope.$element.append('<ul class="slider-nav"></ul>');
    var _sliderItems = $scope.$element.find('div, img');
    _sliderItems.wrapAll("<div class='slider-content'></div>");
    $scope.$element.find('.slider-content').css({
       width: $scope.options.width * _sliderItems.length,
       position: 'relative'
    });
    _sliderItems.css({
       float: 'left',
       width: $scope.options.width,
       height: $scope.options.height
    });
    var _sliderNav = $scope.$element.find('.slider-nav');
    for (var i = 0; i < _sliderItems.length; i++) {
       _sliderNav.append("<li><a href='#" + i + "' " + ((i == 0) ? "class='active'" : "") + ">" + (i + 1) + "</a></li>");
    }
    _sliderNav.on("click", "li a", function(){
       var index = this.hash.replace("#", "");
       _sliderNav.find('li a').removeClass("active");
       $(this).addClass("active");
       $scope.$element.find('.slider-content').animate({
          left: -(index * $scope.options.width) + "px"
       });
    });
    }
    
  4. 将以下 jQuery 代码添加到 recipe-3.js 中以初始化滑块插件:

    $(function(){
        $('.mySlider').slider();
    });
    
  5. 将以下 CSS 代码添加到 slider.css 中:

    .slider-frame {
        overflow: hidden;
        position: relative;
        margin: auto;
        border: solid 1px #CCC;
    }
    .slider-nav {
        list-style: none;
        padding: 0;
        margin: 0;
        height: 35px;
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        text-align: center;
    }
    .slider-nav li {
        display: inline-block;
        margin-right: 5px;
    }
    .slider-nav li a {
        display: block;
        color: #FFF;
        text-decoration: none;
        border-radius: 30px;
        background-color: #333;
        width: 25px;
        height: 25px;
        text-align: center;
        line-height: 25px;
    }
    .slider-nav li a:hover {
        background-color: #000;
    }
    .slider-nav li a.active {
        background-color: #FFF;
        color: #333;
    }
    
  6. 在 Web 浏览器中打开 recipe-3.html,您将看到一个动态创建的图像和内容滑块。

工作原理…

HTML 页面设置了滑块插件所需的 HTML。有一个包含子项的容器分区,滑块插件将使用这些子项作为幻灯片。子项可以是分区元素或图像。

recipe-3.js 中的 jQuery 代码选择 mySlider 分区元素并初始化滑块插件。

我们之前创建的插件模板负责 jQuery 插件的设置。我们的滑块插件的功能放在 init() 函数中。在此函数的开头,将 slider-frame 类添加到选定的元素(.mySlider)中,以便它从 slider.css 样式表中继承一些基本样式。使用来自 options 对象的值,使用 jQuery css() 函数设置元素的宽度和高度,如下所示:

$scope.$element.addClass("slider-frame").css({
width: this.options.width,
height: this.options.height
});

之后,使用 $scope.$element.append('<ul class="slider-nav"></ul>'); 将空的无序列表插入到滑块中,该列表已准备好创建幻灯片导航。

代码的下一部分设置了动画的滑块。如在 第七章 用户界面动画创建动画内容滑块 配方中所解释的,滑块需要其容器的宽度为其幻灯片的组合宽度,以便幻灯片可以浮动在一起,并使用动画移动到视图中,如下面的代码所示:

var _sliderItems = $scope.$element.find('div, img');
_sliderItems.wrapAll("<div class='slider-content'></div>");
$scope.$element.find('.slider-content').css({
width: $scope.options.width * _sliderItems.length,
position: 'relative'
});

为此,选择滑块的子项(幻灯片),然后使用 jQuery wrapAll() 函数将其包装在一个分区元素中。该元素的宽度设置为幻灯片的个数乘以单个幻灯片的宽度。为了浮动每个幻灯片,使用 css() 函数设置 float 属性,如下面的代码所示:

_sliderItems.css({
   float: 'left',
   width: $scope.options.width,
   height: $scope.options.height
});

配置了每个幻灯片后,代码的下一步是为 slider-nav 无序列表元素添加每个幻灯片的列表项,以形成导航:

var _sliderNav = $scope.$element.find('.slider-nav');
for (var i = 0; i < _sliderItems.length; i++) {
   _sliderNav.append("<li><a href='#" + i + "' " + ((i == 0) ? "class='active'" : "") + ">" + (i + 1) + "</a></li>");
 }

插件的最后阶段是监听导航列表中锚元素的点击,代码如下,以允许用户使用此导航更改可见幻灯片:

_sliderNav.on("click", "li a", function(){
   var index = this.hash.replace("#", "");
   _sliderNav.find('li a').removeClass("active");
   $(this).addClass("active");
   $scope.$element.find('.slider-content').animate({
      left: -(index * $scope.options.width) + "px"
});
});

当用户点击链接时,使用 animate() 函数根据所选链接更改 slider-content 分区元素的左侧位置。在 第七章 用户界面动画创建动画内容滑块 配方中可以阅读更多相关信息。

还有更多…

要将流行的自动滑块效果添加到此插件,回顾一下 第七章 中的 创建一个带动画内容滑块 配方,用户界面动画

另请参阅

  • 创建一个带动画内容滑块的 配方在 第七章,用户界面动画

创建一个 RSS 阅读器插件

RSS 阅读器是许多网站非常受欢迎的附加组件。此配方将向您展示如何使用 Google Feed API 创建可配置的 feed 阅读器插件,从而使您可以轻松地在任何网站上重用该插件。

准备工作

再次复制 jquery.plugin-template.js 文件并将其重命名为 jquery.rssreader.js,以提供此配方插件的基础。在同一目录中,创建 recipe-4.jsrssreader.cssrecipe-4.html

如何实现…

要创建 RSS 阅读器插件,请执行以下步骤:

  1. 将以下 HTML 代码添加到 recipe-4.html 中,以创建一个基本的网页,并使 Google Feed API 可供页面内使用:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 8 :: Recipe 4</title>
        <link href="rssreader.css" rel="stylesheet" type="text/css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/jsapi"></script>
        <script type="text/javascript">
            google.load("feeds", "1");
        </script>
        <script src="img/jquery.rssreader.js"></script>
        <script src="img/recipe-4.js"></script>
    </head>
    <body>
    <div class="myRSSContent"></div>
    </body>
    </html>
    
  2. 将以下 CSS 代码添加到 rssreader.css 中,以创建 RSS 阅读器的样式:

    @import url(http://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400);
    .rssreader-frame {
        background-color: #333;
        border-radius: 5px;
        border: solid 1px #1f1f1f;
        padding: 0 10px 10px 10px;
        font-family: 'Source Sans Pro', sans-serif !important;
    }
    .rssreader-frame h1 {
        margin: 5px 0 5px 0;
        padding: 0;
        font-size: 22px;
        color: #FFF;
        line-height: 30px;
        font-weight: 200;
    }
    .rssreader-frame ul {
        margin: 0;
        padding: 0;
        list-style: none;
    }
    .rssreader-frame ul h4 {
        margin: 0;
        position: relative;
        font-weight: 200;
        color: #E1E1E1;
    }
    .rssreader-frame p.description {
        margin: 0 -10px 10px -10px;
        padding: 0 10px 10px 10px;
        color: #CCC;
        font-size: 12px;
        border-bottom: solid 1px #494949;
    }
    .rssreader-frame ul h4 a {
        line-height: 25px;
        margin-right: 110px;
        display: block;
        text-decoration: none;
        color: #8bd;
    }
    .rssreader-frame ul h4 .entry-date {
        width: 100px;
        position: absolute;
        right: 0;
        top: 0;
        height: 25px;
        line-height: 25px;
        text-align: right;
    }
    .rssreader-frame ul li p {
        color: #666;
        margin: 0 0 10px 0;
        padding: 0 0 10px 0;
        border-bottom: dotted 1px #494949;
    }
    
  3. jquery.rssreader.js 的顶部,更新 defaults 对象和 name 变量如下所示:

    var name = 'rssreader';
    Plugin.prototype = {
    defaults: {
        url: 'http://feeds.bbci.co.uk/news/technology/rss.xml',
        amount: 5,
        width: null,
        height: null
       }
    };
    
  4. 更新插件 init() 函数以包含以下代码:

            $scope.init = function () {
                $scope.$element.addClass("rssreader-frame");
                if ($scope.options.width != null) {
                   $scope.$element.width($scope.options.width);
                }
                var feed = new google.feeds.Feed($scope.options.url);
                feed.setNumEntries($scope.options.amount);
                feed.load(function(result) {
                    if (!result.error) {
                        var _title = $("<h1>" + result.feed.title + "</h1>");
                        var _description = $("<p class='description'>" + result.feed.description + "</p>");
                        var _feedList = $("<ul class='feed-list'></ul>");
                        for (var i = 0; i < result.feed.entries.length; i++) {
                            var entry = result.feed.entries[i];
                            var date = new Date(entry.publishedDate);
                            var dateString = date.getDate() + "/" + (date.getMonth() + 1) + "/" + date.getFullYear();
                            var _listElement = $("<li></li>");
                            _listElement.append("<h4><a href='" + entry.link + "'>" + entry.title + "</a><div class='entry-date'>" + dateString + "</div></h4>");
                            _listElement.append("<p>" + entry.content + "</p>");
                            _feedList.append(_listElement);
                        }
                        $scope.$element.append(_title);
                        $scope.$element.append(_description);
                        $scope.$element.append(_feedList);
                        if ($scope.options.height != null && (_feedList.outerHeight() + _title.outerHeight()) > $scope.options.height) {
                            _feedList.css({
                                'height': ($scope.options.height - _title.outerHeight()),
                                'overflow-y': 'scroll',
                                'padding-right': 10
                            });
                        }
                    }
                });
            }
    
  5. 将以下几行 jQuery 添加到 recipe-4.js 中,以为 myRSSContent 元素初始化插件:

    $(function(){
        $('.myRSSContent').rssreader({
            width: 400,
            height: 300
        });
    });
    
  6. 在 Web 浏览器中打开 recipe-4.html,您将看到以下 RSS 阅读器:如何实现…

它是如何工作的…

创建此配方的网页的 HTML 代码有一个用于初始化 RSS 阅读器插件的单个 division 元素,并作为 RSS 内容的容器。此外,Google Feed API 也被用于此页面,位于 jquery.rssreader.js 文件之前。使用 Google Feed API 意味着我们可以轻松创建一个插件,而不需要任何服务器端工作。这也使得插件很容易移植到任何网站上。在 developers.google.com/feed/v1/devguide#hiworld 上阅读更多关于此 API 的信息。

CSS 代码为插件内部创建的 RSS 阅读器元素设置样式。不需要进一步解释此代码。

与本章中的其他插件一样,模板负责插件设置,我们的插件功能位于 init() 函数内,该函数在插件初始化后执行一次。

此函数的第一部分将 rssreader-frame 类添加到所选元素中,CSS 代码使用该类应用各种样式。然后,查看 options 变量,如果已提供,则在所选元素上设置宽度。

使用 Google Feed API,使用options对象的URLamount值配置了反馈请求,如下所示。这将告诉 API 在哪里收集 RSS 内容以及要返回多少个项目。

var feed = new google.feeds.Feed($scope.options.url);
feed.setNumEntries($scope.options.amount);

之后,使用load()函数进行请求,并指定回调函数,如下所示:

feed.load(function(result) {
if (!result.error) {
// -- HIDDEN CODE
}
}

如果没有发生错误,则创建标题、描述和无序列表元素,并将它们存储在本地变量中,如以下代码所示:

var _title = $("<h1>" + result.feed.title + "</h1>");
var _description = $("<p class='description'>" + result.feed.description + "</p>");
var _feedList = $("<ul class='feed-list'></ul>");

使用result.feed对象,可以提取用于放置在这些元素中的反馈标题和描述。这些元素被创建并包裹在 jQuery 选择器($())内,以便 jQuery 的函数可以在稍后对这些元素进行操作。

然后我们循环遍历每个条目,并为每个条目创建一个列表项。在每个列表项内,我们添加了反馈内容、日期、标题和链接。使用 JavaScript 的Date()函数,创建一个更易读的日期以插入到 DOM 中。要将每个元素添加到先前创建的无序列表元素中,使用了_feedList.append(_listElement);

标题、描述和现在已完全填充了 RSS 内容的列表可以使用以下代码插入到 DOM 中:

$scope.$element.append(_title);
$scope.$element.append(_description);
$scope.$element.append(_feedList);

最后,使用以下代码来为 RSS 订阅阅读器应用任何指定的高度,并在内容过大无法适应指定高度时添加滚动条:

if ($scope.options.height != null && (_feedList.outerHeight() + _title.outerHeight()) > $scope.options.height) {
   _feedList.css({
   'height': ($scope.options.height - _title.outerHeight()),
   'overflow-y': 'scroll',
   'padding-right': 10
});
}

另请参阅

  • 第六章中的创建新闻滚动条示例,用户界面

从头开始编写图像裁剪插件

当允许用户上传自己的图像时,无论是用于个人资料图片还是其他用途,让他们能够在浏览器中裁剪图像为用户提供了巨大的好处。这是因为大多数用户不会知道如何使用诸如 Photoshop 之类的第三方应用程序来更改图像。Internet 上有许多免费的图像裁剪插件和许多教程可以帮助您使用它们,但几乎没有提供完整解决方案的示例。本篇将向您展示如何从零开始创建自己的图像裁剪插件,如何将图像上传到 Web 服务器,并如何从图像裁剪器获取数据以按照用户的规范调整并保存图像。

准备就绪

由于此示例包含客户端和服务器端代码,因此请确保您仔细遵循每个步骤。在开始此示例之前,请在 Web 服务器的 Web 根目录中设置以下目录结构:

准备就绪

根据上述结构,您需要在您的 Web 根目录(前图中的www)下创建includesuploads文件夹。在includes文件夹中,保存 jQuery 库并创建以下四个文件:

  • imagecrop.css

  • jquery.imagecrop.js(像以前一样复制jquery.plugin-template.js文件以创建此插件的基础)

  • recipe-5.css

  • recipe-5.js

在 Web 根目录中,您需要创建 index.htmlupload.php 文件。

注意

本示例将 不会 在 IE9 或更低版本中工作,因为较旧的浏览器不支持 XMLHttpRequestFormDataFileReader API。

如何做…

仔细按照以下每个步骤,然后阅读 工作原理… 部分,以充分理解插件及其相关代码:

  1. 将以下 HTML 代码添加到 index.html 中,以创建一个带有图像上传表单的 Web 页面:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 8 :: Recipe 5 - Image Crop Plugin</title>
        <link href="includes/imagecrop.css" rel="stylesheet" type="text/css" />
        <link href="includes/recipe-5.css" rel="stylesheet" type="text/css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/jquery.imagecrop.js"></script>
        <script src="img/recipe-5.js"></script>
    </head>
    <body>
        <div class="container">
            <h3>#1: Select Image</h3>
            <input type="file" id="selectedImage" />
            <h3>#2: Crop Image</h3>
            <div class="image-preview">
                <div class="preview-msg">Select and image to upload</div>
                <img id="croppable-image" style="display: none;" />
            </div>
            <h3>#3: Upload</h3>
            <div class="progress-bar"><div class="inner"></div></div>
            <div class="actions">
                <button class="upload-button">Upload</button>
            </div>
        </div>
    </body>
    </html>
    
  2. 将以下 CSS 代码放入 recipe-5.css 中,为您刚刚创建的 HTML 页面和表单添加样式:

    @import url(http://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400);
    body {
        background-color: #F1F1F1;
        font-family: 'Source Sans Pro', sans-serif !important;
    }
    h1, h2, h3 {
        font-weight: 300;
        margin: 0;
    }
    .container {
        width: 800px;
        margin: 50px auto auto auto;
        background-color: #FFFFFF;
        padding: 20px;
        border: solid 1px #E1E1E1;
    }
    .container h3 {
        line-height: 40px;
    }
    .container .image-preview {
        border: solid 1px #E1E1E1;
        width: 800px;
        height: 600px;
        overflow: hidden;
        margin: auto;
        position: relative;
    }
    .container .image-preview .preview-msg {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: #F1F1F1;
        text-align: center;
        font-size: 22px;
        line-height: 600px;
        font-weight: 300;
        z-index: 1;
    }
    #croppable-image {
        position: relative;
        z-index: 2;
    }
    .container .progress-bar {
        height: 30px;
        border: solid 1px #E1E1E1;
    }
    .container .progress-bar .inner {
        height: 30px;
        width: 0;
        background-color: #54ee86;
    }
    .container .actions {
        text-align: right;
        margin-top: 10px;
    }
    .container .actions .upload-button {
        height: 30px;
        width: 60px;
    }
    
  3. 将以下 jQuery 代码添加到 recipe-5.js 中,该代码将允许用户从其本地文件系统中选择并预览图像,然后启动图像裁剪插件:

    $(function(){
        var _selectedFile;
        $(document).on("change", "#selectedImage", function(){
            var reader = new FileReader();
            var files = $(this).prop("files");
            if (files.length > 0) {
                _selectedFile = files[0];
                reader.onload = function() {
                    var image = new Image;
                    image.src = this.result;
                    if (image.width > 800 || image.height > 600) {
                        alert("Image cannot be larger that 800x600");
                    } else {
                        $('.preview-msg').hide();
                        $('#croppable-image').prop("src", this.result).fadeIn().imagecrop();
                    }
                };
                reader.readAsDataURL(_selectedFile);
            }
        });
        $(document).on("click", ".upload-button", function(){
            var _selectedImage = $('#croppable-image');
            if (_selectedImage.data("selection-width") > 0 && _selectedImage.data("selection-height") > 0) {
                var data = new FormData();
                data.append("image", _selectedFile);
                data.append("selection-width", _selectedImage.data("selection-width"));
                data.append("selection-height", _selectedImage.data("selection-height"));
                data.append("selection-left", _selectedImage.data("selection-x"));
                data.append("selection-top", _selectedImage.data("selection-y"));
                var xhr = new XMLHttpRequest();
                xhr.open("POST", "/upload.php");
                xhr.onprogress = function(event) {
                    var percent = (event.loaded / event.total * 100);
                    $('.progress-bar .inner').width(percent + "%");
                }
                xhr.onload = function() {
                    var response = JSON.parse(this.response);
                    if (response.success == false) {
                        alert(response.error);
                    }
                }
                xhr.send(data);
            } else {
                alert("Please crop the image before upload");
            }
        });
    });
    
  4. jquery.imagecrop.js 中,按照以下代码片段的示例,更新插件名称和默认值:

    var name = 'imagecrop';
        Plugin.prototype = {
            defaults: {
                minWidth: 100,
                minHeight: 100
       }
    };
    
  5. 在由插件模板文件创建的插件构造函数中,在声明 $scope.options 之后直接添加以下声明,如下面的代码片段所示:

    $scope.options = $.extend({}, this.defaults, options);
    $scope.imageSelection = {
       start: {
          x: 0,
          y: 0
       },
       end: {
          x: 0,
          y: 0
       },
       top: 0,
       left: 0
    };
    var _frame;
    var _overlayLayer;
    var _selectionLayer;
    var _selectionOutline;
    
  6. 更新插件 $scope.init() 函数,包括以下代码:

    //Has this element already been initialised?
    if (typeof $scope.$element.data("selection-x") != "undefined") {
       //Yes, so reuse the DOM elements...
       _frame = $(document).find('.crop-frame').css({
          width: $scope.$element.width(),
          height: $scope.$element.height()
       });
          _overlayLayer = $(document).find('.overlay-layer');
          _selectionLayer = $(document).find('.selection-layer');
          _selectionOutline = $(document).find('.selection-outline');
    } else {
       //No, let's initialise then...
       _frame = $("<div class='crop-frame'></div>").css({
          width: $scope.$element.width(),
          height: $scope.$element.height()
       });
       _overlayLayer = $("<div class='overlay-layer'></div>");
       _selectionLayer = $("<div class='selection-layer'></div>");
       _selectionOutline = $("<div class='selection-outline'></div>");
       //Wrap the image with the frame
       $scope.$element.wrap(_frame);
       _overlayLayer.insertAfter($scope.$element);
       _selectionLayer.insertAfter($scope.$element);
       _selectionOutline.insertAfter($scope.$element);
       /** EVENTS **/
       _selectionLayer.on("mousedown", $scope.onSelectionStart);
       _selectionLayer.on("mouseup", $scope.onSelectionEnd);
       _selectionOutline.on("mouseup", $scope.onSelectionEnd); 
       _selectionOutline.on("mousedown", $scope.onSelectionMove);
    }
    $scope.updateElementData();
    /** UPDATE THE OUTLINE BACKGROUND **/
    _selectionOutline.css({
       'background': 'url(' + $scope.$element.prop("src") + ')',
       'display': 'none'
    });
    
  7. $scope.init() 函数之后,添加以下额外的函数:

    /**
    * MAKING THE SELECTION
    */
    $scope.onSelectionStart = function(event) {
       $scope.imageSelection.start = $scope.getMousePosition(event);
       _selectionLayer.bind({
         mousemove: function(event) {
       $scope.imageSelection.end = $scope.getMousePosition(event);
       $scope.drawSelection();
        }
      });
    };
    $scope.onSelectionEnd = function() {
       _selectionLayer.unbind("mousemove");
       //Hide the element if it doesn't not meet the minimum specified dimensions
       if (
          $scope.getSelectionDimentions().width < $scope.options.minWidth || $scope.getSelectionDimentions().height < $scope.options.minHeight
    ) {
          _selectionOutline.hide();
       }
       _selectionOutline.css({
          'z-index': 1001
       });
    };
    $scope.drawSelection = function() {
       _selectionOutline.show();
       //The smallest top value and the smallest left value are used to set the position of the element
       $scope.imageSelection.top = ($scope.imageSelection.end.y < $scope.imageSelection.start.y) ? $scope.imageSelection.end.y : $scope.imageSelection.start.y;
    $scope.imageSelection.left = ($scope.imageSelection.end.x < $scope.imageSelection.start.x) ? $scope.imageSelection.end.x : $scope.imageSelection.start.x;
    _selectionOutline.css({
       position: 'absolute',
       top: $scope.imageSelection.top,
       left: $scope.imageSelection.left,
       width: $scope.getSelectionDimentions().width,
       height: $scope.getSelectionDimentions().height,
       'background-position': '-' + $scope.imageSelection.left + 'px -' + $scope.imageSelection.top + 'px'
    });
    $scope.updateElementData();
    };
       /**
    * MOVING THE SELECTION
    */
    $scope.onSelectionMove = function() {
       //Prevent trigger the selection events
       _selectionOutline.addClass('dragging');
       _selectionOutline.on("mousemove mouseout", function(event){
          if ($(this).hasClass("dragging")) {
             var left = ($scope.getMousePosition(event).x - ($(this).width() / 2));
            //Don't allow the draggable element to over the parent's left and right
            if (left < 0) left = 0;
            if ((left + $(this).width()) > _selectionLayer.width()) left = (_selectionLayer.width() - $(this).outerWidth());
            var top = ($scope.getMousePosition(event).y - ($(this).height() / 2));
            //Don't allow the draggable element to go over the parent's top and bottom
            if (top < 0) top = 0;
            if ((top + $(this).height()) > _selectionLayer.height()) top = (_selectionLayer.height() - $(this).outerHeight());
            $scope.imageSelection.left = left;
            $scope.imageSelection.top = top;
            //Set new position
            $(this).css({
               top: $scope.imageSelection.top,
               left: $scope.imageSelection.left,
               'background-position': '-' + $scope.imageSelection.left + 'px -' + $scope.imageSelection.top + 'px'
            });
       }
       }).on("mouseup", function(){
       $(this).removeClass('dragging');                $scope.updateElementData();
       });
    }
    
  8. 在您添加的函数下方插入以下辅助函数:

    /**
    * HELPER FUNCTIONS
    */
    $scope.getMousePosition = function(event) {
       return {
          y: (event.pageY - _selectionLayer.offset().top),
          x: (event.pageX - _selectionLayer.offset().left)
       };
    };
    $scope.getSelectionDimentions = function() {
       //Work out the width and height based on the start and end positions
       var width = ($scope.imageSelection.end.x - $scope.imageSelection.start.x);
       var height = ($scope.imageSelection.end.y - $scope.imageSelection.start.y);
       //If any negatives turn them into positives
       if (height < 0) height = (height * -1);
       if (width < 0) width = (width * -1);
       return {
          width: width,
          height: height,
          x: $scope.imageSelection.start.x,
          y: $scope.imageSelection.start.y
       };
    }
    $scope.updateElementData = function() {
        $scope.$element.data({
          "selection-x": $scope.imageSelection.left,
          "selection-y": $scope.imageSelection.top,
          "selection-width": $scope.getSelectionDimentions().width,
          "selection-height": $scope.getSelectionDimentions().height
       });
    }
    
  9. 将以下 CSS 代码添加到 imagecrop.css 中,为图像裁剪插件创建的元素添加样式:

    .crop-frame {
        position: relative;
        margin: auto;
    }
    .selection-layer {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 1000;
    }
    .selection-outline {
        border: dotted 1px #000000;
        z-index: 999;
    }
    .selection-outline:hover, .selection-outline:active {
        cursor: move;
    }
    .overlay-layer {
        background-color: rgba(255, 255, 255, 0.60);
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 998;
    }
    
  10. 最后,将以下 PHP 代码添加到 upload.php 中,该代码将从您刚刚创建的 Web 表单中获取数据,然后裁剪图像并将其保存到 uploads 目录中:

    <?php
    if (isset($_FILES['image'])) {
        $response = array(
            "success" => false,
            "error" => ""
        );
        //GET SELECTION DATA
        $selectionWidth = (isset($_POST['selection-width'])) ? $_POST['selection-width'] : 0;
        $selectionHeight = (isset($_POST['selection-height'])) ? $_POST['selection-height'] : 0;
        $selectionTop = (isset($_POST['selection-top'])) ? $_POST['selection-top'] : 0;
        $selectionLeft = (isset($_POST['selection-left'])) ? $_POST['selection-left'] : 0;
        //GET IMAGE DATA
        $fileName = $_FILES['image']['name'];
        $ext = pathinfo($fileName, PATHINFO_EXTENSION);
        if ($selectionWidth > 800 || $selectionHeight > 600) {
            $response["error"] = "Image cannot be larger than 800 x 600";
        } else if (!in_array($ext, array("png", "jpg"))) {
            $response["error"] = "Invalid file type";
        } else {
    if ($ext == "png") {
    $source = imagecreatefrompng($_FILES['image']['tmp_name']);
            } else {
    $source = imagecreatefromjpeg($_FILES['image']['tmp_name']);
            }        $dest = imagecreatetruecolor($selectionWidth, $selectionHeight);
    imagecopyresampled($dest, $source, 0, 0, $selectionLeft, $selectionTop, $selectionWidth, $selectionHeight, $selectionWidth, $selectionHeight);
            $path = "/uploads/";
            if (!imagejpeg($dest, getcwd() . $path . $fileName, 100)) {
                $response["error"] = "Could not save uploaded file";
            } else {
                $response["success"] = true;
            }
        }
        header("Content-Type: application/json; charset=UTF-8");
        echo json_encode($response);
    }
    
  11. 在您的 Web 浏览器中导航到 index.html 文件,您将看到一个包含三个步骤的简单 Web 表单。通过选择 选择文件 按钮并从计算机中选择图像,您将看到图像显示在预览框内。在预览框中,您可以点击并拖动一个选择区域到图像上。完成后,点击 上传 将图像上传到 Web 服务器(通过进度条指示),并且图像将被裁剪并保存到您之前创建的 uploads 文件夹中。

工作原理…

了解本示例的不同部分非常重要。本示例的第一个元素是上传表单本身,在上传之前,它提供了在浏览器中查看用户选择的图像的功能。本示例的第二个元素是图像裁剪插件本身,这是我们将重点关注的内容。最后,为了提供完整的解决方案,本示例的上传元素接收图像裁剪插件提供的数据,并将其发布到 PHP 脚本。然后,该 PHP 脚本将获取这些数据进行裁剪,并将图像保存到用户指定的位置。

图像选择和预览

index.html 中的 HTML 代码创建了一个带有文件输入元素的基本界面。当用户点击 选择文件 按钮时,将会打开浏览窗口,允许他们从计算机中选择文件。使用 JavaScript 的 FileReader 类,我们可以读取此文件并在浏览器中显示它。查看 recipe-5.js,您将看到一个包含执行此操作的代码的 change 事件处理程序。

在代码中的这一点上,有一个基本的验证检查,以确保所选图片不大于 800 x 600 像素。如果是,则向用户显示警报,并且图片不会加载。

图片加载完成后,#cropableImage 元素的 source 属性被更新为所选图片,将其显示在屏幕上。最后,在图片元素上初始化了图片裁剪插件,如下所示:

$('#croppable-image').prop("src", this.result).fadeIn().imagecrop();

图片裁剪插件

图片裁剪插件动态创建了一系列元素,充当图层和容器,允许我们让用户进行选择。为了更容易理解每个图层的作用,它们在下图中进行了说明:

图片裁剪插件

遮罩 层用白色背景和 0.6 的不透明度淡化了大部分图片。选择 层是监听鼠标事件的层,指示用户正在进行选择。这样做的主要原因是,如果将鼠标事件附加到图片本身,我们将在某些允许您将图片拖动到一个带有图片的可视化表示的浏览器中遇到困难,这会妨碍我们的功能。选择轮廓 层是插件在用户进行选择时绘制的内容。其背景是所选图片,除了位置被调整以仅显示已选择的图片部分,提供对遮罩遮挡的原始图片的聚焦。

插件初始化时,有一组局部变量和默认值声明,插件将在其运行过程中使用;这些显示在以下代码片段中:

$scope.imageSelection = {
start: {
   x: 0,
   y: 0
},
end: {
   x: 0,
   y: 0
},
top: 0,
left: 0
};
var _frame;
var _overlayLayer;
var _selectionLayer;
var _selectionOutline;

var 开头的变量将存储代表图层的不同 DOM 元素。imageSelection 对象存储用户的初始点击坐标,然后是用户完成选择时的坐标。然后,我们可以使用这些坐标来计算选择的宽度和位置。topleft 参数存储了选择的最终坐标,一旦宽度和高度已经计算出来。

在插件的 init() 函数内部,有一个初始检查以确定图片是否已初始化。如果是,则图层 DOM 元素已经被创建并插入,如下所示:

if (typeof $scope.$element.data("selection-x") != "undefined") {
   // -- HIDDEN CODE
} else {
   // -- HIDDEN CODE
}

如果 DOM 元素可用,则使用 jQuery 的find()函数选择元素并将它们存储在关联变量中。如果没有,则创建并存储。可能已为图像初始化插件的一种场景是用户决定更改所选图像。图像源发生变化,但 DOM 元素可以保持原位并以不同的尺寸重用。

当图层元素首次创建时,会创建一个容器分隔元素,其类名为crop-frame,尺寸与所选图像相同,如下面的代码片段所示:

_frame = $("<div class='crop-frame'></div>").css({
    width: $scope.$element.width(),
    height: $scope.$element.height()
});

用户选择必须精确匹配实际图像像素尺寸,否则裁剪计算将不正确。然后,选定的图像元素将使用 jQuery 的wrap()函数包装在此框架内,如下所示:

$scope.$element.wrap(_frame);
_overlayLayer.insertAfter($scope.$element);
_selectionLayer.insertAfter($scope.$element);
_selectionOutline.insertAfter($scope.$element); 

其他创建的图层插入到所选图像元素之后,位于crop-frame分隔元素内,如上面的代码所示。

图层创建的最后一部分附加了各种处理选择过程不同部分的事件处理程序函数:

_selectionLayer.on("mousedown", $scope.onSelectionStart);
_selectionLayer.on("mouseup", $scope.onSelectionEnd);
_selectionOutline.on("mouseup", $scope.onSelectionEnd);
_selectionOutline.on("mousedown", $scope.onSelectionMove);

这里指定的每个函数稍后在plugin类中声明。在init()函数的末尾,调用updateElementData()函数,该函数设置所选图像元素上的初始选择尺寸(例如,selection-x)并在选择轮廓图层上设置背景图像。

当用户首次单击选择图层时,鼠标位置将被存储为起始坐标。然后,当用户拖动鼠标进行选择时,新的鼠标坐标被存储为结束坐标,并调用drawSelection()函数。drawSelection()函数使用起始和结束坐标来计算选择的宽度和高度,并更新选择轮廓图层的 CSS 以显示此内容,如下所示:

$scope.drawSelection = function() {
   _selectionOutline.show();
   //The smallest top value and the smallest left value are used to set the position of the element
$scope.imageSelection.top = ($scope.imageSelection.end.y < $scope.imageSelection.start.y) ? $scope.imageSelection.end.y : $scope.imageSelection.start.y;
$scope.imageSelection.left = ($scope.imageSelection.end.x < $scope.imageSelection.start.x) ? $scope.imageSelection.end.x : $scope.imageSelection.start.x;
_selectionOutline.css({
   position: 'absolute',
   top: $scope.imageSelection.top,
   left: $scope.imageSelection.left,
   width: $scope.getSelectionDimentions().width,
   height: $scope.getSelectionDimentions().height,
   'background-position': '-' + $scope.imageSelection.left + 'px -' + $scope.imageSelection.top + 'px'
});
$scope.updateElementData();
};

作为此函数的一部分,选择轮廓图层的背景位置将被更新以显示实际选择,并调用updateElementData()函数以将新的选择数据应用于所选图像。

当用户完成选择并释放鼠标按钮时,将调用onSelectionEnd()函数。此函数确定选择是否小于允许的最小值;如果是,则隐藏选择。将鼠标移动事件从选择图层解绑,以避免与后续功能发生冲突,并更新选择轮廓图层的z-index属性,以便选择轮廓图层移动到选择图层上方,从而实现拖动功能。拖动功能在第六章用户界面中的创建基本拖放功能配方中进行了详细介绍。有关详细说明,请参阅该配方。

图像上传

recipe-5.js 中,为 上传 按钮的点击事件附加了事件处理程序。在此事件的回调函数内,首先确定用户是否已经进行了选择。如果没有,则显示警告,要求用户进行裁剪选择。

如果已经进行了有效的选择,将创建一个新的 FormData 对象来存储要上传到 PHP 脚本的数据,如下所示:

var data = new FormData();
data.append("image", _selectedFile);
data.append("selection-width", _selectedImage.data("selection-width"));
data.append("selection-height", _selectedImage.data("selection-height"));
data.append("selection-left", _selectedImage.data("selection-x"));
data.append("selection-top", _selectedImage.data("selection-y"));

_selectedFile 变量包含对所选文件的引用,在文件输入的更改事件中可用。

将所需数据存储在 FormData 对象中后,创建一个新的 XMLHttpRequest 对象来将数据发送到 PHP 上传脚本,如下代码片段所示:

var xhr = new XMLHttpRequest();
xhr.open("POST", "/upload.php");
xhr.onprogress = function(event) {
   var percent = (event.loaded / event.total * 100);
   $('.progress-bar .inner').width(percent + "%");
}
xhr.onload = function() {
   var response = JSON.parse(this.response);
   if (response.success == false) {
      alert(response.error);
}
}
xhr.send(data);

此代码不言自明,简单地允许我们直接从 JavaScript 中进行 POST,无需 HTML 表单。 onprogress() 函数由 XHR 请求调用,当图像正在上传时允许我们更新 HTML 页面上的进度条以反映上传进度。 onload() 函数在操作完成时调用,允许我们显示任何发生的错误。

使用 PHP 进行裁剪和保存图像

PHP 脚本相对简单。它接受并存储通过 JavaScript 提供的 POST 请求中的信息,并对图像宽度和扩展名进行基本验证,仅允许 JPG 和 PNG 图像。

如果图像通过了验证,则根据提供的图像使用 imagecreatefrompng()imagecreatefromjpeg() 在 PHP 中创建图像资源。然后,如下所示的代码行创建了一个具有指定裁剪尺寸的空白图像:

$dest = imagecreatetruecolor($selectionWidth, $selectionHeight);

你可以将这个空白图像看作是 PHP 将用来在上面绘制修改后图像的画布。然后,提供的图像被裁剪,并且使用 imagecopyresampled() 将新图像存储在空白画布上,如下所示:

imagecopyresampled($dest, $source, 0, 0, $selectionLeft, $selectionTop, $selectionWidth, $selectionHeight, $selectionWidth, $selectionHeight);

最后,新图像将保存到在此配方开始时创建的 uploads 目录中,如下所示:

imagejpeg($dest, getcwd() . $path . $fileName, 100)

当你打开 uploads 目录时,你应该能看到新图像。

还有更多...

本配方提供了一个基本的完整解决方案,用于预览、裁剪、上传和保存图像,但还有许多可以改进的地方。客户端和服务器端的验证都可以进行大幅改进,以允许其他图像类型,并检查文件大小以及尺寸。

FileReader 正在将本地文件读入浏览器时,可以像为上传部分实现进度条一样添加加载器或进度条。

最后,可以改进拖放功能,使选择区域的中心不会“捕捉”到鼠标指针,因为这可能会对用户造成困惑。

另请参阅

  • 在 第六章 用户界面创建基本的拖放功能 配方中

第九章:jQuery UI

在本章中,我们将涵盖:

  • 创建时尚且功能性的按钮

  • 创建用户信息和输入对话框

  • 在应用程序中实现进度条

  • 快速向输入框添加日期选择器界面

  • 创建自动完成搜索功能

介绍

jQuery UI 是建立在 jQuery JavaScript 库之上的用户界面库。jQuery UI 提供了许多交互式插件、效果和界面元素,开发人员可以在其界面中使用。本章将演示 jQuery UI 的最常见元素,如按钮和日期选择器,并向您展示如何快速将它们添加到您的网站或 Web 应用程序中。

在开始本章之前,请确保您已访问过jqueryui.com/并下载了 jQuery UI 库。通过他们网站上的Download Builder下载库;确保所有默认选项保持选中状态。本章中使用的 jQuery UI 版本为 v1.10.3,但大多数示例也适用于更新版本。他们的网站还提供了丰富的文档和示例,帮助您快速入门 jQuery UI。

要开始本章的示例,请创建一个名为 chapter9 的易于访问的文件夹,并将 jQuery 库放入其中。创建一个名为 jquery-ui 的子文件夹,并将 jQuery UI 库的 cssjs 文件夹放入此子文件夹。

创建时尚且功能性的按钮

使用 CSS3 快速创建时尚按钮相对容易,但要添加额外的功能通常需要更多的时间投入。jQuery UI 提供了一个按钮 API,可用于创建各种按钮控件,这些控件可以轻松添加到 UI 中,并在 JavaScript 代码中进行交互。本示例演示了如何创建常见的按钮控件,以便您可以在需要时重新使用代码。

准备工作

在之前创建的 chapter9 文件夹中,创建 recipe-1.htmlrecipe-1.js

如何做…

使用 jQuery UI 库创建一系列不同的按钮控件,执行以下步骤:

  1. 为了添加各种按钮元素,请将以下 HTML 代码添加到 recipe-1.html 中,确保在必要时更新对 jQuery 和 jQuery UI 库的引用:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Chapter 9 :: Recipe 1</title>
       <script src="img/jquery.min.js"></script>
       <script src="img/jquery-ui-1.10.3.custom.min.js"></script>
       <link type="text/css" rel="stylesheet" href="jquery-ui/css/ui-lightness/jquery-ui-1.10.3.custom.min.css" />
       <script src="img/recipe-1.js"></script>
    </head>
    <body>
       <h3>Default buttons: a, button and input</h3>
       <a href="#">Button 1</a>
       <button>Button 2</button>
       <input type="submit" name="button3" value="Button 3" />
       <h3>Button options: Disabled, Custom Label and icons</h3>
       <button class="button4">Button 4: Disabled</button>
       <button class="button5">Button 5</button>
       <button class="button6">Button 6 with icons</button>
       <h3>Button Sets: Radio and Checkbox's</h3>
       <div class="buttonSet1">
          <button>One</button>
          <button>Two</button>
          <button>Three</button>
       </div>
       <div class="buttonSet2">
          <input type="checkbox" id="check1" /><label for="check1">Check 1</label>
          <input type="checkbox" id="check2" /><label for="check2">Check 2</label>
          <input type="checkbox" id="check3" /><label for="check3">Check 3</label>
       </div>
       <h3>Buttons with events</h3>
       <button class="enableDisable">Enable/Disable</button>
    </body>
    </html>
    
  2. 将以下 jQuery 代码添加到 recipe-1.js 中,以将 UI 样式和功能应用于按钮元素:

    $(function(){
       //Default buttons
       $('a, button, input[type=submit]').button();
       //Button options
       $('#button4').button('option', 'disabled', true);
       $('#button5').button({label: 'Button 5 with custom label'});
       $('#button6').button('option', 'icons', {primary: 'ui-icon-arrowthick-1-e', secondary: 'ui-icon-circle-arrow-e'});
       //Button sets
       $('.buttonSet1').buttonset();
       $('.buttonSet2').buttonset();
       //Button events
       $('.enableDisable').button().click(function(){
          var _button4 = $('.button4');
          if (_button4.button('option', 'disabled')) {
             _button4.button('option', 'disabled', false);
          } else {
             _button4.button('option', 'disabled', true);
          }
       });
    }); 
    
  3. 在 Web 浏览器中打开 recipe-1.html,您将看到用默认 jQuery UI 主题样式化的各种按钮元素。如何做…

工作原理…

HTML 提供了一系列不同的按钮元素,可以通过 jQuery UI 按钮 API 使用。通过查看此网页,您将能够了解以下元素的工作原理,并在需要时重新使用代码:

  • 包括 ainputbutton 元素的默认按钮

  • 默认按钮及其选项,如自定义标签、图标和禁用

  • 允许复选框和单选按钮功能的按钮集

  • 按钮上的事件

要初始化 jQuery UI 按钮 API,请以典型的 jQuery 方式选择按钮或一组按钮元素,并使用 button() 函数,如下所示:

$('a, button, input[type=submit]').button();

这将为所选按钮应用 jQuery UI CSS 和附加功能。button() 函数还接受一系列选项,以便您可以单独操作按钮元素。这在 recipe-1.js 中的 Button options 部分中显示。

通过在 HTML 代码中分组按钮,并使用 buttonset() 函数,您可以创建一组按钮,这些按钮共同形成复选框或单选按钮功能,如下所示:

<div class="buttonSet1">
   <button>One</button>
   <button>Two</button>
   <button>Three</button>
</div>

您仍然可以使用正常的 jQuery 与 HTML 按钮元素进行交互,以附加事件并执行操作。使用此配方,标记为启用/禁用的按钮具有附加的点击事件处理程序,如下所示:

$('.enableDisable').button().click(function(){
   var _button4 = $('.button4');
   if (_button4.button('option', 'disabled')) {
      _button4.button('option', 'disabled', false);
   } else {
      _button4.button('option', 'disabled', true);
   }
});

这使用了 jQuery UI 提供的 button('option') 功能来检查按钮的禁用状态,然后根据其当前状态将其设置为 truefalse。在打开的 Web 浏览器中的 recipe-1.html 中,单击此按钮将视觉上启用和禁用标记为按钮 4的按钮。请注意,在上面的示例中,可以在 button() 函数后方便地链接 click() 函数。

还有更多内容…

jQuery UI 库提供了更多类型的按钮。转到其网站提供的文档(jqueryui.com/button/)了解简单示例和更多详细信息。

另请参阅

  • 为用户信息和输入创建对话框

为用户信息和输入创建对话框

在第六章,用户界面中,您已经学会了如何创建自己的模态弹出窗口。jQuery UI 提供了一个易于使用的 API,帮助您快速地向应用程序添加模态或对话框。这个配方将研究 jQuery UI 对话框的默认行为,并向您展示如何使用它们。再次强调,这个配方旨在让您能够轻松找到所需的代码,并在方便时重用它。

准备工作

chapter9 文件夹中,创建 recipe-2.htmlrecipe-2.js 并打开它们以供编辑。

如何做…

要了解如何快速向应用程序添加对话框或模态,请执行以下步骤:

  1. 将以下 HTML 添加到 recipe-2.html 中,以便在 JavaScript 代码中使用按钮和对话框元素:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Chapter 9 :: Recipe 2</title>
       <script src="img/jquery.min.js"></script>
       <script src="img/jquery-ui-1.10.3.custom.min.js"></script>
       <link type="text/css" rel="stylesheet" href="jquery-ui/css/ui-lightness/jquery-ui-1.10.3.custom.min.css" />
       <script src="img/recipe-2.js"></script>
    </head>
    <body>
    <div class="actions">
       <button id="openSecondDialog">Open Second Dialog with Animation</button>
       <button id="openModalDialog">Open Modal Dialog</button>
       <button id="openConfirmationDialog">Open Confirmation Dialog</button>
    </div>
    <div id="default-dialog" title="Default Dialog">
       <p>This is a dialog with default behaviour.</p>
    </div>
    <div id="second-dialog" title="Second Dialog">
       <p>This is a dialog with animation that is opened by a button.</p>
    </div>
    <div id="modal-dialog" title="Modal Dialog">
       <p>This is a modal dialog.</p>
    </div>
    <div id="confirmation-dialog" title="Confirmation Dialog">
       <p>Are you sure you want to close this dialog?</p>
    </div>
    </body>
    </html>
    
  2. 将以下 JavaScript 代码添加到 recipe-2.js 中,以初始化打开对话框的对话框元素和按钮:

     $(function(){
       //Set up the dialog elements
       $('#default-dialog').dialog();
       $('#second-dialog').dialog({
          autoOpen: false,
          show: {
             effect: "fade",
             duration: 500
          },
          hide: {
             effect: "explode",
             duration: 1000
          }
       });
       $('#modal-dialog').dialog({
          autoOpen: false,
          modal: true
       });
       $('#confirmation-dialog').dialog({
          autoOpen: false,
          resizable: false,
          buttons: {
             "Yes": function() {
                $(this).dialog("close");
             },
             "No": function() {
                alert("Your dialog will stay open.");
             }
          }
       });
       //Set up button elements
       $('.actions').buttonset();
       $('#openSecondDialog').click(function(){
          $('#second-dialog').dialog("open");
       });
       $('#openModalDialog').click(function(){
          $('#modal-dialog').dialog("open");
       });
       $('#openConfirmationDialog').click(function(){
          $('#confirmation-dialog').dialog("open");
       });
    });
    
  3. 在 Web 浏览器中打开 recipe-2.html,您将看到默认对话框已经打开。使用按钮集中的按钮打开各种其他对话框类型。

工作原理…

与前面的食谱一样,HTML 代码创建了 jQuery UI 库将用于应用所需功能和样式的元素。页面中有四个对话框元素和三个按钮,用于打开附加对话框。

JavaScript 代码依次初始化每个对话框元素,提供不同的选项和设置。第一个对话框元素#default-dialog通过简单地使用以下 jQuery UI 代码而不使用任何选项进行初始化:

$('#default-dialog').dialog();

这将把#default-dialog HTML 元素转换为 jQuery UI 对话框,并在屏幕上显示它。

第二个对话框初始化时,autoOpen选项设置为false,因此当用户首次访问页面时不会自动打开。要打开此对话框,用户必须单击标有Open Second Dialog with Animation的按钮。第二个对话框提供了一些动画选项,如下所示:

$('#second-dialog').dialog({
   autoOpen: false,
   show: {
   effect: "fade",
   duration: 500
},
hide: {
   effect: "explode",
    duration: 1000
   }
});

这将确保在打开对话框时使用淡入动画,并在关闭对话框时使用爆炸动画。阅读 jQuery UI 对话框文档(api.jqueryui.com/dialog/),以发现可用的动画效果。

第三个对话框是一个模态对话框。只需在打开模态时将modal: true选项添加到dialog()函数中,即可添加一个遮罩,遮挡页面的其余部分视图。

本食谱中的第四个对话框是一个确认对话框。使用按钮选项,您可以指定一些按钮和回调来保存按钮操作,如下所示:

$('#confirmation-dialog').dialog({
   autoOpen: false,
   resizable: false,
   buttons: {
   "Yes": function() {
      $(this).dialog("close");
   },
   "No": function() {
      alert("Your dialog will stay open.");
      }
   }
});

resize选项设置为false,以覆盖允许用户更改对话框大小的默认行为。

更多内容...

通过阅读文档(api.jqueryui.com/dialog/),您将发现更多可供选择的对话框类型。表单对话框特别有用,可以快速检索用户输入,并具有内置的验证功能。

另请参阅

  • 创建时尚和功能性按钮

在您的应用程序中实现进度条

进度条允许用户详细了解应用程序正在执行的过程。进度条是更新用户请求的任务进度的理想解决方案,该任务可能需要很长时间才能完成。此操作可以是文件上传或其他耗时的服务器端进程。本食谱将向您展示如何使用 jQuery UI 进度条 API 轻松地将进度条添加到您的应用程序中。

准备工作

在您之前创建的chapter9文件夹中创建recipe-3.htmlrecipe-3.jsrecipe-3.css

如何实现...

学习如何快速将进度条添加到您的应用程序中,执行以下步骤:

  1. 将以下 HTML 代码添加到recipe-3.html中,以创建具有所需进度条 HTML 元素的网页:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Chapter 9 :: Recipe 3</title>
       <script src="img/jquery.min.js"></script>
       <script src="img/jquery-ui-1.10.3.custom.min.js"></script>
       <link type="text/css" rel="stylesheet" href="jquery-ui/css/ui-lightness/jquery-ui-1.10.3.custom.min.css" />
       <link type="text/css" rel="stylesheet" href="recipe-3.css" />
       <script src="img/recipe-3.js"></script>
    </head>
    <body>
    <div class="progress-bar"><div class="progress-label">Press "Start Progress" to begin load...</div></div>
    <button class="start-progress">Start Progress</button>
    </body>
    </html>
    
  2. 为了为进度条标签提供一些基本样式,将以下 CSS 代码添加到 recipe-3.css 中:

    .progress-bar {
       position: relative;
    }
    .progress-label {
       position: absolute;
       left: 0;
       top: 0;
       right: 0;
       bottom: 0;
       text-align: center;
       line-height: 35px;
    }
    
  3. 将以下 JavaScript 代码添加到 recipe-3.js 中,以初始化进度条并为开始进度按钮提供功能:

    $(function(){
       var progressBar = $('.progress-bar');
       var progressLabel = $('.progress-label');
       progressBar.progressbar({
          change: function() {
             progressLabel.text(progressBar.progressbar("value") + "% complete...");
          },
          complete: function() {
             progressLabel.text("Completed!");
          }
       });
       $('.start-progress').button().click(doStuff);
       function doStuff() {
          var progressValue = ((progressBar.progressbar("value") || 0) + 1);
          progressBar.progressbar("value", progressValue);
          if (progressValue < 100) {
             setTimeout(doStuff, 100);
          }
       }
    });
    
  4. 在网页浏览器中打开 recipe-3.html,然后单击开始进度按钮。进度条将开始显示进度,直到达到 100%。如何操作…

工作原理…

HTML 页面创建了两个元素,jQuery UI 将使用它们来创建进度条和标签:

<div class="progress-bar"><div class="progress-label">Press "Start Progress" to being load...</div></div>

默认的标签文本被添加到标签元素中,在用户首次访问网页时将显示。网页还添加了一个开始进度按钮,以便用户可以启动加载操作。

本示例中的加载操作只是一个虚假过程。您可以轻松地将此代码与 XmlHttpRequest 结合使用,用于图像上传,例如在 第八章 的从头开始编码图像裁剪插件配方中使用的代码,理解插件开发

要初始化添加到 HTML 页面中的 progress-bar 元素中的进度条,使用 progressbar() 函数:

progressBar.progressbar({
   change: function() {
   progressLabel.text(progressBar.progressbar("value") + "% complete...");
   },
   complete: function() {
      progressLabel.text("Completed!");
   }
});

提供一个具有两个属性的对象给此函数设置更改和完成事件回调函数。这使我们能够在进度值发生变化时执行操作,以及在进度完成时执行操作。在本示例中,我们只是更新进度标签,以通知用户完成的百分比值。确保您阅读文档 (jqueryui.com/progressbar/),以便您了解所有可用的选项。

使用 progressBar.progressbar("value"),可以从进度条元素中检索进度值。然后可以使用该值来更新进度标签文本。

当用户单击开始进度按钮时调用的 doStuff() 函数作为进度。它使用 setTimeout() 每 100 毫秒调用自身,然后按如下方式增加进度条值:

var progressValue = ((progressBar.progressbar("value") || 0) + 1);
progressBar.progressbar("value", progressValue);

另请参阅

  • 从头开始编码图像裁剪插件 配方在 第八章 中,理解插件开发

快速向输入框添加日期选择器界面

日期选择器为用户提供了一个易于使用的界面,以便他们快速选择所需的日期。jQuery UI 提供了一个可以快速添加到输入字段的日期选择器。日期选择器提供了许多配置选项,如日期格式化和限制,使开发人员更容易根据需要限制用户的输入。本示例将向您展示如何将日期选择器添加到两个输入字段中,更改日期选择器的日期格式,并为每个字段应用日期限制。

准备就绪

与前一个示例一样,在之前创建的 chapter9 文件夹中创建 recipe-4.htmlrecipe-4.jsrecipe-4.css

如何操作…

按照以下每个步骤创建一个简单的界面,其中包含两个日期选择器和配置选项:

  1. 将以下 HTML 代码插入到 recipe-4.html 中,以创建带有日期选择器元素的基本网页和用户界面:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Chapter 9 :: Recipe 4</title>
       <script src="img/jquery.min.js"></script>
       <script src="img/jquery-ui-1.10.3.custom.min.js"></script>
       <link type="text/css" rel="stylesheet" href="jquery-ui/css/ui-lightness/jquery-ui-1.10.3.custom.min.css" />
       <link type="text/css" rel="stylesheet" href="recipe-4.css" />
       <script src="img/recipe-4.js"></script>
    </head>
    <body>
       <div class="frame">
          <div class="settings">
             <label>Restrict:</label>
             <select class="restrict">
                <option value="1">1 Year</option>
                <option value="2">2 Years</option>
                <option value="3">3 Years</option>
            </select>
            <label>Format:</label>
            <select class="formatDate">
               <option value="dd/mm/yy">English Format</option>
               <option value="mm/dd/yy">American Format</option>
             </select>
          </div>
          <div class="datepickers">
             Start: <input type="text" class="start" />
             End: <input type="text" class="end" />
          </div>
       </div>
    </body>
    </html>
    
  2. 添加以下 CSS 到 recipe-4.css,以为用户界面提供基本样式和定位:

    .frame {
       width: 500px;
       margin: 100px auto auto auto;
       background-color: #494949;
       border-radius: 5px;
       box-shadow: 5px 5px 5px #CCC;
    }
    .frame .settings {
       line-height: 40px;
       text-align: center;
       background-color: #333;
       color: #FFF;
       border-top-left-radius: 5px;
       border-top-right-radius: 5px;
    }
    .frame .datepickers {
       line-height: 100px;
       text-align: center;
       color: #CCC;
    }
    
  3. 添加以下 jQuery 代码到 recipe-4.js,以设置日期选择器元素并为 recipe-4.html 中的其他元素提供功能:

    $(function(){
       var _start = $('.start');
       var _end = $('.end');
       var _restrict = $('.restrict');
       var _formatDate = $('.formatDate');
       var _dateFormat = 'dd/mm/yy';
       _start.datepicker({
          dateFormat: _dateFormat,
          minDate: new Date(),
          onClose: function(selectedDate) {
             _end.datepicker("option", "minDate", selectedDate);
             restrictDates();
          }
       });
       _end.datepicker({
          dateFormat: _dateFormat,
          onClose: function(selectedDate) {
             _start.datepicker("option", "maxDate", selectedDate);
          }
       });
       _formatDate.change(function(){
          _dateFormat = _formatDate.val();
          _start.datepicker("option", "dateFormat", _dateFormat);
          _end.datepicker("option", "dateFormat", _dateFormat);
       });
       _restrict.change(function(){
          restrictDates();
       });
       function restrictDates() {
          var maxDate = _start.datepicker("getDate");
          if (maxDate != null) {
          maxDate.setFullYear(maxDate.getFullYear() + parseInt(_restrict.val()));
          _end.datepicker("option", "maxDate", maxDate);
    }
       }
    });
    
  4. 在 Web 浏览器中打开 recipe-4.html,您将看到一个简单的界面,其中包含两个输入和两个下拉菜单。标记为 startend 的两个输入在您点击输入字段时会为您提供一个日期选择器界面。然后,您可以使用日期选择器选择要插入到相关输入中的日期。通过使用两个下拉菜单,您可以更改日期和日期选择器的行为。格式选项将日期格式更改为英文或美式。限制下拉菜单将允许您选择结束日期选择器允许用户选择的最大年数,超过所选开始日期。

工作原理…

HTML 和 CSS 为我们提供了一个简单的界面,可与 jQuery UI 结合使用,以演示一些日期选择器的功能。在 recipe-4.js 的顶部,有一些变量保存了将由 jQuery 使用的不同 HTML 元素的引用,以及保存了英文日期格式的变量。

要为输入元素添加日期选择器,需要使用 jQuery UI 的 datepicker() 函数以及所需的选项:

_start.datepicker({
   dateFormat: _dateFormat,
   minDate: new Date(),
   onClose: function(selectedDate) {
      _end.datepicker("option", "minDate", selectedDate);
      restrictDates();
   }
});

dateFormat 选项设置所选日期选择器的格式。minDate 选项设置日期选择器允许用户选择的最小日期;使用 new Date() 来将此限制设置为当前日期。在关闭日期选择器后将执行指定的 onClose 函数。在此函数中,为结束输入设置了 minDate 选项。这将确保用户无法选择早于所选开始日期的结束日期。restrictDates() 函数也在此处被调用。restrictDates() 函数定义如下:

function restrictDates() {
   var maxDate = _start.datepicker("getDate");
   if (maxDate != null) {
      maxDate.setFullYear(maxDate.getFullYear() + parseInt(_restrict.val()));
      _end.datepicker("option", "maxDate", maxDate);
   }
}

此函数对结束日期选择器应用限制,使用户无法选择比所选开始日期大 n 年的结束日期。这里,n限制下拉菜单指定的值。就像设置 minDate 一样,设置 maxDate 使用的是所选开始日期加上指定年数的数量。当用户更改下拉菜单选择时,也会使用 change() 函数调用此函数。

当用户选择更改日期格式时,以下代码用于更新每个日期选择器元素的格式:

_formatDate.change(function(){
   _dateFormat = _formatDate.val();
   _start.datepicker("option", "dateFormat", _dateFormat);
   _end.datepicker("option", "dateFormat", _dateFormat);
});

日期选择器 API 的一部分提供了许多选项。阅读文档 (api.jqueryui.com/datepicker/) 以了解其他可用选项。

创建自动完成搜索功能

本配方将向用户建议搜索词,当他们在搜索输入框中输入时。这是一个非常受欢迎的功能,对用户非常有帮助,因为它在用户甚至还没有进行搜索之前就提供了一些关于搜索结果的见解。jQuery UI 提供了可以快速添加到任何输入元素中的自动完成功能。

准备工作

在你保存其他配方文件的 chapter9 文件夹中创建 recipe-5.htmlrecipe-5.jsrecipe-5.css

本配方利用了 Trakt.tv 提供的高质量 API(trakt.tv/api-docs/)。在开始本配方之前,你需要注册(免费)并获取一个 API 密钥。一旦注册成功,你可以在以下页面找到你的 API 密钥:trakt.tv/api-docs/authentication

注意

在编写本配方时,已知 Google Chrome 中存在一个已知的错误,在该错误中,如果你尝试从本地机器(即使用 file:// 而不是 http(s):// 访问 recipe-5.html)调用 AJAX 中的 jQuery 来调用外部源,你可能会收到一个 Access-Control-Allow-Origin 错误。如果你遇到了这个问题,要么通过 web 服务器提供你的配方文件,要么使用其他浏览器。

为了演示自动完成功能如何在真实情境中使用,本配方将使用上述 API 创建相关的电视节目搜索。它将允许用户搜索一个电视节目(并通过自动完成提供建议),一旦用户选择了一个,与所选节目相关的节目将被显示。

如何操作...

要添加自动搜索功能,请执行以下操作:

  1. 将以下 HTML 代码添加到 recipe-5.html 中,以创建基本的网页:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Chapter 9 :: Recipe 5</title>
       <script src="img/jquery.min.js"></script>
       <script src="img/jquery-ui-1.10.3.custom.min.js"></script>
       <link type="text/css" rel="stylesheet" href="jquery-ui/css/ui-lightness/jquery-ui-1.10.3.custom.min.css" />
       <link type="text/css" rel="stylesheet" href="recipe-5.css" />
       <script src="img/recipe-5.js"></script>
    </head>
    <body>
    <div class="frame">
       <h1>RELATED <span>TV</span> SHOWS</h1>
       <div class="head">
          <p>Find TV shows related to your favorites.</p>
          <div class="search-input-frame">
             <input type="text" id="searchInput" placeholder="Search for a TV show..." />
       </div>
       </div>
       <div class="results">
          <div class="searching">Searching for related shows...</div>
          <ul id="results-list"></ul>
       </div>
    </div>
    </body>
    </html>
    
  2. 将以下 CSS 放置在 recipe-5.css 中,将 HTML 代码转换成一个具有吸引力的网页:

    @import url(http://fonts.googleapis.com/css?family=Roboto:400,300,100);
    body {
       background-color: #333;
       font-family: 'Roboto', sans-serif;
    }
    .frame {
       width: 800px;
       background-color: #FFF;
       margin: 100px auto auto auto;
       padding: 20px;
       border-radius: 5px;
    }
    .frame h1 {
       margin: -93px 0 0 0;
       color: #FFF;
       font-size: 70px;
       text-align: center;
    }
    .frame h1 span {
       color: #00B5B5;
    }
    .search-input-frame #searchInput {
       width: 780px;
       border: none;
       font-weight: bold;
       color: #999;
       background: #373737;
       font-size: 14px;
       height: 40px;
       padding: 0 0 0 10px;
       margin: 0;
       border-radius: 5px;
       line-height: 40px;
    }
    .frame .head p {
       font-style: italic;
       text-align: center;
    }
    .frame .results ul {
       list-style: none;
       margin: 10px 0 0 5px;
       padding: 0;
    }
    .frame .results ul li {
       line-height: 30px;
       font-size: 18px;
    }
    .frame .results .searching {
       display: none;
       text-align: center;
       font-style: italic;
       font-size: 18px;
       line-height: 100px;
    }
    .frame .results ul li.no-results {
       line-height: 100px;
       text-align: center;
       font-size: 16px;
       font-weight: bold;
    }
    
  3. 将以下 jQuery 添加到 recipe-5.js 中,以初始化搜索输入元素上的自动完成功能:

    $(function(){
       $('#searchInput').autocomplete({
          minLength: 2,
          source: function(input, response) {            
       },
       select: function (event, ui) { 
       }
       });
    });
    
  4. 在你刚刚添加的源函数中插入以下代码,根据用户的输入调用 Trakt.tv API,以提供自动完成功能所需的数据。确保你将 [API KEY HERE] 替换为你的 Trakt.tv API 密钥,如下所示:

    $.ajax({
    type: 'GET',
    url: 'http://api.trakt.tv/search/shows.json/[API KEY HERE]?query=' + input.term + "&limit=10",
    dataType: 'jsonp',
    success: function(data) {
       var results = [];
    for (var i = 0; i < data.length; i++) {
    results.push({
    id: data[i].tvdb_id,
    label: data[i].title,
    value: data[i].title
       });
       }
       response(results);
    }
    });
    
  5. 为了基于用户的自动完成部分填充主要结果列表,将以下 jQuery 代码添加到你刚刚添加的 select 函数中。再次记得用你的 API 密钥替换 [API KEY HERE]

    var showId = ui.item.id;
    var _searchingMsg = $('.searching');
    var _resultList = $('#results-list');
    _resultList.empty();
    _searchingMsg.fadeIn();
    $.ajax({
    type: 'GET',
       url: 'http://api.trakt.tv/show/related.json/[API KEY HERE]/' + showId,
       dataType: 'jsonp',
    success: function(data) {
    _searchingMsg.hide();
    for (var i = 0; i < data.length; i++) {
       resultList.append("<li><a target='_blank' href='" + data[i].url + "'>" + data[i].title + "</a></li>");
    }
    }
    });
    
  6. 在网页浏览器中打开 recipe-5.html,并搜索你最喜欢的电视节目:如何操作...

工作原理...

jQuery UI 自动完成功能将所有复杂性封装起来,以便开发者只需要考虑提供数据和选择后的操作。

这个配方中的 HTML 页面创建了一个用户可以在其中进行搜索的网页。然后在 jQuery 代码中选择此输入,并使用autocomplete()函数来初始化所选元素上的自动完成功能,如下所示:

$('#searchInput').autocomplete({
   minLength: 2,
   source: function(input, response) {            

},
select: function (event, ui) { 

}
});

在提供给autocomplete()函数的对象上的source属性是显示给用户的下拉菜单中使用的数据。source属性可以是数组、字符串或函数。当source是字符串时,它期望值是提供数据的资源 URL,以期望的格式提供数据。因为我们使用的是一个不会提供期望格式数据的外部 API,所以我们使用第三个选项,并在函数内进行一些额外的处理。minLength属性允许我们控制用户必须输入多少字符才能触发自动完成功能

首先,需要从 Trackt.tv 检索数据。为此,使用熟悉的 jQuery $.ajax()函数:

$.ajax({
   type: 'GET',
   url: 'http://api.trakt.tv/search/shows.json/[API KEY HERE]?query=' + input.term + "&limit=10",
   dataType: 'jsonp',
   success: function(data) {

}
});

source()函数接受两个参数:input(对象)和response(函数)。使用input.term,我们可以获取用户输入到搜索输入框中的值,并将其插入到 API URL 中以搜索电视节目。限制查询字符串变量被设置为10,以便只返回 10 个结果。

注意,这个配方中的两个 AJAX 请求的dataType属性都被设置为jsonp。这是为了在与 API 一起工作时防止任何跨域问题。在www.jquery4u.com/json/jsonp-examples/上阅读更多关于 jQuery 的 JSONP 的信息。

如果请求成功,我们可以遍历所有结果并创建一个以自动完成功能期望的格式的数组,如下所示:

var results = [];
for (var i = 0; i < data.length; i++) {
   results.push({
      id: data[i].tvdb_id,
      label: data[i].title,
      value: data[i].title
});
}
response(results);

调用response()函数,这是source()函数的第二个参数;这将把结果发送给自动完成功能以显示。

在这些配方中,下一段功能发生在用户从自动完成建议列表中选择选项时。在提供给autocomplete()函数的对象上的select属性接受一个回调函数,当用户做出选择时执行。使用ui参数,然后可以从表示用户选择的对象中检索数据。在这种情况下,我们需要 ID,以便我们可以将其传递回到 Trackt.tv API,并检索相关的电视节目列表:

var showId = ui.item.id;

这个变量被用作另一个$.ajax()请求的一部分。在这个请求成功后,结果将被循环遍历,并且为每个相关的电视节目插入一个列表项。还会添加一个链接到 Trakt.tv 网页,显示更多关于每个节目的信息,如下所示:

for (var i = 0; i < data.length; i++) {
   resultList.append("<li><a target='_blank' href='" + data[i].url + "'>" + data[i].title + "</a></li>");
}

另见

  • 在 [第三章 使用 AJAX 和 JSON 加载和操作动态内容中创建自动建议功能] 这个示例

第十章:使用 jQuery Mobile

在本章中,我们将涵盖以下主题:

  • 创建基本的移动网站模板

  • 构建完整的静态网站

  • 构建动态移动网站

  • 实现快速呼叫功能

  • 实现发送短信功能

  • 添加移动友好的列表

  • 使用面向触摸的事件

  • 创建移动兼容表单

  • 构建完整的注册和登录系统

  • 构建完整的移动 Web 应用程序

介绍

jQuery Mobile 是一个精心设计的框架,旨在使创建移动友好的网站和应用程序更容易。jQuery Mobile 结合了为移动体验量身定制的可主题化 UI 元素,并提供了针对触摸屏设备上特殊事件的自定义事件。

本章介绍了 jQuery Mobile 并深入了解其功能。在本章中,您将学习如何创建一个利用常见元素(如按钮和列表)的基本移动网站。然后,您将继续学习一些移动特定功能,如触摸呼叫

在开始本章之前,请确保您已从 jQuery 网站(jquerymobile.com/download)下载了最新版本的 jQuery Mobile 框架。创建一个名为chapter10的文件夹,用于保存本章的所有配方文件。在此文件夹中,创建一个名为jquery-mobile的文件夹,并将主要的 jQuery Mobile JavaScript 和 CSS 文件放入其中,包括images文件夹,其中包含 CSS 中引用的所有图标精灵。

本章使用的 jQuery Mobile 版本是 1.3.2,但大多数配方也适用于更新版本。

对于本章中的一些配方,您将需要运行 PHP 和 MySQL 的 Web 服务器。该 Web 服务器可以是本地开发服务器,也可以是托管在云中的服务器。您还需要访问 MySQL 管理界面,如 PHPMyAdmin,以便运行 SQL 脚本。

创建基本的移动网站模板

这个配方将展示一个简单的 jQuery Mobile 网页的基本布局是什么样的。您还将能够将此 HTML 页面用作未来 jQuery 移动项目的模板。

准备工作

在您之前创建的chapter10文件夹中,创建recipe-1.html

如何操作…

将以下 HTML 代码插入到recipe-1.html中,以创建一个非常基本的 jQuery Mobile 单页网站:

<!DOCTYPE html>
<html>
<head>
    <title>Chapter 10 :: jQuery Mobile Template</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="jquery-mobile/jquery.mobile.min.css" />
    <script src="img/jquery.min.js"></script>
    <script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page">
    <header data-role="header">
        <h1>Chapter 10 :: Recipe 1 :: jQuery Mobile Webpage Template</h1>
    </header>
    <div data-role="content">
        <p>This is where your page content will go.</p>
    </div>
    <footer data-role="footer">
        <h4>Look how easy it is to add a styled footer</h4>
    </footer>
</div>
</body>
</html>

确保更新对 jQuery 库和 CSS 的引用,以反映您下载的文件。在 Web 浏览器中打开recipe-1.html,您将看到如何使用 jQuery Mobile 快速创建一个基本的移动友好网页。

工作原理…

乍一看,模板页面与典型的 HTML 网页并没有太大区别。文档中声明了 HTML5 标准化文档类型<!DOCTYPE html>,所需的 CSS 和 JavaScript 包含在文档的头部。

与一般 HTML 页面不同的是,视口的meta标签,并不总是存在。它告诉浏览器如何设置页面的尺寸和缩放级别。如果这些没有被设置,大部分移动设备将使用虚拟宽度,使网页看上去缩小。

注意

data-属性是 HTML5 的新实现,允许自定义元素属性,并仍提供有效的标记。这些data-*属性允许你存储关于特定元素的任意信息,而 jQuery Mobile 利用了这个能力。

在 jQuery Mobile 中,使用data-role属性来指示元素的作用。在这个配方中创建的简单模板中,我们使用了 page、header、content 和 footer 角色来创建简单页面的结构。这些角色都不言而喻,但在本章的过程中也会变得更加清晰。

还有更多…

正如所有 jQuery 实现一样,提供了丰富的文档可供参考(jquerymobile.com),所有开发者都应该加以利用。要充分利用 jQuery Mobile,请确保阅读文档。

参见

  • 创建一个完整的静态网站

创建一个完整的静态网站

这个配方将向你展示如何快速使用 jQuery Mobile 创建一个简单的静态网站。在前一个配方中创建的模板中,只需要添加带有正确角色的附加元素,就能创建额外的页面和它们之间的导航。

准备工作

在之前创建的chapter10文件夹中创建recipe-2.html,并确保你已准备好你新创建的 jQuery Mobile 模板。

如何做…

要使用 jQuery Mobile 创建功能性移动网站,请执行以下步骤:

  1. 将之前创建的 jQuery Mobile 模板复制到recipe-2.html中,并删除<body>标签内的所有内容,如以下代码片段所示:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 10 :: jQuery Mobile Template</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" href="jquery-mobile/jquery.mobile.min.css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/jquery.mobile.min.js"></script>
    </head>
    <body>
    
    </body>
    </html>
    
  2. <body>标签之间插入以下代码,可创建简单静态网站的主页:

    <div data-role="page" id="home">
        <header data-role="header">
            <h1>Home Page</h1>
        </header>
        <div data-role="content">
            <p>This is the content for the home page. You can choose to go to another page using the buttons below.</p>
            <a href="#about" data-role="button" data-theme="a">About</a>
            <a href="#contact" data-role="button" data-theme="a">Contact</a>
        </div>
        <footer data-role="footer">
            <h4>Chapter 10 :: Recipe 2</h4>
        </footer>
    </div>
    
  3. 要创建一个链接到主页的关于页面,请在主页声明后但仍在<body>标签内添加以下代码:

    <div data-role="page" id="about" data-title="About Page">
        <header data-role="header">
            <h1><a href="#home" data-role="button" data-theme="b" data-icon="arrow-l" data-inline="true">Back</a> About Page</h1>
        </header>
        <div data-role="content">
            <p>This is the content for the about page.</p>
        </div>
        <footer data-role="footer">
            <h4>Chapter 10 :: Recipe 2</h4>
        </footer>
    </div>
    
  4. 重复上一步,使用以下代码来添加最终的联系页面:

    <div data-role="page" id="about" data-title="About Page">
        <header data-role="header">
            <h1><a href="#home" data-role="button" data-theme="b" data-icon="arrow-l" data-inline="true">Back</a> About Page</h1>
        </header>
        <div data-role="content">
            <p>This is the content for the about page.</p>
        </div>
        <footer data-role="footer">
            <h4>Chapter 10 :: Recipe 2</h4>
        </footer>
    </div>
    
  5. 在网页浏览器中打开recipe-2.html,你将看到移动网站,并且你可以使用主页上的按钮浏览到关于和联系页面之间。

它是如何运行的…

在这个配方的代码中,你会看到data-role属性被多次使用来指示许多 HTML 元素的功能。要声明多个页面,只需重复使用模板中使用的基本页面结构,并根据需要更改内容。考虑下面的例子:

<div data-role="page" id="about" data-title="About Page">
    <header data-role="header">

    </header>
    <div data-role="content">

    </div>
    <footer data-role="footer">

    </footer>
</div>

这是用于本案例中的关于页面的基本结构。主div元素被指定为使用data-role="page"表示一个页面。为了允许导航到此页面,定义了一个唯一的 ID,就像你会对任何 HTML 元素一样(id="about")。页面分割线上还有data-title属性,使得可以覆盖文档头中的<title>标签的内容,这样就可以根据每页更改页面标题。

您可以使用锚元素创建到此方式创建的页面之一的内部链接,就像下面的代码行所示:

<a href="#about" data-role="button" data-theme="a">About</a>

当用户点击链接时,他们将看到带有唯一 ID about的页面,该 ID 在href属性中表示为#about。默认页面转换也将被用来提供平滑的导航效果。data-role="button"属性用于将元素样式设置为按钮,而data-theme="a"属性指定了要使用的主题样式。阅读上述文件以查看默认可用的主题以及如何创建自己的主题。

参见也

  • 创建基本移动网站模板

  • 构建动态移动网站

构建动态移动网站

在上一个案例中,我们创建了一个基本网站,允许您为用户提供内容并相对容易地手动更新它。在大多数情况下,这是不够的。今天的大多数网站依赖某种形式的数据库,以便定期为它们提供丰富的、新的内容,移动网站也应该一样。本案例将向您展示如何使用 PHP 与 jQuery Mobile 创建动态页面,该页面的内容来自 Web 服务器。

准备工作

您需要在 Web 服务器的 Web 根目录中创建以下目录结构。在下面的图中,www是 Web 根目录;这可能对您来说是不同的:

准备工作

在 Web 服务器的 Web 根目录(www)中,创建一个includes文件夹以及文件index.htmlcategories.php。在includes文件夹中,创建一个名为jquery-mobile的子文件夹,并确保所有 jQuery Mobile 库文件都已复制到其中。此外,在includes文件夹中,创建script.js并添加 jQuery 库(jquery.min.js)。

如何实现…

要使用 PHP 创建一个动态移动网站,请仔细执行以下步骤:

  1. 重新使用作为第一个案例模板的结构,将以下代码添加到index.html。这将创建一个主页和一个 ID 为categorypage的额外空白页面。

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 10 :: Recipe 3</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" href="includes/jquery-mobile/jquery.mobile.min.css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/jquery.mobile.min.js"></script>
        <script src="img/script.js"></script>
    </head>
    <body>
    <div id="home" data-role="page">
        <header data-role="header"><h1>Dynamic page creation demo</h1></header>
        <div data-role="content">
            <h2>Select a category:</h2>
            <a href="#categorypage?cat=colours" data-role="button">Colours</a>
            <a href="#categorypage?cat=shapes" data-role="button">Shapes</a>
            <a href="#categorypage?cat=sounds" data-role="button">Sounds</a>
        </div>
    </div>
    <div id="categorypage" data-role="page">
        <div data-role="header"><h1></h1></div>
        <div data-role="content"></div>
    </div>
    </body>
    </html>
    
  2. 添加以下 PHP 代码到categories.php中,以能够根据 jQuery Mobile 站点上的请求提供内容:

    <?php
    $categories = array(
        "colours" => array(
            "title" => "Colours",
            "description" => "Some of my favorite colours",
            "items" => array(
                "Black",
                "Green",
                "Red",
                "Blue",
                "Purple"
            )
        ),
        "shapes" => array(
            "title" => "Shapes",
            "description" => "Some shapes I really like",
            "items" => array(
                "Triangle",
                "Circle",
                "Square"
            )
        ),
        "sounds" => array(
            "title" => "Sounds",
            "description" => "Some crazy sounds",
            "items" => array(
                "Buzz",
                "Swish",
                "Boom!",
                "Tick"
            )
        )
    );
    if (isset($_POST['category'])) {
        $response = array(
            "success" => true,
            "data" => array()
        );
        $category = $_POST['category'];
        if (isset($categories[$category])) {
            $response["data"] = $categories[$category];
        } else {
            $response["success"] = false;
            $response["data"] = "Invalid category provided";
        }
        header("Content-Type: application/json; charset-UTF-8");
        echo json_encode($response);
    }
    
  3. 为了捕捉用户对动态页面之一的请求,将以下 jQuery 代码添加到script.js,它将监听pagebeforechange事件。这允许我们在用户发送到类别页面之前进行拦截。

    $(document).bind("pagebeforechange", function(e, data) {
        if (typeof data.toPage === "string") {
            var urlObject = $.mobile.path.parseUrl(data.toPage);
            if (urlObject.hash.search(/^#categorypage/) !== -1 && urlObject.hash.search(/cat=*/) !== -1) {
                displayCategory(urlObject, data.options);
                //We are handling the change page event ourselves so prevent the default behaviour
                e.preventDefault();
            }
        }
    });
    
  4. 为了能够生成动态页面,需要从 PHP 脚本中获取内容。在script.js的末尾添加以下 JavaScript 函数,以便发起 AJAX 请求收集这些数据并生成动态页面的标记:

    function displayCategory(urlObject, options) {
        var catName = urlObject.hash.replace(/.*cat=/, "");
        var pageId = urlObject.hash.replace( /\?.*$/, "");
        var _page = $(pageId);
        var _header = _page.children(":jqmData(role=header)");
        var _content = _page.children(":jqmData(role=content)");
        $.ajax({
            url: 'categories.php',
            type: 'POST',
            data: {
                category: catName
            },
            success: function(response) {
                if (response.success) {
                    var category = response.data;
                    //Add title to header
                    _header.find("h1").html(category.title);
                    //Create content HTML
                    var contentHtml = "<p>" + category.description + ":</p><ul>";
                    for (var i = 0; i < category.items.length; i++) {
                        var item = category.items[i];
                        contentHtml += "<li>" + item + "</li>";
                    }
                    contentHtml += "</ul>";
                    _content.html(contentHtml);
                    //Update the URL to reflect the page the user is actually on
                    _page.data("url", urlObject.href);
                    $.mobile.changePage(_page, options);
                } else {
                    alert(response.data);
                }
            }
        });
    }
    
  5. 通过网页浏览器(例如,http://localhost/)访问您新创建的移动网站,您将看到首页,其中提供了三个不同类别的按钮。单击其中一个按钮,将进入新页面,该页面显示的内容是从您刚刚创建的 PHP 脚本提供的。

工作原理...

在此配方中用于创建移动站点的 HTML 代码与之前的静态移动站点几乎没有区别。唯一的区别是只有一个附加页面,没有标题或内容。这是因为附加页面将被重复使用以动态创建多个页面,并且其标题和内容将根据用户请求设置。

index.html中的 HTML 代码创建了带有标签为颜色形状声音的三个按钮的首页。这些按钮中的每一个都是指向相同内部页面的链接,该页面带有一些额外信息,如以下代码行所示:

#categorypage?cat=colours

每个按钮为cat变量提供不同的值,表示不同的类别页面。当用户单击其中一个页面时,默认行为是使 jQuery Mobile 将用户导航到此内部页面。由于我们正在动态创建这些内部页面,因此我们需要拦截此行为,从 PHP 脚本中收集请求的类别内容,然后生成页面。为此,我们绑定到pagebeforechange事件,如下所示:

$(document).bind("pagebeforechange", function(e, data) {
    if (typeof data.toPage === "string") {
        var urlObject = $.mobile.path.parseUrl(data.toPage);
        if (urlObject.hash.search(/^#categorypage/) !== -1 && urlObject.hash.search(/cat=*/) !== -1) {
            displayCategory(urlObject, data.options);
            //We are handling the change page event ourselves to prevent the default behaviour
            e.preventDefault();
        }
    }
});

由于我们只想拦截特定的页面请求,在我们请求动态内容之前,我们执行了一些检查。我们可以从提供给事件处理程序函数的data对象中获取请求 URL。我们首先检查 URL 是否为字符串,如下所示:

if (typeof data.toPage === "string") {

如果是字符串,则按照以下方式解析为 URL 对象:

var urlObject = $.mobile.path.parseUrl(data.toPage);

创建了 URL 对象后,可以执行两个最终检查,以查看请求的页面是否属于类别页面,如下所示:

if (urlObject.hash.search(/^#categorypage/) !== -1 && urlObject.hash.search(/cat=*/) !== -1) {

使用search()函数,可以搜索字符串#categorypage以检查是否正在请求类别页面,然后再次检查是否还提供了一个cat变量。

如果这些检查通过,则调用displayCategory()函数来收集和呈现动态页面的内容。还使用了e.preventDefault()来阻止 jQuery Mobile 在生成具有动态内容之前将用户导航到请求的页面。

displayCategory()函数的顶部,声明了一系列变量,如下所示:

var catName = urlObject.hash.replace(/.*cat=/, "");
var pageId = urlObject.hash.replace( /\?.*$/, "");
var _page = $(pageId);
var _header = _page.children(":jqmData(role=header)");
var _content = _page.children(":jqmData(role=content)");

前两个从请求 URL 获取值,即请求的类别和页面 ID(即#categorypage)。

然后,使用页面 ID 通过典型的 jQuery 选择器从 index.html 中选择页面 DOM 元素。接着,使用 page 元素,可以找到并存储页面标题和内容的 DOM 元素,稍后可以使用标准的 jQuery 进行操作。

然后,使用 jQuery 的 $.ajax() 函数进行 AJAX 请求,向 categories.php 发起 POST 请求,指定了来自请求页面 URL 的 catName 的值。

categories.php PHP 脚本保存一个多维数组,其中存储了三种不同类别的数据。此 PHP 脚本获取了提交的类别并使用 isset() 检查 $categories 数组中是否存在匹配的类别。如果存在,则将 $response 数组的数据值更新为请求的类别的数据。如果没有请求的类别数据,则将 $response 数组的成功值设置为 false 并提供错误消息。

最后,PHP 脚本在将 $response 数组编码为 JSON 并输出之前设置内容类型和字符集。

displayCategory() 函数发起的 AJAX 请求将接收此 JSON 数据并相应处理。

通过检查 response.success 是否为真,可以确定是否有一些数据要显示给请求的类别。如果有,则可以添加页面的标题以及为内容创建的 HTML 代码,如下所示:

var category = response.data;
//Add title to header
_header.find("h1").html(category.title);
//Create content HTML
var contentHtml = "<p>" + category.description + ":</p><ul>";
for (var i = 0; i < category.items.length; i++) {
var item = category.items[i];
contentHtml += "<li>" + item + "</li>";
}
contentHtml += "</ul>";
_content.html(contentHtml);

为确保 URL 反映用户正在查看的页面,使用 jQuery 的 data() 函数设置 categorypage 元素的 url 属性如下:

_page.data("url", urlObject.href);

最后,调用 changePage() 函数将用户导航到新生成的页面,在那里,他们将看到从 PHP 脚本提供的请求内容。changePage() 函数还会插入一个条目到浏览器历史中,以提供典型的浏览器导航行为。

更多信息…

此配方中的 PHP 脚本提供了填充附加类别页面的内容,并将此内容存储在 PHP 数组中。这仅供演示目的,可以轻松地是存储在由 PHP 脚本访问的数据库中的内容。

参见

  • 构建完整的静态网站

实现快速呼叫功能

HTML5 允许开发人员告知浏览器启动应用程序以进行电话呼叫,方式与发邮件类似。本配方将向您展示如何使用 jQuery Mobile 按钮来实现此功能,以便用户点击此按钮时,他们的默认呼叫应用程序将打开,并预填充电话号码。

准备工作

chapter10 文件夹中,创建 recipe-4.html 以供本配方使用。

如何做…

为了让用户能够点击按钮进行电话呼叫,而不必将号码复制粘贴到其通话应用程序中,执行以下简单步骤:

  1. 将以下 HTML 代码添加到 recipe-4.html 中,以重复使用移动网站模板:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 10 :: jQuery Mobile Template</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" href="jquery-mobile/jquery.mobile.min.css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/jquery.mobile.min.js"></script>
    </head>
    <body>
    <div data-role="page">
        <header data-role="header">
            <h1>Chapter 10 :: Recipe 4</h1>
        </header>
        <div data-role="content">
    
        </div>
        <footer data-role="footer">
            <h4>The HTML5 tel: attribute allows you to provide interaction to telephone numbers</h4>
        </footer>
    </div>
    </body>
    </html>
    
  2. 在主页的 content 部分中添加一个具有 tel: 属性的按钮,一旦按下即会启动通话应用程序,如下所示:

    <p>This is my simple mobile website, click the button below to call me!</p>
    <a href="tel: 01234 567891" data-role="button">Call Me!</a>
    
  3. 在 Google Chrome 中打开 recipe-4.html,并点击 Call Me! 按钮,将弹出一个警告,提示该网站正在请求打开外部应用程序。在移动浏览器上打开该网页将会打开您设备的默认通话应用程序,允许您使用按钮元素上指定的号码进行通话。

它是如何工作的…

多年来,mailto: 属性一直可用于允许网站打开用户的默认邮件客户端。以下代码行显示了一个示例:

<a href="mailto:name@domain.com">E-Mail Me</a>

HTML5 允许一些额外的属性以类似的方式工作,以允许额外的功能。tel: 属性是其中之一。支持此属性的浏览器将在用户点击链接时打开设备或计算机上安装的默认通话应用程序。请注意,要打开 Skype,一款流行的 VOIP 应用程序,您可能需要使用一个名为 callto: 的替代属性。

另请参阅

  • 实现发送短信功能

实现发送短信功能

上一个配方介绍了如何直接从您的移动网站拨打电话。让用户轻松发送短信也是一个有用的功能。本配方将向您展示如何添加一个按钮,当点击时将在用户设备上打开默认的短信客户端。

准备工作

在开始本章之前创建的 chapter10 文件夹中创建 recipe-5.html

如何做…

允许用户通过您的移动网站快速发送短信消息非常容易。执行以下简单步骤来了解如何:

  1. 再一次,使用本章第一个配方中创建的 jQuery Mobile 模板,在 recipe-5.html 中创建一个简单的移动网站,使用以下代码:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 10 :: Recipe 5</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" href="jquery-mobile/jquery.mobile.min.css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/jquery.mobile.min.js"></script>
    </head>
    <body>
    <div data-role="page">
        <header data-role="header">
            <h1>Chapter 10 :: Recipe 5</h1>
        </header>
        <div data-role="content">
    
        </div>
        <footer data-role="footer">
            <h4>Use the HTML5 sms: attribute to open the default SMS client on click</h4>
        </footer>
    </div>
    </body>
    </html>
    
  2. recipe-5.html 的主页的 content 部分中添加以下文本和锚元素:

    <p>This is my simple mobile website, click the button below to send me an SMS message!</p>
    <a href="sms:01234 567891" data-role="button">SMS Me!</a>
    
  3. 在移动设备上打开 recipe-5.html,并点击 SMS Me! 按钮。你的默认短信客户端将打开,接收者字段已经填充了 HTML 中指定的号码。

它是如何工作的…

除了 HTML5 提供的新 tel: 属性外,还提供了 sms: 属性。这将告诉兼容的设备使用指定的电话号码打开默认的短信客户端。以下代码行显示了一个示例:

<a href="sms:01234 567891" data-role="button">SMS Me!</a>

此锚元素还具有 data-role 属性和一个按钮的值,以便 jQuery Mobile 为简单按钮添加适当的样式。

还有更多…

除了电话号码外,还可以指定一些文本自动添加到消息正文中;将锚元素更改如下以添加此功能:

<a href="sms:01234 567891?body=This is some text in the body" data-role="button">SMS Me!</a>

另请参阅

  • 实现快速通话功能

添加移动友好的列表

在此食谱书中,有各种利用 HTML 列表以简单有效的方式呈现数据的食谱。jQuery Mobile 允许开发人员快速将移动友好且易于触摸的列表添加到其 jQuery Mobile 网站中。此食谱为您提供了 jQuery Mobile 提供的更常见类型的列表的多个示例。您可以随时复制和重用这些列表的代码。

准备工作

在之前创建的chapter10文件夹中,创建一个名为recipe-6.html的 HTML 文件。

如何做…

要了解如何添加不同类型的移动友好列表,请执行以下步骤:

  1. 通过将以下 HTML 添加到recipe-6.html中,创建一个基本的 jQuery Mobile 网站:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 10 :: Recipe 6</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" href="jquery-mobile/jquery.mobile.min.css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/jquery.mobile.min.js"></script>
    </head>
    <body>
    <div data-role="page">
        <header data-role="header">
            <h1>Chapter 10 :: Recipe 6 :: Lists</h1>
        </header>
        <div data-role="content">
    
        </div>
    </div>
    </body>
    </html>
    
  2. 要创建最常见的列表类型 - 基本链接列表 - 在recipe-6.htmlcontent部分元素中添加以下代码:

    <p>This page contains a selection of list examples for you to reuse at your convenience.</p>
    <h2>Basic linked list</h2>
    <ul data-role="listview">
    <li><a href='#'>Linked Item 1</a></li>
    <li><a href='#'>Linked Item 2</a></li>
    <li><a href='#'>Linked Item 3</a></li>
    </ul>
    
  3. 要创建嵌套列表,请在content部分元素中添加以下 HTML 结构。请注意 HTML 中的注释,为了使此列表正确工作,您需要从 Web 服务器提供recipe-6.html。这样做的原因在本食谱的如何做...部分中给出。

    <h2>Nested list</h2>
    <p>Please note that the sub-list will not work if you have opened recipe-6.html directly in a web browser. For the sub-list navigation to work you must serve this HTML file from a web server. i.e. http://localhost/recipe-6.html.</p>
    <ul data-role="listview">
    <li><a href='#'>Top Level Item 1</a></li>
    <li><a href='#'>Top Level Item 2</a></li>
    <li><a href='#'>Top Level Item 3 - With Sub-Level</a>
    <ul data-role="listview">
    <li><a href='#'>Second Level Item 1</a></li>
    <li><a href='#'>Second Level Item 2</a></li>
    </ul>
    </li>
    </ul>
    
  4. 当在列表中显示内容时,可能需要允许用户以多种方式与每个列表项进行交互。jQuery Mobile 允许开发人员轻松地在列表元素旁边添加带有图标的按钮,以增强其功能性。使用data-split-icon属性将此功能添加到列表中,如下面的代码所示:

    <h2>List items with buttons</h2>
    <ul data-role="listview" data-split-icon="delete">
    <li><a href='#'>Jane Doe</a><a href='#'></a></li>
    <li><a href='#'>John Doe</a><a href='#'></a></li>
    <li><a href='#'>James Mathews</a><a href='#'></a></li>
    </ul>
    
  5. 长列表可能会变得难以导航。jQuery Mobile 允许开发人员快速为任何列表添加过滤选项,使用户可以查找他们需要的列表项。要添加具有此功能的列表,请使用以下代码:

    <h2>List with filter</h2>
    <ul data-role="listview" data-filter="true">
    <li><a href='#'>Cat</a></li>
    <li><a href='#'>Dog</a></li>
    <li><a href='#'>Lizard</a></li>
    <li><a href='#'>Rabbit</a></li>
    </ul>
    
  6. 在 Web 浏览器中打开recipe-6.html将呈现一系列列表示例,如下面的屏幕截图所示,您可以在将来的项目中随时使用:如何做…

工作原理…

使用data-role="listview"属性和值,可以将基本的 HTML 列表转换为移动友好的实现。jQuery Mobile 会自动添加样式,就像按钮和其他元素一样。

如果您参考文档(jquerymobile.com/demos/1.2.1/docs/lists/docs-lists.html),您将获得所有可用列表类型的完整列表以及详细示例。

此食谱中使用的大多数示例都很简单且不言自明。食谱的嵌套列表部分具有一些额外的功能,可能不太明显。对于大多数移动设备,屏幕空间非常有限,特别是在纵向模式下。因此,不允许嵌套列表以传统方式展开(向右展开并具有不同的缩进),如下列表所示是没有意义的:

  • 顶层项目 1

  • 顶层项目 2

  • 顶层项目 3 – 带有子级

    • 第二级项目 1

    • 第二级项目 2

为了节省空间并提供更好的用户体验,当您添加嵌套列表时,jQuery Mobile 将创建一个附加页面,并在其中显示子列表项。当用户选择一个带有列表的列表项时,他们将被带到一个额外的页面,其中显示子级项目。

撰写本食谱时,除非从使用 HTTP 的 Web 服务器提供页面,否则为子级项目创建的附加页面不起作用。

在这个示例中更为强大的一项是能够快速为您的列表添加过滤器。只需在 HTML 列表上添加 data-filter="true" 属性和值,jQuery Mobile 就会自动在列表顶部添加过滤器输入框,允许用户过滤掉不需要的列表项。

使用面向触摸的事件

除了 jQuery 提供的典型事件,如 clickhover,jQuery Mobile 还为开发者提供了触摸中心的事件。使用这些事件,可以为您的移动应用程序添加额外的功能,以适应这些额外的用户交互。本食谱提供了许多有用事件的示例,您可以随时重复使用它们。

准备工作

在您的 Web 服务器的 Web 根目录中,创建 recipe-7.htmlrecipe-7.js

如何做…

要了解可用的触摸中心事件及其用法,请执行以下步骤:

  1. 通过将以下 HTML 添加到 recipe-7.html 来创建一个基本的移动网站,其中包含一个空列表。确保根据需要更新所包含库的引用。

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 11 :: Recipe 1</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" href="includes/jquery-mobile/jquery.mobile.min.css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/jquery.mobile.min.js"></script>
        <script src="img/recipe-7.js"></script>
    </head>
    <body>
    <div data-role="page">
        <header data-role="header">
            <h1>Chapter 10 :: Recipe 7 :: jQuery Mobile Touch Events</h1>
        </header>
        <div data-role="content">
            <p>Perform various touch events and watch the output below.</p>
            <ul id="touch-event-response" data-role="listview"></ul>
        </div>
    </div>
    </body>
    </html>
    
  2. recipe-7.js 的顶部,添加以下函数,该函数将在您刚刚在 recipe-7.html 中创建的列表中添加新的列表项:

    function addEvent(msg) {
        var _list = $('#touch-event-response');
        _list.append("<li>" + msg + "</li>");
        _list.listview('refresh');
    }
    
  3. 要在用户轻触时添加新的列表项,请将以下 JavaScript 代码添加到 recipe-7.js 中:

    $(function(){
        $(document).bind('tap', function(){
            addEvent("Tap");
        });
    });
    
  4. 若要监听 taphold 事件并添加新的列表项,请在 $(function(){}) 块中的前一个 .bind() 语句下直接添加以下代码:

    $(document).bind('taphold', function(){
    addEvent("Tap & Hold");
    });
    
  5. 可以使用相同的方法来监听 swipe 事件。追加以下 .bind() 定义:

    $(document).bind('swipe', function(){
    addEvent("Swipe");
    });
    
  6. 若要在用户向左滑动时清除列表,请追加以下 JavaScript 代码:

    $(document).bind('swipeleft', function(){
    $('#touch-event-response').empty();
    });
    
  7. 最后,要在用户更改设备方向时检测,请在 swipeleft 绑定定义之后添加以下代码:

    $(window).bind('orientationchange', function(event){
    addEvent("Orientation changed to: " + event.orientation);
    });
    
  8. 使用支持移动和触摸的设备,打开 recipe-7.html 并执行一系列触摸事件,以查看添加到列表的适当响应。当您向左滑动时,列表应该被清空,当您改变设备的方向时,将添加一个新的列表项,指示新的方向(纵向或横向)。

工作原理…

通过使用以下代码,可以监听 jQuery Mobile 提供的各种事件:

$(document).bind('[EVENT]', function() {
});

要查看可用的完整事件列表,请阅读 jQuery Mobile 网站上的文档(jquerymobile.com/demos/1.2.1/docs/api/events.html),其中提供了详细的带有示例的全面列表。

在这个食谱中,addEvent()函数接受一个字符串,它将附加到在recipe-7.html中创建的简单移动网站中的列表元素中。当您使用 JavaScript 操作 jQuery Mobile 列表时,您必须调用refresh方法,以确保样式重新应用到新添加的元素上。如以下代码所示:

var _list = $('#touch-event-response');
_list.append("<li>" + msg + "</li>");
_list.listview('refresh');

知道用户何时更改设备的方向可以帮助重新整理页面上的元素,以改善用户体验。通过 jQuery Mobile,这非常容易实现。只需绑定到orientationchange事件,并准备event对象的orientation属性来确定新的方向是什么,如下面的代码所示:

$(window).bind('orientationchange', function(event){
addEvent("Orientation changed to: " + event.orientation);
});

请注意,与本食谱中的其他事件不同,这个事件被绑定到window而不是document,因为document不知道浏览器或设备的方向。

另请参阅

  • 第二章,通过使用 jQuery 事件与用户进行交互

创建兼容移动设备的表单

jQuery Mobile 提供了一系列与 jQuery UI 类似但针对移动设备进行优化的表单组件。本食谱提供了更常用的表单元素的示例,以便您随时重复使用。

准备工作

在您之前创建的chapter10文件夹中,创建 recipe-8.html

如何操作…

要了解 jQuery Mobile 提供了哪些表单元素以及如何使用它们,请执行以下每一步:

  1. 创建一个简单的 jQuery Mobile 网站来存放所有的示例。将以下 HTML 代码添加到recipe-8.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 10 :: Recipe 8</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" href="jquery-mobile/jquery.mobile.min.css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/jquery.mobile.min.js"></script>
    </head>
    <body>
    <div data-role="page" id="home">
        <header data-role="header" data-theme="b">
            <h1>Chapter 10 :: Recipe 8</h1>
        </header>
        <div data-role="content">
        </div>
    </div>
    </body>
    </html>
    
  2. 在您刚刚添加的content区域元素内添加以下代码,以创建一系列文本输入元素:

    <h1>Text Input</h1>
    <div data-role="fieldcontain">
    <label for="textInput">Text input:</label>
    <input type="text" name="textInput" id="textInput" />
    </div>
    <div data-role="fieldcontain">
    <label for="textArea">Text area:</label>
    <textarea id="textArea" name="textArea"></textarea>
    </div>
    <div data-role="fieldcontain">
    <label for="textSearch">Text search:</label>
    <input type="text" name="textSearch" id="textSearch" data-type="search">
    </div>
    
  3. 要创建两种不同类型的选择菜单,请在文本输入下添加以下代码:

    <h1>Select Menu</h1>
    <div data-role="fieldcontain">
    <label for="simpleSelect">Simple select:</label>
    <select id="simpleSelect">
    <option value="1">Option 1</option>
    <option value="2">Option 2</option>
           <option value="3">Option 3</option>
    </select>
    </div>
    <div data-role="fieldcontain">
    <label for="customSelect">Custom select:</label>
    <select id="customSelect" data-native-menu="false">
    <option value="1">Option 1</option>
    <option value="2">Option 2</option>
          <option value="3">Option 3</option>
    </select>
    </div>
    
  4. 要创建复选框和单选按钮,请使用以下代码:

    <h1>Selection</h1>
    <h2>Checkboxes</h2>
    <fieldset data-role="controlgroup">
    <input type="checkbox" name="checkbox-1" id="checkbox-1">
    <label for="checkbox-1">Option 1</label>
    <input type="checkbox" name="checkbox-2" id="checkbox-2">
    <label for="checkbox-2">Option 2</label>
    <input type="checkbox" name="checkbox-3" id="checkbox-3">
    <label for="checkbox-3">Option 3</label>
    </fieldset>
    <h2>Radio buttons</h2>
    <fieldset data-role="controlgroup">
    <input type="radio" name="radio-1" id="radio-1">
    <label for="radio-1">Option 1</label>
    <input type="radio" name="radio-1" id="radio-2">
    <label for="radio-2">Option 2</label>
    <input type="radio" name="radio-1" id="radio-3">
    <label for="radio-3">Option 3</label>
    </fieldset>
    <h2>Inline selection</h2>
    <fieldset data-role="controlgroup" data-type="horizontal">
    <input type="checkbox" name="checkbox-1" id="checkbox-4">
    <label for="checkbox-4">Option 1</label>
    <input type="checkbox" name="checkbox-2" id="checkbox-5">
    <label for="checkbox-5">Option 2</label>
    <input type="checkbox" name="checkbox-3" id="checkbox-6">
    <label for="checkbox-6">Option 3</label>
    </fieldset>
    <fieldset data-role="controlgroup" data-type="horizontal">
    <input type="radio" name="radio-2" id="radio-4">
    <label for="radio-4">Option 1</label>
    <input type="radio" name="radio-2" id="radio-5">
    <label for="radio-5">Option 2</label>
    <input type="radio" name="radio-2" id="radio-6">
    <label for="radio-6">Option 3</label>
    </fieldset>
    
  5. 最后,要创建一些附加元素——开关和滑块——请添加以下代码:

    <h1>Additional</h1>
    <div data-role="fieldcontain">
    <label for="switch">Switch:</label>
    <select id="switch" data-role="slider">
    <option value="1">On</option>
          <option value="0">Off</option>
    </select>
    </div>
    <div data-role="fieldcontain">
    <label for="slider">Slider:</label>
    <input type="number" data-type="range" name="slider" id="slider" value="50" min="0" max="100" data-highlight="true">
    </div>
    
  6. 在网络浏览器中打开recipe-8.html将呈现出一系列不同的表单元素。然后你可以轻松地选择并重复使用任何元素类型的代码,如下面的屏幕截图所示:如何操作…

它是如何工作的…

本食谱中使用的每种类型的 jQuery Mobile 元素在以下各节中都有详细解释。

文本输入

jQuery Mobile 提供了不同的文本输入元素。典型的文本输入和文本区域元素可以通过在div元素内添加标签和inputtextarea元素,并将其放在具有fieldcontain类的div元素内来轻松创建,如以下代码所示:

<div data-role="fieldcontain">
<label for="textInput">Text input:</label>
<input type="text" name="textInput" id="textInput" />
</div>

要创建搜索输入,只需将data-type="search"添加到input元素中。这会向input元素添加一个搜索图标,并在用户输入一些文本后提供清除按钮。

选择菜单

此教程中提供的两个选择菜单在外观上看起来相同。当选择第一个简单示例时,您将获得一个下拉列表,看起来像在一个普通非移动优化网站上的典型选择菜单。

第二个示例添加了额外的data-native-menu="false"属性,一旦单击,将提供不同的选择菜单。这个额外的菜单使得使用触摸界面更容易进行选择。以下屏幕截图对两种类型的选择菜单进行了比较:

Select menu

复选框和单选按钮

使用具有data-role="controlgroup"属性的fieldset元素,非常容易创建复选框和单选按钮,如下面的代码片段所示:

<fieldset data-role="controlgroup">
<input type="checkbox" name="checkbox-1" id="checkbox-1">
<label for="checkbox-1">Option 1</label>
<input type="checkbox" name="checkbox-2" id="checkbox-2">
<label for="checkbox-2">Option 2</label>
<input type="checkbox" name="checkbox-3" id="checkbox-3">
<label for="checkbox-3">Option 3</label>
</fieldset>

要创建一组单选按钮,可以重复使用前面的代码,将type属性更改为radio并确保它们的name属性中都有相同的值。

除了这些界面元素外,jQuery Mobile 还可以提供嵌入式等效物。只需将data-type="horizontal"属性添加到fieldset元素上,就可以获得复选框或单选按钮的嵌入式版本。

额外信息

作为此教程的最后两个元素提供的是一个开关和一个滑块。switch元素实质上是一个只有两个选项的选择菜单,但以更适合触摸的方式呈现。通过将data-type="range"属性添加到数字输入中(如下所示的代码),可以创建slider元素,允许用户轻松地在表单上输入和更改数字值:

<div data-role="fieldcontain">
<label for="slider">Slider:</label>
<input type="number" data-type="range" name="slider" id="slider" value="50" min="0" max="100" data-highlight="true">
</div>

还有更多…

作为此教程的一部分提供的所有示例都显示为默认尺寸。当默认尺寸稍大时,jQuery Mobile 为所有表单元素提供额外的较小尺寸。

要使用小型等效物,将属性data-mini="true"添加到需要较小尺寸的元素中。

建立完整的注册和登录系统

本教程向您展示如何使用 jQuery Mobile 和 PHP 与 MySQL 数据库从头开始创建简单的注册和登录系统。这个教程将为本章的下一个教程中的完整网络应用程序奠定基础。

准备工作

您应该已经准备好一个可用于完成此教程的 PHP 和 MySQL 服务器。在 Web 服务器的 Web 根目录中,创建index2.htmlscript2.js,它们将保存应用程序的主要功能。

如何去做…

要创建完整的注册和登录系统,请确保您仔细遵循以下每个说明:

  1. 将以下 HTML 代码添加到index2.html中,以创建一个简单的 jQuery Mobile 网站和主页:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 10 :: Register & Login</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" href="includes/jquery-mobile/jquery.mobile.min.css" />
        <script src="img/jquery.min.js"></script>
        <script src="img/jquery.mobile.min.js"></script>
        <script src="img/script2.js"></script>
        <link rel="stylesheet" href="styles.css" />
    </head>
    <body>
    <div data-role="page" id="home">
        <header data-role="header" data-theme="b">
            <h1><a href="#home" data-role="button" data-icon="home" data-iconpos="notext" data-inline="true"></a> Home Page</h1>
        </header>
        <div data-role="content">
            <p>Welcome to my community.</p>
            <a data-role="button" href="#login">Login</a>
            <a data-role="button" data-theme="a" href="#register">Register</a>
        </div>
    </div>
    </body>
    </html>
    
  2. 使用以下 HTML 将登录页面添加到index2.html

    <div data-role="page" id="login" data-title="Login">
        <header data-role="header" data-theme="b">
            <h1><a href="#home" data-role="button" data-icon="home" data-iconpos="notext" data-inline="true"></a> Login</h1>
        </header>
        <div data-role="content">
            <div data-role="fieldcontain">
                <label for="login-username">Username:</label>
                <input type="text" name="username" id="login-username" value="" />
            </div>
            <div data-role="fieldcontain">
                <label for="login-password">Password:</label>
                <input type="password" name="password" id="login-password" value="" />
            </div>
            <button data-role="button" id="login-account" data-theme="a">Login</button>
            <p>Don't have an account? <a href='#register'>Register</a>.</p>
        </div>
    </div>
    
  3. 还可以使用以下 HTML 代码创建注册页面,确保将页面代码添加到index2.html中 HTML 文档的body部分中:

    <div data-role="page" id="register" data-title="Register">
        <header data-role="header" data-theme="b">
            <h1><a href="#home" data-role="button" data-icon="home" data-iconpos="notext" data-inline="true"></a> Register</h1>
        </header>
        <div data-role="content">
            <div data-role="fieldcontain">
                <label for="register-username">Username:</label>
                <input type="text" name="username" id="register-username" value="" />
            </div>
            <div data-role="fieldcontain">
                <label for="register-password">Password:</label>
                <input type="password" name="password" id="register-password" value="" />
            </div>
            <div data-role="fieldcontain">
                <label for="register-passwordagain">Password Again:</label>
                <input type="password" name="register-passwordagain" id="register-passwordagain" value="" />
            </div>
            <button data-role="button" id="register-account" data-theme="a">Register</button>
            <p>Already have an account? <a href='#login'>Login</a>.</p>
        </div>
    </div>
    
  4. 最后一个要添加的页面是成员页面。使用以下 HTML 代码创建此页面:

    <div data-role="page" id="member">
        <header data-role="header" data-theme="b">
            <h1><a href="#home" data-role="button" data-icon="home" data-iconpos="notext" data-inline="true"></a> Member's Page</h1>
        </header>
        <div data-role="content">
            <p>You're logged in.</p>
            <button data-role="button" data-theme="a" id="logout">Logout</button>
        </div>
    </div>
    
  5. 使用以下 SQL 代码,在您的 MySQL 数据库中创建名为chapter10的数据库和名为user的表:

    SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
    SET time_zone = "+00:00";
    
    --
    -- Database: `chapter10`
    --
    CREATE DATABASE `chapter10` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
    USE `chapter10`;
    
    -- --------------------------------------------------------
    
    --
    -- Table structure for table `user`
    --
    
    CREATE TABLE IF NOT EXISTS `user` (
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
      `username` varchar(128) DEFAULT NULL,
      `password` varchar(512) DEFAULT NULL,
      UNIQUE KEY `id` (`id`),
      UNIQUE KEY `username` (`username`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=8;
    
  6. 在您的 Web 服务器的 Web 根目录中创建connect.db.php并添加以下 PHP 代码来连接到chapter10数据库。如有需要,请更新数据库用户名和密码。

    <?php
    $mysqli = new mysqli("localhost", "root", "", "chapter10");
    if ($mysqli->connect_errno) {
        die("Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error);
    }
    $pwsalt = "TH1SISF0RCHAPTER10";
    
  7. 为了能够向user表中添加新用户,创建register.php并在您的 Web 服务器的 Web 根目录中添加以下 PHP 代码:

    <?php
    require_once("connect.db.php");
    $username = isset($_POST['username']) ? strtolower($_POST['username']) : "";
    $password = isset($_POST['password']) ? $_POST['password'] : "";
    $passwordAgain = isset($_POST['passwordagain']) ? $_POST['passwordagain'] : "";
    
    $response = array(
        "success" => false,
        "errors" => array()
    );
    
    if (strlen($username) < 3 || strlen($username) > 32) {
        $response["errors"]["username"] = "Username must be between 3 and 64 characters in length";
    } else {
        $query = "SELECT `id` FROM `user` WHERE `username` = ? LIMIT 1";
        $stmt = $mysqli->stmt_init();
        if ($stmt->prepare($query)) {
            $stmt->bind_param("s", $username);
            if ($stmt->execute()) {
                $stmt->store_result();
                if ($stmt->num_rows > 0) {
                    $response["errors"]["username"] = "Username has already been taken";
                }
            } else {
                $response["errors"]["username"] = "Could not execute query";
            }
        } else {
            $response["errors"]["username"] = "Could query database for existing usernames";
        }
        $stmt->close();
    }
    
    if (strlen($password) < 6 || strlen($password) > 32) {
        $response["errors"]["password"] = "Password must be between 6 and 32 characters in length";
    }
    if ($password != $passwordAgain) {
        $response["errors"]["passwordagain"] = "Passwords must match";
    }
    
    if (empty($response["errors"])) {
        $query = "INSERT INTO `user` (`username`, `password`) VALUES (?, ?)";
        $stmt = $mysqli->stmt_init();
        if ($stmt->prepare($query)) {
            $password = crypt($password, $pwsalt);
            $stmt->bind_param("ss", $username, $password);
            if ($stmt->execute()) {
                $stmt->close();
                $response["success"] = true;
            } else {
                $response["errors"]["username"] = "Could not execute query";
            }
        } else {
            $response["errors"]["username"] = "Could not insert new user, please try again";
        }
    }
    $mysqli->close();
    header("Content-Type: application/json; charset=UTF-8");
    echo json_encode($response);
    
  8. 为了允许用户使用他们新创建的帐户登录,创建login.php并在您的 Web 服务器的 Web 根目录中添加以下 PHP 代码:

    <?php
    session_start();
    require_once("connect.db.php");
    $username = isset($_POST['username']) ? strtolower($_POST['username']) : "";
    $password = isset($_POST['password']) ? $_POST['password'] : "";
    
    $response = array(
        "success" => false,
        "error" => "",
        "user" => array()
    );
    
    $query = "SELECT `id` FROM `user` WHERE `username` = ? AND `password` = ? LIMIT 1";
    $stmt = $mysqli->stmt_init();
    if ($stmt->prepare($query)) {
        $password = crypt($password, $pwsalt);
        $stmt->bind_param("ss", $username, $password);
        if ($stmt->execute()) {
            $res = $stmt->get_result();
            if ($res->num_rows > 0) {
                $row = $res->fetch_assoc();
                $response["success"] = true;
                $_SESSION['uid'] = $response["user"]["id"] = $row["id"];
                $_SESSION['username'] = $response["user"]["username"] = $username;
            } else {
                $response["error"] = "Incorrect username or password";
            }
        } else {
            $response["error"] = "Could not execute query";
        }
    } else {
        $response["error"] = "Could not query database";
    }
    $stmt->close();
    $mysqli->close();
    header("Content-Type: application/json; charset=UTF-8");
    echo json_encode($response);
    
  9. 为了实现登出功能,在与login.php相同的目录中创建logout.php并添加以下代码:

    <?php
    session_start();
    $response = array(
        "success" => false,
        "error" => ""
    );
    if (isset($_SESSION["uid"]) && isset($_SESSION["username"])) {
        $_SESSION = array();
        session_destroy();
     $response["success"] = true;
    } else {
        $response["success"] = false;
        $response["error"] = "Not logged in";
    }
    header("Content-Type: application/json; charset=UTF-8");
    echo json_encode($response);
    
  10. 为了允许用户提交他们的注册信息,将以下 JavaScript 代码添加到script2.js的 jQuery 加载块($(function(){});)中:

    $('#register-account').click(function(){
            $('.input-error').remove();
            var data = {
                username: $('#register-username').val(),
                password: $('#register-password').val(),
                passwordagain: $('#register-passwordagain').val()
            };
            $.ajax({
                type: 'POST',
                url: 'register.php',
                data: data,
                beforeSend: function() {
                    $.mobile.loading('show');
                },
                success: function(data) {
                    $.mobile.loading('hide');
                    if (data.success) {
                        $.mobile.showPageLoadingMsg("b", "Registration successful! You may now login.", true);
                    } else {
                        $.each(data.errors, function(key, value){
                            $('#register-' + key).parent().after("<div class='input-error'>" + value + "</div>");
                        });
                    }
                }
            });
        });
    
  11. 当用户尝试从登录页面登录时,将以下 JavaScript 代码添加到script2.js中刚刚为注册添加的代码下面,以对登录进行反应:

    $('#login-account').click(function(){
            var data = {
                username: $('#login-username').val(),
                password: $('#login-password').val()
            };
            $.ajax({
                type: 'POST',
                url: 'login.php',
                data: data,
                beforeSend: function() {
                    $.mobile.loading('show');
                },
                success: function(data) {
                    $.mobile.loading('hide');
                    if (data.success) {
                        $.mobile.showPageLoadingMsg("b", "Login Successful", true);
                        localStorage.setItem("user", JSON.stringify(data.user));
                        $.mobile.changePage("#member");
                    } else {
                        $.mobile.showPageLoadingMsg("b", data.error, true);
                    }
                }
            });
        });
    
  12. 为了让用户能够单击登出按钮并注销,将以下代码添加到script2.js中:

     $('#logout').click(function(){
            $.ajax({
                type: 'POST',
                url: 'logout.php',
                beforeSend: function() {
                    $.mobile.loading('show');
                },
                success: function(data) {
                    $.mobile.loading('hide');
                    if (data.success) {
                        localStorage.removeItem("user");
                        $.mobile.changePage("#home");
                    } else {
                        $.mobile.showPageLoadingMsg("b", data.error, true);
                    }
                }
            });
        });
    
  13. 为了在用户尝试导航到此页面时检查用户是否已登录,添加以下代码以防止访问成员页面:

    $(document).bind("pagebeforechange", function(e, data) {
            if (typeof data.toPage === "string") {
                var urlObject = $.mobile.path.parseUrl(data.toPage);
                if (urlObject.hash.search(/^#member/) !== -1) {
                    if (getUser() === false) {
                        e.preventDefault();
                        $.mobile.showPageLoadingMsg("b", "You must be logged in to access this page", true);
                        setTimeout(function(){
                            $.mobile.hidePageLoadingMsg();
                            $.mobile.changePage("#home");
                        }, 1500);
                    }
                }
            }
        });
    
  14. 前面的代码使用getUser()函数来确定用户是否已登录。将以下函数添加到script2.js的末尾,确保它添加在$(function(){});块之外:

    function getUser() {
        var user = localStorage.getItem("user");
        if (user == null) {
            return false;
        } else {
            return JSON.parse(user);
        }
    }
    
  15. 为了对 Web 服务器的错误消息添加一些基本样式,创建一个名为styles.css的文件,并添加以下 CSS 代码:

    .input-error {
        position: absolute;
        font-size: 10px;
        color: #ff0800;
    }
    
  16. 访问提供index2.html的 Web 服务器将允许您注册一个帐户。如果尝试访问成员页面而未登录,您将收到一条消息,告诉您必须登录,然后将被发送回主页。

工作原理...

本配方中创建的每个代码部分都在接下来的各节中有详细说明。

HTML

index2.html中的 HTML 创建了一个简单的 jQuery Mobile 网站,包括以下四个页面:

  • 主页

  • 注册页面

  • 登录页面

  • 成员页面

主页提供了指向登录和注册页面的链接,每个页面分别链接到对方。成员页面有一个登出按钮,允许用户一旦获得访问成员页面后退出登录。HTML 代码简单,每个元素都在本章的先前配方中有详细说明。

SQL

作为此配方的一部分提供的 SQL 代码可用于创建所需的chapter10数据库和存储用户帐户的user表。

PHP

此配方中创建了四个 PHP 文件。第一个是connect.db.php,它建立与 MySQL 数据库的连接,并包含在其他三个 PHP 文件中。PHP mysqli类用于在此配方中的 PHP 文件中连接和查询 MySQL 数据库。您可以在 PHP.net(www.php.net/mysqli)上找到有关此类的更多信息。

register.php文件通过 POST 请求接收一组值。这些值如下所示:

  • 用户名

  • 密码

  • 再次输入密码

PHP 脚本对所有三个输入执行基本验证,以确保指定的用户名长度在 3 到 32 个字符之间,并且已提供的密码至少为 6 个字符长。它还确保两个密码匹配,并查询数据库以确保请求的用户名尚未被占用。

如果通过了所有验证,将在数据库中插入新用户,然后允许此用户使用指定的详细信息登录。重要的是要注意,密码使用 PHP crypt()函数进行加密,使用默认设置。这是一种简单的加密方法,在生产环境中应使用更强大的加密技术。

login.php脚本通过 POST 请求接收用户名和密码,并查询用户表以查看是否有任何匹配的用户凭据;如果有,将为该用户创建一个 PHP 会话,并将用户对象返回给客户端。

logout.php脚本只是销毁 PHP 会话(如果存在),将用户注销。

这些 PHP 脚本中的每一个都以本配方中多次使用的标准格式返回数据。在每个脚本的顶部,创建一个数组,如以下代码所示:

$response = array(
    "success" => false,
    "errors" => array()
);

如果脚本成功执行且无需输出错误,则成功值更改为true,而errors数组保持为空。对于register.php脚本,当输入之一未通过验证时,将返回一个具有与输入匹配的键的关联数组。以下是一个示例:

$response["errors"]["username"] = "Username has already been taken";

这样,客户端上的 JavaScript 就知道在哪个输入框下放置错误消息,使用户更容易理解他们需要进行哪些更改。

输出响应数组时,它被转换为 JSON 对象,并使用 PHP header()函数适当地设置内容类型和字符集,如以下代码所示:

header("Content-Type: application/json; charset=UTF-8");
echo json_encode($response);

JavaScript

此示例中使用的 JavaScript 简单而且并不新奇。为注册、登录和注销按钮创建了三个 click 事件处理程序。提供给这些事件处理程序的回调函数从相关表单收集数据,并使用 jQuery $.ajax() 函数向 register.phplogin.phplogout.php 脚本分别发出 POST 请求。AJAX 与 jQuery 在 第三章 使用 AJAX 和 JSON 加载和操作动态内容 中已经广泛讨论过。

对于每个 AJAX 请求,beforeSend() 函数用于打开并显示一个旋转图像,向用户指示正在进行请求。在 AJAX 请求成功时,此旋转图像将被移除。以下代码展示了这一点:

$.ajax({
type: 'POST',
url: 'register.php',
data: data,
beforeSend: function() {
$.mobile.loading('show');
},
success: function(data) {
       $.mobile.loading('hide');
// -- HIDDEN CODE
}
});

此外,正如下面的代码所示,在每个 AJAX 请求的 success() 函数中,使用 $.mobile.showPageLoadingMsg() 函数向用户显示消息,无论是出错还是提供关于成功注册的信息:

$.mobile.showPageLoadingMsg("b", "Registration successful! You may now login.", true);

函数的第一个参数是主题,第二个参数是您希望显示的消息,将第三个参数设置为 true 将移除旋转图像,仅显示简单的文本消息。

如前所述,login.php 脚本返回一个表示新登录用户的对象。由于客户端 JavaScript 无法感知 PHP 会话,因此需要将此用户对象存储在本地,以便客户端知道已登录的用户。为此,使用本地存储,如下所示的代码行所示:

localStorage.setItem("user", JSON.stringify(data.user));

本地存储只允许存储字符串,但我们需要存储整个对象。为了解决这个问题,我们将对象转换为 JSON 字符串,然后当从本地存储中检索时再次转换为对象。上述示例使用 JSON.stringify() 函数将用户对象转换为字符串,并将其存储在名为 user 的本地存储中。

然后使用 getUser() 函数来检索并将字符串值转换为对象,如果当前没有登录用户,则返回 false

function getUser() {
    var user = localStorage.getItem("user");
    if (user == null) {
        return false;
    } else {
        return JSON.parse(user);
    }
}

当向销毁服务器会话的 logout.php 脚本发起的 AJAX 调用成功时,也会使用 localStorage.removeItem("user") 来移除客户端上的用户对象。

此示例中 JavaScript 的最后一个元素是限制访问成员页面。请注意,使用客户端代码强制执行的任何限制都可以被具有适当知识的任何用户绕过。这种类型的客户端限制仅用于增强用户体验,并且服务器端始终要求阻止用户无法执行的任何操作。

构建动态移动网站示例中,使用了 jQuery Mobile pagebeforechange 事件来检测用户尝试访问某个页面。在此示例中,使用相同的功能来捕获用户尝试访问成员页面时的情况。然后使用getUser()函数来确定用户是否已登录。如果他们没有登录,则阻止他们导航到成员页面,并在告知他们必须登录才能访问成员页面后将其发送回主页。

还有更多...

目前,要提交网站上的任何表单,用户需要点击或按下相关按钮。为了改进这一点,如果用户可以从表单中的任何输入框中按下 Enter 键或移动设备的等效按钮,则会更有益。

另请参阅

  • 构建动态移动网站

构建完整的移动 Web 应用程序

此示例向您展示了如何创建一个简单但完整的 Web 应用程序,允许注册用户编写可以在所有设备上访问的笔记。笔记应用程序在之前的登录和注册示例的基础上进行扩展,允许已登录用户创建和管理笔记或待办事项清单。

准备工作

在开始此示例之前,请确保您已完成之前的示例构建完整的注册和登录系统。您仍然需要一个运行 PHP 和 MySQL 的 Web 服务器才能完成此示例。

如何做...

要创建一个可以在所有移动设备和桌面设备上访问的完整移动 Web 应用程序,请执行以下步骤:

  1. 要存储用户创建的笔记,需要另一个数据库表。使用以下 SQL 代码在chapter10数据库中创建一个名为note的表:

    CREATE TABLE IF NOT EXISTS `note` (
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
      `user_id` bigint(20) unsigned NOT NULL,
      `text` varchar(2048) DEFAULT NULL,
      `added` datetime DEFAULT NULL,
      UNIQUE KEY `id` (`id`),
      KEY `user_id` (`user_id`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=latin1;
    
    ALTER TABLE `note`
      ADD CONSTRAINT `note_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
    
  2. 虽然在index2.html中定义的大多数页面保持不变,但我们需要更新成员页面,以便有一个按钮将用户带到他们当前的笔记。使用以下 HTML 在index2.html中更新成员页面:

    <div data-role="page" id="member">
        <div data-role="header" data-theme="b">
            <h1><a href="#home" data-role="button" data-icon="home" data-iconpos="notext" data-inline="true"></a> Member's Page</h1>
        </div>
        <div data-role="content">
            <p>Welcome <strong><span class="username"></span></strong>, what would you like to do?</p>
            <a href="#notes" data-role="button" data-inline="true" data-icon="arrow-r">View Notes</a>
            <button data-role="button" data-theme="a" id="logout" data-inline="true" data-icon="delete">Logout</button>
        </div>
    </div>
    
  3. 现在,我们需要创建新按钮将用户带到的笔记页面。使用以下 HTML 代码在index2.html中的成员页面之后创建笔记页面:

    <div data-role="page" id="notes">
        <div data-role="header" data-theme="b">
            <h1><a href="#home" data-role="button" data-icon="home" data-iconpos="notext" data-inline="true"></a> Your Notes</h1>
        </div>
        <div data-role="content">
            <h1>Your Notes <a href="#add-note" data-icon="plus" data-role="button" data-inline="true">Add note</a><a href="#member" data-theme="e" data-icon="back" data-role="button" data-inline="true">Back</a></h1>
            <ul data-role="listview" data-filter="true" id="current-notes" data-icon="delete"></ul>
        </div>
    </div>
    
  4. 有了笔记页面,用户将能够查看他们当前的笔记,因此需要一种方法来创建新的笔记。使用以下 HTML 代码,将创建笔记页面添加到index2.html中:

    <div data-role="page" id="add-note" data-title="Add new note">
        <div data-role="header" data-theme="b">
            <h1>Add new note</h1>
        </div>
        <div data-role="content">
            <textarea id="note-text"></textarea>
            <div class='input-error' style="display: none;" id="note-error"></div>
            <div class="actions">
                <button data-role="button" id="save-new-note" data-theme="a" data-icon="check" data-inline="true">Save</button>
                <a href="#notes" data-role="button" data-theme="e" data-icon="delete" data-inline="true">Cancel</a>
            </div>
        </div>
    </div>
    
  5. 通过创建一个新的数据库表并更新用于附加功能的 HTML UI,我们现在需要创建提供与数据库交互的 PHP。为了让用户创建新的笔记,在您的 Web 服务器的 Web 根目录中创建一个名为addNote.php的文件,并插入以下代码:

    <?php
    session_start();
    
    require_once("connect.db.php");
    $text = isset($_POST['text']) ? $_POST['text'] : "";
    
    $response = array(
        "success" => false,
        "error" => "",
        "note" => array()
    );
    
    if (!isset($_SESSION['uid'])) {
        $response["error"] = "You must be logged in to add a new note";
    } else if (strlen($text) <= 0 || strlen($text) > 1024) {
        $response["error"] = "A note must be between 1 and 1024 characters in length";
    } else {
        $query = "INSERT INTO `note` (`user_id`, `text`, `added`) VALUES (?, ?, ?)";
        $stmt = $mysqli->stmt_init();
        if ($stmt->prepare($query)) {
            $now = date("Y-m-d H:i:s");
            $stmt->bind_param("sss", $_SESSION['uid'], $text, $now);
            if ($stmt->execute()) {
                $stmt->close();
                $response["success"] = true;
                $response["note"] = array(
                    "id" => $mysqli->insert_id,
                    "text" => $text,
                    "added" => $now
                );
            } else {
                $response["error"] = "Could not execute query";
            }
        } else {
            $response["error"] = "Could not insert new note, please try again";
        }
    }
    $mysqli->close();
    header("Content-Type: application/json; charset=UTF-8");
    echo json_encode($response);
    
  6. 要使用用户当前的笔记填充笔记页面,我们需要能够从数据库中检索笔记。创建一个名为getNotes.php的文件,并添加以下 PHP 代码:

    <?php
    session_start();
    require_once("connect.db.php");
    
    $response = array(
        "success" => false,
        "error" => "",
        "notes" => array()
    );
    
    if (!isset($_SESSION['uid'])) {
        $response["error"] = "You must be logged in to add a new note";
    } else {
        $query = "SELECT * FROM `note` WHERE `user_id` = ? ORDER BY `added` DESC";
        $stmt = $mysqli->stmt_init();
        if ($stmt->prepare($query)) {
            $stmt->bind_param("s", $_SESSION['uid']);
            if ($stmt->execute()) {
                $res = $stmt->get_result();
                $response["success"] = true;
                if ($res->num_rows > 0) {
                    while ($row = $res->fetch_assoc()) {
                        $response["notes"][] = array(
                            "id" => $row["id"],
                            "text" => $row["text"],
                            "added" => $row["added"]
                        );
                    }
                }
            } else {
                $response["error"] = "Could not execute query";
            }
        } else {
            $response["error"] = "Could not query database";
        }
        $stmt->close();
    }
    $mysqli->close();
    header("Content-Type: application/json; charset=UTF-8");
    echo json_encode($response);
    
  7. 用户还需要能够删除不需要的笔记。为此,在您的 Web 服务器的 Web 根目录中创建一个名为deleteNote.php的文件,并添加以下代码:

    <?php
    session_start();
    
    require_once("connect.db.php");
    $id = isset($_POST['id']) ? (int)$_POST['id'] : 0;
    
    $response = array(
        "success" => false,
        "error" => ""
    );
    
    if (!isset($_SESSION['uid'])) {
        $response["error"] = "You must be logged in to delete a note";
    } else if ($id <= 0) {
        $response["error"] = "Invalid note ID specified";
    } else {
        $query = "DELETE FROM `note` WHERE `id` = ?";
        $stmt = $mysqli->stmt_init();
        if ($stmt->prepare($query)) {
            $stmt->bind_param("i", $id);
            if ($stmt->execute()) {
                $stmt->close();
                $response["success"] = true;
            } else {
                $response["error"] = "Could not execute query";
            }
        } else {
            $response["error"] = "Could not insert new note, please try again";
        }
    }
    $mysqli->close();
    header("Content-Type: application/json; charset=UTF-8");
    echo json_encode($response);
    
  8. 当所有后端代码都就位后,我们现在可以添加 JavaScript 来将用户界面与这些后端代码联系起来。首先,我们需要对前一个示例中 script2.js 中的原始 JavaScript 代码进行一些更改。在 script2.js 的顶部,但仍然在 jQuery 的加载完成块 $(function(){}); 内部,添加以下一行代码:

    var _currentNotes = $('#current-notes');
    
  9. 在注销 AJAX 调用的 success() 函数中,在 $.mobile.changePage("#home"); 之前添加以下一行代码:

    _currentNotes.data("initialized", false);
    
  10. pagebeforechange 事件处理程序中,我们需要添加一些代码,以便我们可以在成员页面中显示当前登录用户的用户名。更新代码如下,添加 $('.username').html(user.username);

    if (urlObject.hash.search(/^#member/) !== -1) {
    var user = getUser();
    if (user === false) {
          e.preventDefault();
    $.mobile.showPageLoadingMsg("b", "You must be logged in to access this page", true);
    setTimeout(function(){
    $.mobile.hidePageLoadingMsg();
    $.mobile.changePage("#home");
    }, 1500);
    } else {
          $('.username').html(user.username);
    }
    }
    
  11. 在进行所需的 JavaScript 更新后,我们需要添加额外的功能。为了允许用户添加一个新的笔记,将以下代码插入到 script2.js 中,以捕获当用户点击保存笔记按钮时的情况:

    $('#save-new-note').click(function(){
            $('#note-error').hide();
            var _text = $('#note-text');
            $.ajax({
                type: 'POST',
                url: 'addNote.php',
                data: {
                    'text': _text.val()
                },
                beforeSend: function() {
                    $.mobile.loading('show');
                },
                success: function(data) {
                    $.mobile.loading('hide');
                    if (data.success) {
                        _text.val("");
                        _currentNotes.prepend(createNoteItem(data.note));
                        //If the list view has already been initialized then we need to refresh it
                        if (_currentNotes.hasClass('ui-listview')) {
                            _currentNotes.listview('refresh');
                        }
                        $.mobile.changePage("#notes");
                    } else {
                        $('#note-error').html(data.error).fadeIn();
                    }
                }
            });
        });
    
  12. 要填充笔记页面上当前可用的所有笔记,我们需要向 pagebeforechange 事件处理程序添加一些附加功能。将代码更新如下(一些代码已隐藏以示说明):

    $(document).bind("pagebeforechange", function(e, data) {
     if (typeof data.toPage === "string") {
      var urlObject = $.mobile.path.parseUrl(data.toPage);
      if (urlObject.hash.search(/^#member/) !== -1) {
       //HIDDEN CODE – DO NOT REMOVE
      } else if(urlObject.hash.search(/^#notes/) !== -1) {
       if (_currentNotes.data("initialized") != true) {
        e.preventDefault();
        _currentNotes.empty();
        _currentNotes.data("initialized", true);
        $.ajax({
         type: 'GET',
         url: 'getNotes.php',
         beforeSend: function() {
          $.mobile.loading('show');
         },
         success: function(data) {
          $.mobile.loading('hide');
          if (data.success) {
           for (var i = 0; i < data.notes.length; i++) {
            _currentNotes.append(createNoteItem(data.notes[i]));
           }
           //If the list view has already been initialized then we need to refresh it
           if (_currentNotes.hasClass('ui-listview')) {                                       _currentNotes.listview("refresh");
            }
           $.mobile.changePage("#notes");
           } else {
            alert(data.error);
           }
          }
        });
       }
      }
     }
    });
    
  13. 列出的当前可用笔记需要是可点击的,以允许用户删除它们。在 script2.js 中添加以下代码来监听当前笔记列表项的点击,然后发出 AJAX 调用到 deleteNote.php 脚本:

    $(document).on('click', '.delete-note', function(){
            var _listItem = $(this).closest('li');
            var id = _listItem.data("id");
            var response = confirm("Are you sure you want to delete this note?");
            if (response) {
                $.ajax({
                    type: 'POST',
                    url: 'deleteNote.php',
                    data: {
                        'id': id
                    },
                    beforeSend: function() {
                        $.mobile.loading('show');
                    },
                    success: function(data) {
                        $.mobile.loading('hide');
                        if (data.success) {
                            _listItem.remove();
                            _currentNotes.listview("refresh");
                        } else {
                            alert(data.error);
                        }
                    }
                });
            }
        });
    
  14. 最后,在 jQuery 的加载完成块 ($(function(){});) 外部添加以下函数,用于构建一个笔记的列表项:

    function createNoteItem(note) {
        return "<li data-id='" + note.id + "'><a href='javascript:void(0);' class='delete-note'>" + note.text + "</a></li>";
    }
    
  15. 通过访问从 Web 服务器提供的 index2.html,您将能够注册一个帐户,然后登录,就像之前的示例一样。一旦登录,点击查看笔记按钮将带您到一个空列表的页面。点击添加笔记按钮以添加新的笔记。一旦添加了新的笔记,您将会被带回到当前笔记列表,并显示您的新笔记。您可以通过点击它并确认要删除它来删除此笔记。您可以在已登录的会话跨多个设备上访问您的笔记。操作方法…

工作原理…

此示例代码的每个部分在接下来的几节中都有详细说明。

HTML

此示例中的 HTML 代码添加了一些额外的页面,以便已登录用户可以创建笔记并查看以前的笔记。笔记页面使用了一个带有过滤器的列表视图,该过滤器在本章的添加移动友好的列表示例中已经展示过。

SQL

在此示例中的简单 SQL 代码创建了一个名为 note 的附加表,用于存储所有用户的笔记。还定义了 note 表上的 user_id 字段和 user 表上的 id 字段之间的外键关系。

PHP

此示例中的所有 PHP 脚本都使用了与前一个示例相同的数据库连接文件和结构。为此示例创建了另外三个 PHP 脚本,如下所示:

  • addNote.php: 此脚本接受一个带有笔记文本的 POST 请求。然后,它使用 PHP $_SESSION超全局变量检查当前是否有已登录用户。如果有已登录用户,则验证提供的文本以确保其长度在 0 到 1024 个字符之间。如果是,则将其插入到数据库中,并附加用户 ID 和添加日期。为了获取新创建的笔记项的数据库 ID,使用了$mysqli->insert_id。然后,此 ID 在返回到请求脚本的note对象中。

  • deleteNote.php: 此脚本与addNote.php类似,接受一个带有笔记 ID 的 POST 请求。它还检查是否有已登录用户,如果有,则使用简单的 SQL 查询从数据库中删除指定的笔记。

  • getNotes.php: 通过使用已登录用户的 ID,从数据库中检索该用户的所有笔记,并将其转换为 JSON,以便可以使用 JavaScript 填充列表元素。

    注意

    如果 PHP 脚本需要访问会话数据,则必须在脚本顶部调用session_start()函数,即在任何其他代码之前。

JavaScript

script2.js的顶部,声明了_currentNotes变量,如下代码所示:

var _currentNotes = $('#current-notes');

这是因为在整个代码中需要当前笔记列表,并且通过重用相同的变量,jQuery 不会被强制多次重新选择元素。

为了动态填充#current-notes列表元素,使用了pagebeforechange事件。通过if...else语句的额外检查,可以确定用户何时尝试转到笔记页面,如下一行代码所示:

else if(urlObject.hash.search(/^#notes/) !== -1) {

当用户使用_currentNotes.data("initialized")访问此页面时,可以检查列表是否已填充。如果 initialized data属性已经设置,则已填充,并且无需再次从数据库中获取所有数据。如果 initialized 属性尚未设置为true,则会发出 AJAX 调用来收集当前的笔记并填充列表,如下代码所示:

_currentNotes.empty();
    _currentNotes.data("initialized", true);
    $.ajax({
     type: 'GET',
     url: 'getNotes.php',
     beforeSend: function() {
      $.mobile.loading('show');
     },
     success: function(data) {
      $.mobile.loading('hide');
      if (data.success) {
       for (var i = 0; i < data.notes.length; i++) {
        _currentNotes.append(createNoteItem(data.notes[i]));
       }
       //If the list view has already been initialized then we need to refresh it
if (_currentNotes.hasClass('ui-listview')) {                                       _currentNotes.listview("refresh");
        }
       $.mobile.changePage("#notes");
       } else {
        alert(data.error);
       }
      }
       });

_currentNotes.data("initialized", true);行用于将 initialized 属性设置为true,以便当用户返回页面时,脚本知道不要重新收集数据。然后,向getNotes.php脚本发出 AJAX 调用,并为每个返回的note对象使用createNoteItem()函数创建一个新的列表项。

如果 jQuery Mobile 已经初始化了#current-notes列表(意味着用户之前已经访问过该页面),则需要刷新列表视图。这是使用以下代码完成的,该代码取自 AJAX 调用的success()函数:

//If the list view has already been initialized then we need to refresh it
if (_currentNotes.hasClass('ui-listview')) {
   _currentNotes.listview("refresh");
      }

此食谱中的创建笔记和删除笔记功能非常简单,并且在本书中已经多次介绍过。简而言之,当单击保存笔记按钮或笔记列表项时,将分别向addNote.phpdeleteNote.php脚本发出 AJAX 调用。

在添加新笔记时,使用以下代码将新笔记项添加到当前笔记列表并将用户返回到笔记页面:

_currentNotes.prepend(createNoteItem(data.note));
//If the list view has already been initialized then we need to refresh it
if (_currentNotes.hasClass('ui-listview')) {
_currentNotes.listview('refresh');
}
$.mobile.changePage("#notes");

删除笔记时,使用以下代码来删除已删除的笔记项:

var _listItem = $(this).closest('li');
_listItem.remove();

由于 jQuery Mobile 为 DOM 添加了许多额外的元素来对列表进行样式设置,因此在单击锚点(在列表内)时,使用closest()函数来查找列表元素。另外,请注意使用$(document).on('click', '.delete-note'而不是$('.delete-note').click(),以便为动态添加的元素触发click事件处理程序。这在第二章中有介绍,通过使用 jQuery 事件与用户进行交互

还有更多...

本食谱提供了一个非常简单的完整移动 Web 应用程序的示例。有许多方面可以改进,但为了确保本食谱尽可能简洁,它们被省略了。

有一个可以改进的要素是deleteNote.php脚本的安全性方面。目前该脚本允许已登录的用户删除任何笔记,只要指定正确的 ID 即可。有一些知识的用户可以通过指定他们选择的笔记 ID 来劫持请求,潜在地删除另一个用户的笔记。通过检查指定的笔记 ID 是否属于已登录用户,可以很容易地避免这种情况。

请参阅

  • 第二章,通过使用 jQuery 事件与用户进行交互

  • 构建完整的注册和登录系统

posted @ 2024-05-19 20:12  绝不原创的飞龙  阅读(1)  评论(0编辑  收藏  举报