在最后一章中,我们介绍了动画以及它们如何使您的站点充满活力。在本章中,我们将介绍任何网站最重要的功能之一——表单。精心设计的表单可能是新客户和错过机会之间的区别。因此,表格值得仔细检查。
让用户填写表单并提交表单可能是一项挑战。如果我们的网站在任何时候挫败了用户,他们可能会放弃表单和我们的网站。因此,我们通过使用工具提示、占位符文本和视觉指示器向用户提供温和的提示,让他们知道表单的每个输入元素需要什么,让他们知道输入是有效的还是无效的。
jQuery 没有太多专门处理表单的方法。第一种都是快捷方式,;它们使用.on()
替换为事件名称作为第一个参数。让我们检查它们并学习如何使用它们。
让我们看看表单中使用的许多 jQuery 方法。
表单方法中最重要的是.submit()
。它将处理程序绑定到浏览器提交事件。当用户填写表单并单击 submit 按钮时,此处的事件处理程序将被激活。如果您希望自己处理此事件而不实际提交表单,则必须调用event.preventDefault()
或从方法返回false
。如果您不执行这些操作之一,表单将提交到服务器。
// Cancel the default action by returning false from event handler
$('form').submit(function(event){
alert('submit');
return false;
});
在前面的事件处理程序中,我们返回false
以阻止浏览器提交表单。我们也可以叫event.preventDefault()
。我们可以将上述内容写成:
// Cancel the default action by call
$('form').on('submit', function(event){
alert('submit');
event.preventDefault();
});
此示例与第一个示例相同,但使用了更多的文本。我们用它的长格式.on()
方法替换了 submit 快捷方式方法,我们还通过直接调用事件对象的preventDefault()
方法替换了 return false。
当用户选项卡或单击表单元素时,浏览器触发焦点事件。focus 方法为该事件创建一个处理程序。如果您想为您的用户创建某种指示,表明这是活动元素,那么这可能很方便。查看.blur()
方法的代码示例,了解如何将其与.focus()
一起使用。
需要注意的是,只有表单元素才能接收焦点。以下所有内容均为表单元素:
<input>
<select>
<textarea>
<button>
.blur()
方法是.focus()
方法的伴侣。它创建一个处理程序,当用户关闭或离开此元素时触发该处理程序,从而使其失去焦点。此事件也可用于运行元素验证,但实际上更改事件是一个更好的选择,稍后将使用.change()
方法对其进行解释。
// Adds / removes the active class using the focus/blur events
$("input, textarea").focus(function(event){
$(this).addClass('active');
});
$("input, textarea").blur(function(event){
$(this).removeClass('active');
});
我们可以使用方法.focus()
和.blur()
方法一起向活动元素添加一个类,并在它失去焦点时将其删除,以便为用户提供更好的视觉提示。注意,我们通过用逗号分隔标记名来钩住输入元素和文本区域元素。
.focus()
和.blur()
方法的一个潜在问题是它们不会冒泡。如果将要接收焦点的子元素放置在父元素中,并钩住父元素的焦点事件,则永远不会触发该事件。这意味着您不能将这些事件委托给它们的父级。如果需要钩住动态生成的输入标记的焦点/模糊事件,您也会遇到问题。
// These handlers will never be triggered
$('#fiOne').focus(function (event) {
console.info('Focus: ' + this.id + ', triggered by: ' + event.target.id);
$(this).addClass('active');
});
$('#fiOne').blur(function (event) {
console.info('Blur: ' + this.id + ', triggered by: ' + event.target.id);
$(this).removeClass('active');
});
在前面的代码中,我们钩住了fieldset
、fiOne
的焦点和模糊事件,这是所有单选按钮的父元素。在任何单选按钮子项上都没有这些事件的处理程序。不幸的是,由于这两个事件都不会冒泡到其父元素,因此不会触发任何事件。
所以现在我们知道焦点事件和模糊事件都不会出现在它们的父母身上。在前面的章节中,我们还了解了冒泡如何帮助我们创建更动态的应用程序。我们有没有办法避免泡沫的缺乏?幸运的是,有一个解决方案:.focusin()
和.focusout()
方法。.focusin()
方法为focusin
事件创建一个处理程序,该事件在元素即将接收焦点时触发。.focusout()
方法与.focusin()
方法相同除了它与focusout
事件一起工作,该事件在元素即将失去焦点时触发。这两种方法都将冒泡到它们的父元素。
// These handlers use the focusin/focusout, which bubble up
$('#fiOne').focusin(function (event) {
console.info('Focusin: ' + this.id + ', triggered by: ' + event.target.id);
$(this).addClass('active');
});
$('#fiOne').focusout(function (event) {
console.info('Focusout: ' + this.id + ', triggered by: ' + event.target.id);
$(this).removeClass('active');
});
除了焦点和模糊事件分别被focusin
和focusout
事件替换外,此代码示例与前面的示例几乎相同。我们再次钩住父fieldset
元素。然而,这一次,这些事件都是由它们的父事件引起的。我们将活动类添加到fieldset
中,甚至通过从 event 对象的 target 属性获取 ID 来显示哪个元素生成了事件。
// Adds an input tag dynamically by clicking the "Add Another" button
var inputCounter = 0;
$('#addAnother').click(function (event) {
console.info("Adding another");
$('#inputMomma').append($("<input>").attr({'type': 'text', 'id': 'newInput' + inputCounter++}));
});
// Makes the parent element the active class
$('#inputMomma').focusin(function (event) {
console.info('Focusin: ' + this.id + ', triggered by: ' + event.target.id);
$(this).addClass('active');
});
// Removes the active class from the parent
$('#inputMomma').focusout(function (event) {
console.info('FocusOut: ' + this.id + ', triggered by: ' + event.target.id);
$(this).removeClass('active');
});
在本例中,我们使用 jQuery 动态创建新的输入标记。请注意我们如何使用链接来附加新的输入标记并设置其属性。尽管这些标记在其父级钩住focusin
和focusout
事件时并不存在,但它们仍然会将自己的事件绑定到它。
.change()
方法为变更事件创建处理程序。更改事件的好处在于,它仅在输入或文本元素的值更改且字段不再具有焦点时才会触发。这使得验证比使用模糊事件更好,因为模糊事件总是在元素失去焦点时触发,无论其值是否已更改。通过使用变更事件,我们可以避免进行一些不必要的处理。
// only called once focus is lost and contents have changed
$("input, textarea").change(function (event) {
console.info('Change is good:' + this.id);
});
我们将在本章中研究的最后一个事件处理程序方法是.select()
方法。它绑定到 select 事件。此事件仅在允许您键入文本的两个元素上触发:<textarea>
和<input type='text'>
。选择事件仅在用户选择某些文本时发生。
// Triggered when some text is selected
$('textarea').select(function(event){
console.info("Something was selected: " + this.tagName);
});
在本例中,我们只需钩住 select 事件,并在收到标记时显示其名称。与大多数事件一样,我们也可以使用.trigger()
方法触发 select 事件。
// Selects all of the textarea text
$('#selectText').click(function (event) {
console.info("Adding another");
$('textarea').select();
});
这个片段选择了textarea
中的所有文本,并给出了<textarea>
的焦点。select 事件的其他缺点是没有标准的方法来检索所选文本或声明要选择的字符范围。触发 select 事件时,它始终选择所有字符。有 jQuery 插件可以填补这一空白。
标题属性自 HTML 4.01 起可用于除<base>
、<basefont>
、<head>
、<html>
、<meta>
、<param>
、<script>
和<title>
之外的所有元素。它定义了一个字符串,当光标位于元素上方时,大多数浏览器将在元素上方和附近呈现该字符串。显示的字符串通常称为工具提示。
标准 HTML 工具提示还有很多需要改进的地方。开箱即用的样式通常非常简单,可能与您的站点冲突。例如,如果您的站点使用大字体来帮助用户,那么标准的工具提示看起来会非常尴尬。幸运的是,jQuery 有一个解决方案,尽管它不在核心库中。
jQueryUI 是一个包含一组用户界面组件的库。该套装设计为可定制。该集合的一个成员是工具提示。对于缺少本机工具提示(标题属性支持)的浏览器,它添加了支持。对于本机支持工具提示的浏览器,它通过使其可自定义和设置动画来增强工具提示。
jqueryui 的所有组件都需要 jQuery 核心库加上 CSS 和 JavaScript 文件才能工作。CSS 文件必须在 jQuery 之前添加到 HTML 文件中,JavaScript 文件必须在 jQuery 之后添加。
<head lang="en">
<meta charset="UTF-8">
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<title>Chapter06-Forms</title>
前面的标记显示了如何正确地向网站添加 jQuery UI 支持。首先,我们添加 CSS 文件,然后添加 jQuery,最后添加 jQueryUI。
前面的代码使用内容交付网络 CDN 来承载文件。您也可以将文件托管在自己的服务器上,但通过使用 CDN,您可以获得潜在的性能提升,因为用户浏览器可能在文件第一次访问您的站点时就已经缓存了您的文件。
一旦我们加载了 jQuery 库,使用工具提示就非常简单了。我们需要钩住 jQuery 文档就绪事件,并在此期间设置工具提示。
// Hook the document ready event and
$(document).ready(function () {
// bind the tooltip plugin to the document
$(document).tooltip({
show: {
effect: "slideDown",
delay: 150
}
});
});
在前面的示例中,我们等待 DocumentReady 事件。在事件处理程序中,我们将工具提示绑定到文档。这使得我们的整个网站都可以使用它。最后一步是添加动画。可以自定义工具提示,使其在页面上和页面外都具有动画效果。在这里,我们有一个 150 毫秒的延迟后,在页面上动画的工具提示。它使用slideDown
动画效果。
现代浏览器的另一项功能是占位符文本,而旧浏览器则缺乏这一功能。它是显示在输入元素内部的略呈灰色的文本,一旦用户开始键入,它就会消失。占位符对于表单很重要。与<label>
元素不同,它们为用户提供了内容格式的提示,而<label>
元素是预期的信息类型。占位符属性仅在 HTML5 之后出现。仍然有很多浏览器缺乏对它的支持。
为了向旧浏览器添加对占位符属性的支持,我们将再次使用插件,但不是 jQuery 团队的插件。相反,我们将使用来自 Mathias Bynens 的优秀 jquery 占位符。可从 bower 和 npm 下载,但我们将直接从其 GitHub 回购协议下载,网址为:http://mathiasbynens.github.io/jquery-placeholder/ 。由于我们不关心它是如何工作的,只关心如何使用它,我们将在我们的网站上安装缩小版。为此,我们在 HTML 文件中添加以下行:
<script src="jquery.placeholder.min.js"></script>
占位符是一种称为 polyfill 的插件。这意味着它的目标仅仅是让浏览器缺少一个标准特性,即该特性。如果浏览器已经支持该标准,那么它什么也不做。为了激活插件,我们将其添加到 jQuery document ready 事件中,与前面的工具提示相同。
// Hook the document ready event and
$(document).ready(function () {
// bind the placeholder to the input & textarea elements
$('input, textarea').placeholder();
});
表单中无效的元素应被禁用。禁用的元素通常显示为灰色文本暗显。被禁用的元素无法聚焦,不响应用户,并且在提交表单时不会被发送。
关于 disabled 属性的奇怪之处在于它在元素中的存在禁用了它。它不需要设置为true
或false
。事实上,设置它true
或false
没有效果。要禁用该元素,请添加 disabled 属性。要启用元素,请删除禁用的属性。幸运的是,jQuery 理解这种奇怪的行为,并为我们处理好这个细节。
我们可以使用 jQuery.prop()
方法来帮助我们。当我们想要禁用该元素时,我们会执行以下操作:
$('#someId).prop('disabled', true);
当我们想要启用该元素时,我们会执行以下操作:
$('#someId).prop('disabled', false);
不管事情看起来如何,jQuery 都会完全按照我们所说的去做。第一行代码将向元素添加 disabled 属性,第二行代码将删除它。下面是一段功能更全面的代码:
// disables/enable elements
$('#disableEnable').click(function (event) {
var $ptr = $('#names > *');
if ($ptr.prop('disabled')) {
$ptr.prop('disabled', false);
$(this).text('Disable Them');
} else {
$ptr.prop('disabled', true);
$(this).text('Enable Them');
}
});
我们首先为disableEnable
按钮的点击事件连接一个事件监听器。一旦收到事件,我们将检查按钮当前是否已禁用。如果是,我们启用它并更改按钮的文本标签。如果元素未被禁用,我们将禁用它并更改文本消息。
到目前为止,我们已经学习了如何钩住表单事件,如何为旧浏览器提供占位符和工具提示等现代浏览器功能,以及如何使用 jQuery 表单方法收集所有表单数据。但我们并没有做真正重要的事情:验证数据。
验证对用户和我们网站的创造者都很重要。对于用户,可以使用验证让他们知道如何正确填写表单。当他们出错时,我们可以轻轻地推他们,而不是让他们提交一个不好的表单,然后告诉他们表单包含错误。作为网站的维护者,在一个字段中找到一个应该有电话号码的地址可能会让人沮丧。HTML5 为 web 添加了许多验证功能。在我们了解 jQuery 提供了什么之前,让我们先看看在现代浏览器中我们可以免费获得什么。
我们将看到的第一个添加 HTML5 的属性看起来非常简单和琐碎,很难想象它已经不存在了:autofocus
。autofocus
属性声明加载表单时哪个表单元素应该具有焦点。在它存在之前,用户必须单击一个元素以选择它,或者我们必须使用一点 jQuery 代码,如下所示:
// Hook the document ready event and
$(document).ready(function () {
// Give the title select element the focus
$('#title').focus();
});
对于 HTML5,前面的代码替换为:
<select id="title" name="title" autofocus>
autofocus
属性声明该元素获得焦点。在任何给定时间,只有一个元素应该具有该属性。
HTML5 还增加了<input>
元素类型的数量。以前,唯一可用的类型是:
类型
|
意图
| | --- | --- | | 按钮 | 按下按钮 | | 复选框 | 复选框 | | 文件 | 文件选择 | | 隐藏的 | 未显示,但已提交到服务器 | | 形象 | “提交”按钮的图形版本 | | 暗语 | 具有模糊值的文本字段 | | 无线电广播 | 单选按钮 | | 重置 | 将窗体的内容重置为默认值 | | 提交 | 提交表格 | | 文本 | 单行文本字段 |
HTML5 增加了以下新类型的<input>
:
类型
|
意图
| | --- | --- | | 颜色 | 颜色选择器 | | 日期 | 日期选择器(没有时间) | | 日期时间 | UTC 的日期/时间选择器 | | 日期时间本地 | 本地时区的日期/时间选择器 | | 电子邮件 | 电子邮件地址 | | 月 | 月/年选择器 | | 数字 | 浮点数的文本字段 | | 范围 | 范围滑块 | | 搜索 | 搜索字符串的文本字段 | | 电话 | 电话号码的文本字段 | | 时间 | 没有时区的时间选择器 | | 网址 | URL 的文本字段 | | 周 | 一周/一年的挑选者 |
必须指出的是,对不同的类型很少进行检查。例如,Tel 类型允许输入通常不属于电话号码的字符。HTML5 的三个属性可以提供帮助:minlength
、maxlength
和pattern
。minlength
属性表示为使字符串被视为有效,可以输入的最小字符数。maxlength
属性除最大字符数外,其他功能相同。最后一个属性是pattern
;它声明了一个正则表达式,用于检查输入的字符串。为了使字符串被认为是有效的,它必须通过。正则表达式在验证方面非常方便,但要正确编写正则表达式可能很困难。确保彻底测试添加到站点的任何正则表达式。我还强烈建议使用一个有流行验证方法的网站。一个这样的站点是非常流行的正则表达式站点:http://www.regular-expressions.info 。
HTML5 还添加了一个非常简单但重要的验证属性:required。required 属性只是声明必须填写一个输入元素才能认为表单有效。如果保留为空或已填充但无效,则兼容浏览器将在用户尝试提交表单时标记错误。不幸的是,错误消息和样式因浏览器而异。所以再一次,如果我们真的想负责我们网站的风格设计,我们必须求助于我们的好朋友 jQuery。
验证不是 jQuery 或 jQuery UI 的一部分,但它是 jQuery 验证插件的主要功能。它由 jQuery、jQuery UI 和 QUnit 团队的一名成员 Jörn Zaeffer 编写和维护。它始于 2006 年,至今仍在维护中,使其成为最古老的 jQuery 插件之一。jquery 验证的主页是:http://jqueryvalidation.org/ 。它可以作为 zip 文件下载,也可以通过 bower 或 nuget 软件包管理器下载。插件的核心在文件jquery.validate.js
中。这就是大多数安装所需的全部内容。
将插件添加到脚本文件后,接下来需要将对要验证的表单上的 validate 方法的调用添加到 jQuery document ready 事件处理程序中。为了最大限度地减少验证,只需增强 HTML5 提供的功能,您只需添加以下内容:
$('#personalInfo').validate();
这一行告诉插件验证名为personalInfo
的表单。除此之外,不需要其他任何东西。该插件的行为将与您在表单元素上放置的验证属性一致,即使浏览器不兼容 HTML5。
如果您想要更多的定制,您需要向插件传递一个初始化对象。两个最重要的属性是规则和消息。rules 属性定义插件将如何验证每个表单元素。messages 属性定义当元素验证失败时插件将显示的消息。以下是我们验证样本的代码:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<script src="jquery.validate.min.js"></script>
<script src="jquery.placeholder.min.js"></script>
<title>Chapter06-Forms</title>
<style type="text/css">
.wider {
display: inline-block;
width: 125px;
margin-right: 8px;
}
select {
margin-right: 8px;
}
.error{
color: red;
}
</style>
</head>
<body>
<div>
<form id="personalInfo">
<fieldset>
<legend>Personal Info</legend>
<p>
<label for="title" class="wider">Greeting</label>
<select id="title" name="title" class="wider" autofocus>
<option selected></option>
<option>Mr.</option>
<option>Ms.</option>
<option>Miss</option>
<option>Mrs.</option>
<option>Dr.</option>
</select>
</p>
<p>
<label for="firstName" class="wider">First Name:</label>
<input id="firstName" name="firstName" class="wider" type="text" title="Your first name"/>
</p>
<p>
<label for="lastName" class="wider">Last Name:</label>
<input id="lastName" name="lastName" class="wider" type="text" title="Your last name"/>
</p>
<p>
<label for="password" class="wider">Password:</label>
<input id="password" name="password" class="wider" type="password" title="Your password" title="Your password"/>
</p>
<p>
<label for="confirmPassword" class="wider">Confirm Password</label>
<input id="confirmPassword" name="confirmPassword" class="wider" type="password" title="Confirm your password"/>
</p>
<p>
<label for="email" class="wider">E-Mail:</label>
<input id="email" name="email" class="wider" type="email" title="Your email address" placeholder="yourname@email.com" />
</p>
</fieldset>
<input type="reset" value="Reset" class="wider"/>
<input type="submit" value="Submit" class="wider"/>
</form>
</div>
除了添加验证插件外,我们还需要包括 jQuery,因为我们仍然在使用 jQuery 工具提示和占位符插件,所以我们也包括它们。接下来,我们添加了一点内联 CSS 以提供一点样式。
我们的表单非常标准,除了一件事:我们不再添加任何内联验证属性。相反,我们在传递到验证方法的 JavaScript 对象中定义验证规则,我们将在下面看到:
<script type="text/javascript">
(function () {
"use strict";
// Hook the document ready event and
$(document).ready(function () {
// bind the placeholder polyfill to the input + textarea elements
$('input, textarea').placeholder();
// bind the tooltip plugin to the document
$(document).tooltip({
show: {
effect: "slideDown",
delay: 150
}
});
此代码示例的第一部分相当简单。我们绑定到 jQuery 的就绪事件,然后启用占位符 polyfill 和工具提示。
// bind validation to the personalInfo form
$('#personalInfo').validate({
rules: {
title: {
required: true
},
firstName: {
required: true,
minlength: 5
},
lastName: {
required: true,
minlength: 5
},
password: {
required: true,
minlength: 5
},
confirmPassword: {
required: true,
minlength: 5,
equalTo: '#password'
},
email: {
required: true,
email: true
}
},
在 validation 对象的 rules 属性中,我们传递希望验证的所有元素的名称。我们可以告诉验证器需要哪些元素,它们的最小长度,它们是否应该匹配另一个元素,等等。验证器可以做的比代码中显示的多得多,因此请务必阅读文档以了解更多信息。
messages: {
title: "Please choose a title.",
firstName: "Please enter your first name.",
lastName: "Please enter your last name.",
password: "Please create a password.",
confirmPassword: {
required: "Please confirm your password.",
equalTo: "Your passwords must match."
},
email: "Please enter a valid email."
},
submitHandler: function(form) {
alert('submit');
}
});
});
}());
</script>
</body>
</html>
在验证对象的 message 属性中,我们传递所有希望显示的消息。此处未定义的任何元素或状态都将被简单地分配一条默认的验证错误消息,在许多情况下,这可能就足够了。
传递给验证方法的最后一个属性是提交处理程序。这是用户成功提交表单后调用的方法。您必须使用提交处理程序,而不是 jQuery 提交处理程序。
作为 web 开发人员,我们的工作是防止用户意外地做坏事。当用户输入错误时,验证可以让用户知道。筛选有助于防止用户输入无效字符。为了过滤输入到文本字段中的字符,我们需要钩住两个事件:“按键”和“粘贴”。
// filters out unwanted characters
$('#alphaNumOnly').on('keypress paste', function (event) {
// convert the keycode into a character
var nextChar = String.fromCharCode(event.which);
if(event.type === 'keypress'){
// add it to the current input text string, the remove any
bad chars via regex
this.value = (this.value + nextChar).replace(/[^0-9|a-z|AZ]+/g, '');
}
// let the browser know we've handled this event
event.preventDefault();
return false;
});
挂钩keypress
事件允许我们在按下每个键时查看它,并决定是否在文本字段中使用该字符。我们钩住粘贴键以阻止用户将字符串剪切和粘贴到文本字段中。大部分工作是由正则表达式完成的。它过滤掉除了数字和字母以外的所有东西。
表单对于大多数网站来说都非常重要。它们是我们网站用户与网站交流的主要方式。帮助我们的用户填写我们的表格,并确保我们得到的数据是好的。我们已经看到了 jQuery 帮助我们处理表单的许多方法。工具提示插件帮助我们将工具提示添加到缺少它的浏览器中,并设置工具提示的样式以匹配我们网站的外观。占位符 polyfill 为旧浏览器提供占位符属性,并悄悄地为已经支持它的浏览器让路。
jQuery 还为我们提供了钩住提交、更改和其他表单事件的简单方法。这些事件还提供了在我们提交数据之前或数据更改后验证数据的点。
在下一章中,我们将学习 Ajax,以及 jQuery 如何使从服务器发送和接收数据变得非常简单。