jQueryUI 1.10:jQuery 的用户界面库(二)
原文:
zh.annas-archive.org/md5/67D4BB507B37025C38972681032F3C25译者:飞龙
第五章:对话框
传统上,显示简短消息或询问访问者问题的方法是使用 JavaScript 的本机对话框之一(如alert或confirm),或者打开一个具有预定义大小且样式设计成对话框样式的新网页。
不幸的是,我相信你也清楚,这些方法对于我们作为开发人员并不特别灵活,对我们的访问者也不特别引人入胜。它们解决了一些问题,但通常也会引入几个新问题。
对话框小部件可以让我们显示消息、补充内容(如图像或文本)甚至交互式内容(如表单)。也很容易添加按钮,例如简单的确定和取消按钮,并为它们定义回调函数以便对它们的点击作出反应;对话框也可以是模态的或非模态的。
在本章中,我们将涵盖以下主题:
-
创建基本对话框
-
使用对话框选项
-
模态性
-
启用内置动画
-
向对话框添加按钮
-
使用对话框回调
-
控制对话框的程序化方法
以下截图显示了对话框小部件及其所包含的不同元素:
创建基本对话框
对话框具有许多内置的默认行为,但只需要少量方法来程序化地控制它,使其成为一个易于使用的小部件,同时也具有高度可配置性和强大性。
生成小部件很简单,只需要最小的底层标记结构。以下页面包含实现对话框小部件所需的最小标记:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Dialog</title>
<link rel="stylesheet" href="development-bundle/themes/redmond/jquery.ui.all.css">
<script src="img/jquery-2.0.3.js"></script>
<script src="img/jquery.ui.core.js"></script>
<script src="img/jquery.ui.widget.js"> </script>
<script src="img/jquery.ui.position.js"> </script>
<script src="img/jquery.ui.dialog.js"> </script>
<script src="img/jquery.ui.button.js"> </script>
<script>
$(document).ready(function($){
$("#myDialog").dialog();
});
</script>
</head>
<body>
<div id="myDialog" title="This is the title!">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Aenean sollicitudin. Sed interdum pulvinar justo. Nam iaculis volutpat ligula. Integer vitae felis quis diam laoreet ullamcorper. Etiam tincidunt est vitae est.
</div>
</body>
</html>
将此文件保存为dialog1.html,放在jqueryui项目文件夹中。要使用对话框,需要以下依赖项:
-
jquery.ui.all.css -
jquery.ui.core.js -
jquery.ui.widget.js -
jquery.ui.position.js -
jquery.ui.dialog.js -
jquery.ui.button.js
可选地,我们还可以包含以下文件来使对话框可拖动和可调整大小:
-
jquery.ui.mouse.js -
jquery.ui.draggable.js -
jquery.ui.resizable.js
对话框小部件的初始化方式与我们已经了解的其他小部件相同,通过调用小部件的插件方法。
当您在浏览器中运行此页面时,您应该看到默认的对话框小部件,如下截图所示:
与我们之前介绍的小部件一样,CSS 框架中的各种类名被添加到小部件中的不同元素中,以使它们具有各自元素的适当样式,并且所需的任何附加元素都是即时创建的。
第一个示例中的对话框在大小和位置上都是固定的,并且将被定位在视口的中心。我们可以很容易地使小部件可拖动、可调整大小或两者兼具。我们只需要在<head>的末尾与其他<script>资源一起包含可拖动和可调整大小组件的源文件,以及鼠标工具。
不重要的是,在对话框的源文件之前将可拖动和可调整大小的文件包含在页面中。它们可以出现在对话框的源文件之前或之后,小部件仍将继承这些行为。任何所需的样式,例如出现在对话框左下角的调整大小指示器,将自动从主 CSS 文件中捡取。
在dialog1.html的关闭</head>标签之前直接添加以下三个<script>元素:
<script src="img/jquery.ui.mouse.js">
</script>
<script src="img/jquery.ui.draggable.js">
</script>
<script src="img/jquery.ui.resizable.js">
</script>
将其保存为dialog2.html并在浏览器中查看。现在对话框应该是可拖动的,并且可以移动到视口的任何部分,但是如果小部件移动到边缘,它不会导致滚动。
对话框还应该是可调整大小的——通过单击并按住任何角落并拖动,可以使小部件变大或变小。如果对话框比视口大,它将导致窗口滚动。
列出对话框选项
选项对象可用于对话框的小部件方法中配置各种对话框选项。让我们来看看可用的选项:
| 选项 | 默认值 | 描述 |
|---|---|---|
appendTo | "body" | 确定对话框(和遮罩,如果是模态的)应追加到哪个元素。 |
autoOpen | true | 当设置为true时,调用dialog()方法时立即显示对话框。 |
buttons | {} | 提供一个包含要与对话框一起使用的按钮的对象。每个键都成为<button>元素上的文本,每个值都是一个回调函数,在单击按钮时执行。 |
closeOnEscape | true | 如果设置为true,则按下Esc键时对话框将关闭。 |
dialogClass | "" | 为对话框设置额外的类名以进行主题设置。 |
draggable | true | 使对话框可拖动(需要使用jquery.ui.draggable.js)。 |
height | auto | 设置对话框的起始高度。 |
hide | null | 设置对话框关闭时要使用的效果。 |
maxHeight | false | 设置对话框的最大高度。 |
maxWidth | false | 设置对话框的最大宽度。 |
minHeight | 150 | 设置对话框的最小高度。 |
minWidth | 150 | 设置对话框的最小宽度。 |
modal | false | 在对话框打开时启用模态。 |
position | center | 设置对话框在视口中的起始位置。它可以接受一个字符串、一个字符串数组或包含对话框偏离视口顶部和左侧的确切坐标的数组(需要使用jquery.ui.position.js)。 |
resizable | true | 使对话框可调整大小(还需要jquery.ui.resizable.js)。 |
show | null | 设置对话框打开时要使用的效果。 |
title | "" | 替代在小部件的基础容器元素上指定标题属性。 |
width | 300 | 设置对话框的起始宽度。 |
如您所见,我们有各种可配置的选项可供在实现对话框时使用。其中许多选项是布尔值、数值或基于字符串的,使它们易于在您的代码中获取和设置。
显示对话框
到目前为止,我们的示例中,对话框在页面加载后立即显示。 autoOpen 选项默认设置为 true,因此对话框将在初始化时立即显示。
我们可以更改这样,以便在发生其他事情时打开对话框,比如通过将 autoOpen 选项设置为 false 来点击按钮。将 dialog2.html 底部的最终 <script> 元素更改为以下内容:
<script>
$(document).ready(function($){
$("#myDialog").dialog({
autoOpen: false
});
});
</script>
将此保存为 dialog3.html。小部件仍然被创建;底层标记被从页面中移除,转换为小部件,然后重新附加到 <body> 的末尾。它将保持隐藏,直到调用 open 方法为止。我们稍后在本章中查看 open 方法时会回到这个选项。
设置对话框标题
选项表显示一个 title 选项,我们可以使用它来控制标题在小部件上的显示方式;如果将 draggable 属性设置为 false,则可以将其设置为可选择。虽然可以直接在代码中设置它,但在配置选项中设置它要容易得多,因为这样可以更好地控制标题在小部件中的显示方式。
默认情况下,对话框小部件的标题文本将显示为纯文本;我们可以通过向 .ui-dialog-title 类添加自定义样式来覆盖此设置。
在浏览器中,将 dialog3.html 中对话框的 <script> 块修改如下:
<script>
$(document).ready(function($){
$("#myDialog").dialog({
draggable: false,
open: function() {
$(".ui-dialog-title").addClass("customtitle");
}
});
});
</script>
将文件保存为 dialog4.html。我们现在可以为对话框的标题栏添加一些样式 - 在一个单独的文件中添加以下代码,并将其保存为 dialogOverrides.css,在链接到 jQuery UI 样式表后:
.customtitle { color: #800080; }
如果我们在浏览器中预览结果,您可以清楚地看到标题现在以不同的颜色显示:
要查看代码的效果,我们可以查看脚本如何覆盖基本代码,使用 DOM 检查器如 Firebug:
<span id="ui-id-1" class="ui-dialog-title customtitle">This is the title!</span>
我们可以在样式表中手动为对话框元素设置样式,但这将是通过反复试验;简单地使用 jQuery 添加一个新类,然后我们可以根据自己的喜好进行样式设置,这会更容易得多!
小贴士
如果未提供值给 title 属性,则将使用对话框源元素上的属性。
配置模态选项
对话框的最大优势之一是模态性。此功能在对话框打开时创建一个覆盖在对话框下方的底层页面的覆盖层。一旦对话框关闭,覆盖层就会被移除。在对话框打开时,无法以任何方式操纵底层页面内容。
这个功能的好处是它确保对话框在基础页面再次变得交互之前关闭,并为访问者提供清晰的视觉指示,表明必须与对话框交互,然后才能继续。
修改dialog4.html中的配置对象如下所示:
$(document).ready(function($){
$("#myDialog").dialog({
modal: true
});
});
此文件可以保存为dialog5.html。以下截图显示了模态效果(您可能需要向页面添加一些虚假内容,以充分体验模态效果):
添加模态的唯一属性是modal选项。当您在浏览器中查看页面时,您将立即看到模态效果。用于创建覆盖图像的重复背景图像完全由 CSS 框架样式化,因此可以通过ThemeRoller工具进行完全主题化。如果需要,我们还可以使用自己的图像。ui-widget-overlay类名称会被添加到覆盖层中,因此这是需要覆盖的选择器,如果需要自定义的话。
添加按钮
button选项接受一个对象文字,用于指定对话框上应存在的不同<button>元素。每个property: value对表示一个单个按钮。让我们向我们的对话框添加一些<button>元素。
修改dialog5.html中的最终<script>元素,使其如下所示:
<script>
$(document).ready(function($){
$("#myDialog").dialog({
buttons: { Ok: function() { }, Cancel: function() { } },
draggable: false
});
});
</script>
将文件保存为dialog6.html。buttons对象中每个属性的关键是将形成<button>标签的文本,值是单击按钮时要执行的回调函数的名称。buttons选项可以采用对象,如此示例中的示例,也可以采用对象数组。在这个例子中,execute()和cancel()函数什么都不做;我们很快就会回到这个例子并填充它们。
以下截图显示了我们的新<button>元素将如何显示:
小部件将在对话框底部的自己容器中添加我们的新按钮,并且如果对话框被调整大小,此容器将保持其原始尺寸。<button>元素是完全可主题化的,并且将根据使用的主题进行样式设置。
向对话框按钮添加图标
直到现在,关闭对话框通常意味着必须点击标题栏中的关闭图标-它对此目的非常有效,但并不为我们提供任何机会从浏览我们网站或在线应用程序的人那里获得响应。
在前面的示例中添加按钮有助于消除这一限制,并允许我们从最终用户处接受各种响应-我们可以通过添加图标进一步提供按钮的视觉支持。
在您的文本编辑器中,修改dialog6.html中的<script>块如下:
<script>
$(document).ready(function($){
$("#myDialog").dialog({
buttons: [ {
text: "Ok",
icons: { primary: "ui-icon-check", secondary: "ui-icon-circle-check" },
click: function() { }
}, {
text: "Cancel",
icons: { primary: "ui-icon-closethick", secondary: "ui-icon-circle-close" },
click: function() { }
} ],
draggable: false
});
});
</script>
将此保存为dialog7.html。在这里,我们使用了按钮选项来指定文本、图标以及当单击按钮时应该执行的操作。您会注意到,与前一个示例相比,我们还使用了一种不同的方式来指定每个选项。两种方法都同样有效;我们需要在添加图标时使用这种方法,否则您可能会发现出现没有文本的按钮!
如果我们在浏览器中预览结果,我们现在可以看到在对话框底部出现的带有额外图标的按钮:
图标的样式将根据使用的主题进行设置。在我们的示例中,我们指定了主要和次要图标;前者位于按钮文本的左侧,而后者位于右侧。然而,在您的应用程序或网站中,您可能只需要根据您的需求指定一个图标。
启用对话框动画
对话框为我们提供了一个内置效果,可以应用于小部件的打开或关闭(或两者)。我们只能使用一个效果,即缩放效果的实现(我们将在第十三章中更详细地介绍这一点,“使用 jQuery UI 进行选择和排序”)。将dialog7.html中的最终<script>元素更改为以下内容:
<script>
$(document).ready(function($){
$("#myDialog").dialog({
show: true,
hide: true
});
});
</script>
将此保存为dialog8.html。我们将hide和show选项都设置为布尔值true。这将启用内置效果,逐渐减小对话框的大小和不透明度,直到它优雅地消失。以下截图显示了效果正在进行中:
我们可以使用布尔值分别启用或禁用显示或隐藏动画,就像我们在此示例中所做的那样。我们还可以通过提供指定要使用的效果名称的字符串来指定要使用的动画类型:
<script>
$(document).ready(function($){
$("#myDialog").dialog({
show: {effect: "fadeIn", duration: 1000},
hide: {effect: "fadeOut", duration: 1000}
});
});
</script>
我们甚至可以更进一步,使用一些效果,比如弹跳或爆炸,尽管这些效果只有在适当时才应添加!我们稍后将在 jQuery UI 中介绍效果,第十四章中可以找到更多详细信息,“UI 效果”。您还可以在api.jqueryui.com/category/effects/上查看更多细节。
配置对话框的尺寸
与对话框大小以及其可以调整到的最小和最大尺寸相关的选项有几个。我们可以将所有这些选项添加到下一个示例中,因为它们都是相关的,以节省逐个查看它们的时间。将dialog8.html中的配置对象更改为以下内容:
$("#myDialog").dialog({
width: 500,
height: 300,
minWidth: 150,
minHeight: 150,
maxWidth: 600,
maxHeight: 450
});
将此文件保存为dialog9.html。这些选项对小部件的影响很简单;width和height选项定义了对话框在首次打开时的大小,而min-和max-选项分别定义了对话框可以调整到的最小或最大尺寸。
提示
另外一点需要注意的是,如果对话框过小,辅助技术和键盘用户可能会发现内容难以导航。有一个可用性原则坚持认为对话框应该始终是不可调整大小的,而窗口应该始终是可调整大小的。
虽然我认为这不是一条黑白分明、铁板一块的规则,但是将小型、信息性、基于文本的对话框保持固定大小可能是明智的,而允许包含图像和文本的内容丰富的对话框可以调整大小。我们将在第十二章中介绍如何将调整大小手柄添加到任何合适的元素(如对话框),调整大小组件中。
设置对话框的 z-index 顺序
对话框被设置为出现在任何现有页面内容的上方。我们可以使用 CSS 更改其 z-index 设置,或者通过确保正确将其附加到其父元素来提高它,以覆盖我们的现有内容。但是如果页面上有两个对话框怎么办?我们是否需要分别为每个对话框定义zIndex?焦点如何考虑?
让我们看看是否可以通过查看另一个示例来回答这些问题;将dialog7.html的<body>标记更改为具有两个对话框:
<div id="dialog1" title="Dialog 1">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Aenean sollicitudin. Sed interdum pulvinar justo. Nam aculis
volutpat ligula. Integer vitae felis quis diam laoreet ullamcorper. Etiam tincidunt est vitae est.
</div>
<div id="dialog2" title="Dialog 2">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean sollicitudin. Sed interdum pulvinar justo. Nam iaculis volutpat ligula. Integer vitae felis quis diam laoreet ullamcorper. Etiam tincidunt est vitae est.
</div>
现在将最终的<script>元素更改为如下所示:
<script>
$(document).ready(function($){
$("#dialog1, #dialog2").dialog();
});
</script>
将此文件保存为dialog10.html。我们在页面上添加了另一个对话框,它基本上只是原始对话框的一个克隆,具有不同的id和title属性。在<script>中,我们只需在两个底层对话框容器上调用widget方法。
由于widget方法在第二个对话框上被最后调用,因此它接收焦点,第二个对话框将自动具有较高的 z-index 值。这意味着我们不需要担心单独配置它。对话框在底层标记中出现的顺序无关紧要;决定每个对话框 z-index 值的是 widget 方法的顺序。
提示
覆盖 z-index 值
如果需要覆盖 z-index 值,可以(并且应该)使用 CSS 来执行此操作-您需要使用!important属性来覆盖现有值。
由于两个对话框都没有显式设置其位置,所以当我们的示例页面加载时,只有第二个对话框会可见。然而,两者都是可拖动的,我们可以通过将第二个对话框拖离来将它们对齐,使它们略微重叠。如果我们点击第一个对话框框,它将接收焦点,因此它将显示在第二个框上方。
控制焦点
在打开对话框时,接收焦点的元素由匹配以下条件的项目确定:
-
对话框中具有 autofocus 属性的第一个元素
-
对话框内容中的第一个
:tabbable元素 -
对话框按钮面板中的第一个
:tabbable元素 -
对话框的关闭按钮
-
对话框本身
以下代码摘录最能说明这一点,我们已经将autofocus属性添加到“是”单选按钮中:
<div id="myDialog" title="Best Widget Library">
<p>Is jQuery UI the greatest JavaScript widget library?</p>
<label for="yes">Yes!</label>
<input type="radio" autofocus="autofocus" id="yes" value="yes" name="question" checked="checked"><br>
<label for="no">No!</label>
<input type="radio" id="no" value="no" name="question">
</div>
“是”单选按钮首先接收焦点;然后我们可以通过标签切换到小部件内的其他元素。一旦对话框关闭,焦点将自动返回到对话框打开之前具有焦点的元素。
处理对话框的事件回调
对话框小部件为我们提供了广泛的回调选项,我们可以使用这些选项在任何对话框交互中的不同点执行任意代码。以下表格列出了我们可以使用的选项:
| 事件 | 描述 |
|---|---|
beforeClose | 当对话框即将关闭时触发此事件 |
close | 当对话框关闭时触发此事件 |
create | 当对话框初始化时触发此事件 |
drag | 当对话框被拖动时触发此事件 |
dragStart | 当对话框开始拖动时触发此事件 |
dragStop | 当对话框停止拖动时触发此事件 |
focus | 当对话框获得焦点时触发此事件 |
open | 当对话框打开时触发此事件 |
resize | 当对话框被调整大小时触发此事件 |
resizeStart | 当对话框开始调整大小时触发此事件 |
resizeStop | 当对话框停止调整大小时触发此事件 |
这些回调中的一些仅在特定情况下可用,例如当包含可拖动和可调整大小的 jQuery UI 组件时,才会有drag和resize回调。在本章中,我们不会讨论这些回调选项,因为它们将分别在 第十一章、“拖放” 和 第十二章、“可调整大小组件” 中详细介绍。
其他回调,例如beforeClose、create、open、close和focus将在任何实现中可用。让我们看一个使用这些回调选项的例子。
在 dialog10.html 页面中删除第二个对话框,然后在第一个对话框后面直接添加以下新的标记:
<div id="status" class="ui-widget ui-dialog ui-corner-all ui-widget-content">
<div class="ui-widget-header ui-dialog-titlebar ui-corner-all">Dialog Status</div>
<div class="ui-widget-content ui-dialog-content"></div>
</div>
现在将最终的 <script> 元素更改为以下内容:
<script>
$(document).ready(function($){
$("#dialog1").dialog({
open: function() {
$("#status").children(":last").text("The dialog is open");
},
close: function() {
$("#status").children(":last").text("The dialog is closed");
},
beforeClose: function() {
if ($(".ui-dialog").css("width") > "300") {
return false;
}
}
});
});
</script>
将此保存为 dialog11.html。该页面包含一个新的状态框,用于报告对话框是打开还是关闭。我们已经给状态框的各个元素添加了几个 CSS 框架类,以使它们与正在使用的主题相适应。
我们的配置对象使用了 open、close 和 beforeClose 选项来指定简单的回调函数。open 和 close 回调简单地相应地设置状态框的文本。在 Close 按钮在对话框上被点击之后(但在实际关闭之前)触发的 beforeClose 回调用于确定是否关闭对话框。
我们使用简单的if语句来检查对话框的宽度;如果对话框宽度大于 300 像素,则从回调中返回false,对话框保持打开状态。当然,这种行为通常在可用性方面通常是不可接受的,但它确实突出了我们如何使用beforeClose回调来阻止对话框被关闭。
页面加载时,对话框显示,并执行open回调,状态框应显示一条消息。当对话框关闭时,如下图所示,会显示不同的消息:
我应该澄清的一件事是,对话框小部件只将一个对象(原始事件对象)传递给回调函数。虽然它确实将第二个ui对象传递到处理程序函数中,但在该库的此版本中,此对象不包含任何属性。
以编程方式控制对话框
对话框直观且易于使用,与库中的其他组件一样,它提供了一系列方法,用于在初始化后以编程方式控制小部件。我们可以在对话框上调用的所有方法的完整列表如下:
| 方法 | 描述 |
|---|---|
close | 这用于关闭或隐藏对话框。 |
destroy | 这用于永久禁用对话框。至于对话框的destroy方法,它与我们之前见过的其他小部件的工作方式略有不同。它不仅仅是将底层 HTML 返回到其原始状态,还会隐藏对话框。 |
isOpen | 这用于确定对话框是否打开。 |
moveToTop | 这用于将指定的对话框移动到堆栈顶部。 |
open | 这用于打开对话框。 |
option | 这用于在对话框初始化后获取或设置任何可配置选项。 |
widget | 这用于返回调用了dialog()小部件方法的外部元素。 |
切换对话框
首先我们来看看如何以编程方式控制小部件的打开,可以简单地使用open方法实现。让我们重新访问dialog3.html,其中autoOpen选项设置为false,因此当页面加载时对话框不会打开。在页面上添加以下<button>:
<button type="button" id="toggle">Toggle dialog!</button>
然后将以下点击处理程序添加到代码顶部的<script>块中:
$("#toggle").click(function() {
if(!$("#myDialog").dialog("isOpen")) {
$("#myDialog").dialog("open");
} else {
$("#myDialog").dialog("close");
}
});
将此文件保存为dialog12.html。在页面上,我们添加了一个简单的<button>,可以用来打开或关闭对话框,具体取决于其当前状态。在<script>元素中,我们为<button>元素添加了一个点击处理程序,检查isOpen方法的返回值;感叹号的使用意味着我们要查看对话框是否没有打开。如果语句返回true,则对话框未打开,因此我们调用其open方法,否则我们调用close方法。
open 和 close 方法都会触发任何适用的事件;例如,#toggle 单击处理程序方法首先触发 beforeClose 然后是 close 事件。调用 close 方法类似于点击对话框上的关闭按钮。
从对话框获取数据
因为小部件是底层页面的一部分,所以传递数据到它和从它获取数据都很简单。对话框可以像页面上的任何其他标准元素一样对待。让我们看一个基本的例子。
在本章的早些时候,我们看过一个例子,其中向对话框添加了一些 <button> 元素。那个例子中的回调函数没有做任何事情,但是下面的例子给了我们使用它们的机会。将 dialog8.html 中的现有对话框标记替换为以下内容:
<div id="myDialog" title="Best Widget Library">
<p>Is jQuery UI the greatest JavaScript widget library?</p>
<label for="yes">Yes!</label>
<input type="radio" id="yes" value="yes" name="question" checked="checked"><br>
<label for="no">No!</label>
<input type="radio" id="no" value="no" name="question">
</div>
现在将最终的 <script> 元素更改如下:
<script>
$(document).ready(function($){
var execute = function(){
var answer = $("#myDialog").find("input:checked").val();
$("<p>").text("Thanks for selecting " + answer).
appendTo($("body"));
$("#myDialog").dialog("close");
}
var cancel = function() {
$("#myDialog").dialog("close");
}
$("#myDialog").dialog({
buttons: {
"Ok": execute,
"Cancel": cancel
}
});
});
</script>
将此保存为 dialog13.html。我们的对话框小部件现在包含一组单选按钮,一些 <label> 元素和一些文本。在这个例子中,当对话框关闭时,我们将获取所选单选按钮的结果,然后执行一些操作。
我们通过填写 execute 函数来开始 <script> 元素,该函数将作为按钮对象中 Ok 属性的值附加,稍后在脚本中。因此,每次点击 Ok 按钮时都会执行它。
在这个函数中,我们使用 :checked 过滤器来确定哪个单选按钮被选中。我们将 answer 变量的值设置为单选按钮的值,然后创建一个简短的消息,并将其附加到页面的 <body> 元素中。映射到 Cancel 按钮的回调函数很简单;我们所做的就是使用 close 方法关闭对话框。
这个例子的重点在于看到从对话框获取数据就像从页面上的任何其他元素获取数据一样简单。如果你在浏览器中预览它,你会首先看到左边的对话框;点击按钮会给出相应的响应,如下面的截图所示:
探索对话框的互操作性
在以前的章节中,我们已经组合了多个小部件,以便我们可以看到它们如何很好地一起工作,本章也不例外。我们可以轻松地将其他 UI 小部件放入对话框中,例如我们在上一章中看到的折叠小部件。在文本编辑器中的新文件中,创建以下页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Dialog</title>
<link rel="stylesheet" href="development-bundle/themes/redmond/jquery.ui.all.css">
<script src="img/jquery-2.0.3.js"></script>
<script src="img/jquery.ui.core.js"></script>
<script src="img/jquery.ui.widget.js"></script>
<script src="img/jquery.ui.position.js"></script>
<script src="img/jquery.ui.dialog.js"></script>
<script src="img/jquery.ui.button.js"></script>
<script src="img/jquery.ui.accordion.js">
</script>
<script src="img/jquery.ui.mouse.js"></script>
<script src="img/jquery.ui.draggable.js"></script>
<script src="img/jquery.ui.resizable.js"></script>
<script>
$(document).ready(function($){
$("#myDialog").dialog();
$("#myAccordion").accordion();
});
</script>
</head>
<body>
<div id="myDialog" title="An Accordion Dialog">
<div id="myAccordion">
<h2><a href="#">Header 1</a></h2>
<div>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean sollicitudin.</div>
<h2><a href="#">Header 2</a></h2>
<div>Etiam tincidunt est vitae est. Ut posuere, mauris at so dales rutrum, turpis.</div>
<h2><a href="#">Header 3</a></h2>
<div>Donec at dolor ac metus pharetra aliquam. Suspendisse pu rus.</div>
</div>
</div>
</body>
</html>
将此文件保存为 dialog14.html。折叠小部件的基本标记被放置到对话框的容器元素中,我们只需在 <script> 元素中调用每个组件的小部件方法。
提示
在这个例子中,我们使用了相当多独立的 <script> 资源。值得记住的是,对于生产,我们应该使用组合和缩小的脚本文件,其中包含我们在下载构建器中选择的所有组件。
组合小部件应该像这样显示:
创建一个动态基于图像的对话框
对话框部件背后的类是紧凑的,适用于一小部分专业行为,其中大部分我们已经了解过了。我们仍然可以通过一个动态对话框来玩一些有趣的东西,这个对话框根据触发它的元素加载不同的内容。
在文本编辑器中的新页面中,添加以下代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Dialog</title>
<link rel="stylesheet" href="development-bundle/themes/redmond/jquery.ui.all.css">
<link rel="stylesheet" href="css/dialogTheme.css">
<script src="img/jquery-2.0.3.js"></script>
<script src="img/jquery.ui.core.js"></script>
<script src="img/jquery.ui.widget.js"></script>
<script src="img/jquery.ui.position.js"></script>
<script src="img/jquery.ui.dialog.js"></script>
<script src="img/jquery.ui.button.js"></script>
<script src="img/jquery.ui.accordion.js"></script>
<script src="img/jquery.ui.mouse.js"></script>
<script src="img/jquery.ui.draggable.js"></script>
<script src="img/jquery.ui.resizable.js"></script>
</head>
<body>
<div id="thumbs" class="ui-corner-all">
<div class="ui-widget-header ui-corner-top">
<h2>Some Common Flowers</h2>
</div>
<p>(click a thumbnail to view a full-size image)</p>
<div class="thumb ui-helper-clearfix ui-widget-content">
<a href="img/haFull.jpg" title="Helianthus annuus"><img src="img/haThumb.jpg" alt="Helianthus annuus"></a>
<h3>Helianthus annuus</h3>
<p>Sunflowers (Helianthus annuus) are annual plants native to the Americas, that possess a large flowering head</p>
</div>
<div class="thumb ui-helper-clearfix ui-widget-content">
<a href="img/lcFull.jpg" title="Lilium columbianum"> <img src="img/lcThumb.jpg" alt="Lilium columbianum"></a>
<h3>Lilium columbianum</h3>
<p>The Lilium columbianum is a lily native to western North America. It is also known as the Columbia Lily or Tiger Lily</p>
</div>
<div class="thumb ui-helper-clearfix ui-widget-content">
<a href="img/msFull.jpg" title="Myosotis scorpioides"> <img src="img/msThumb.jpg" alt="Myosotis scorpioides"></a>
<h3>Myosotis scorpioides</h3>
<p>The Myosotis scorpioides, or Forget-me-not, is a herbaceous perennial plant of the genus Myosotis.</p>
</div>
<div class="thumb ui-helper-clearfix ui-widget-content last">
<a href="img/nnFull.jpg" title="Nelumbo nucifera"><img src="img/nnThumb.jpg" alt="Nelumbo nucifera"></a>
<h3>Nelumbo nucifera</h3>
<p>Nelumbo nucifera is known by a number of names including; Indian lotus, sacred lotus, bean of India, or simply lotus.</p>
</div>
</div>
<div id="dialog"></div>
</body>
</html>
将此文件保存为dialog15.html。以下截图显示了在浏览器中预览时的结果:
页面相对简单——我们有一个外部容器,它包围着所有内容,以及一个我们给予了类名ui-widget-header的元素。我们使用后者是为了从正在使用的主题中获取一些默认样式。
在此之后,我们有一些解释性文本,然后是一系列容器。这些容器被赋予了几个类名,其中一些是为了我们能够对其进行样式设置,而另一些(如ui-helper-clearfix)则是为了获取框架或主题样式。
在每个容器中都有一个图像,包裹在一个锚点内,一个副标题和一些描述性文本。在外部容器之后,是一个空的<div>元素,用于创建对话框。在这个例子中,我们不使用可调整大小的功能。每个缩略图都包裹在一个锚点内,以便即使禁用了 JavaScript,页面也能正常工作。在这种情况下,对话框部件不会显示,但访问者仍然可以看到每个图像的全尺寸版本。这种渐进增强形式在这种类型的应用程序中至关重要,我们始终可以查看内容。添加对话框部件的调用是为了增强对访问者的整体视图,同时确保即使禁用了 JavaScript,内容仍将显示出来!
现在,在闭合的</head>标记之前直接添加以下<script>块:
<script>
$(document).ready(function($){
var filename, titleText, dialogOpts = {
modal: true,
width: 388,
height: 470,
autoOpen: false,
open: function() {
$("#dialog").empty();
$("<img />", { src: filename }).appendTo("#dialog");
$("#dialog").dialog("option", "title", titleText);
}
};
$("#dialog").dialog(dialogOpts);
$("#thumbs").find("a").click(function(e) {
e.preventDefault();
filename = $(this).attr("href");
titleText = $(this).attr("title");
$("#dialog").dialog("open");
});
});
</script>
我们首先定义了三个变量;第一个变量用于添加被点击的缩略图的全尺寸图像的路径,第二个用于存储用作部件标题文本的图像标题,第三个是对话框的配置对象。我们已经看到了所有的配置选项都已经在实际操作中使用过了,所以我就不会详细介绍大部分选项了。
open回调,在对话框打开之前直接调用,是我们向对话框添加全尺寸图像的地方。我们首先清空对话框,然后创建一个新的<img>元素,并将其src设置为filename变量的值。然后将新的<img>附加到对话框的内部内容区域。
然后,我们使用option方法将标题选项设置为titleText变量的值。一旦定义了open回调,我们就像平常一样调用对话框的部件方法。
我们可以使用包装器<a>元素作为打开对话框的触发器。在我们的点击处理程序中,我们首先调用e.preventDefault()来阻止点击的默认操作,然后使用被点击的链接的href和title属性设置我们的filename和titleText变量的内容。然后,我们调用对话框的open方法来显示对话框,这将触发open选项中指定的回调函数。
提示
如果我们省略e.preventDefault(),这将覆盖对话框,浏览器将呈现每个图像,就像点击了链接一样。
对于此示例,我们还需要一个新的样式表。在文本编辑器的新页面中,添加以下代码:
#thumbs { width:342px; padding: 10px 0 10px 10px; border:1px
solid #ccc; background-color:#eee; }
#thumbs p { width: 330px; font-family: Verdana; font-size: 9px;
text-align: center; }
.thumb { width: 310px; height: 114px; padding: 10px;
border:1px solid #ccc; border-bottom: none; }
.last { border-bottom: 1px solid #ccc; }
.thumb img { border: 1px solid #ccc; margin-right: 10px;
float: left; cursor: pointer; }
.thumb h3 { margin: 0; float: left; width:198px; }
#thumbs .thumb p { width: 310px; margin:0; font-family:
Verdana; font-size: 13px; text-align: left; }
#thumbs .ui-widget-header { width: 330px; text-align: center; }
在前面的示例中已经使用了许多这些样式,但是为其他页面元素添加一些新规则使我们可以在实际环境中看到对话框。将此保存为dialogTheme.css,并放入css文件夹中。我们在此示例中还使用了一些图像,这些图像可以在本书的附带代码下载的img文件夹中找到。
这样现在应该给我们提供了前面截图中看到的页面,当点击缩略图时,将显示相同图像的完整尺寸版本:
概要
对话框小部件是专门设计的,用于在悬浮面板中显示消息或问题,该面板位于页面内容之上。高级功能,如拖动和调整大小,已直接内置,并且仅需要为每个功能包含额外的脚本文件。其他功能,如出色的模态和覆盖层,易于配置。
我们首先看了默认实现,它与迄今为止我们看过的其他小部件一样简单。然后,我们检查了对话框 API 公开的一系列可配置选项。我们可以利用它们来启用或禁用内置行为,例如模态,或设置小部件的尺寸。它还为我们提供了广泛的回调,允许我们在交互期间通过小部件触发的自定义事件中挂钩。
然后,我们简要介绍了与对话框一起使用的内置打开和关闭效果,然后继续查看我们可以调用的基本方法,以执行对话框执行操作的任务,例如打开或关闭。
在下一章中,我们将继续查看滑块和进度条小部件,它们允许我们创建交互式表单小部件,用于从预定义范围中选择值并在屏幕上显示结果。
第六章:滑块和进度条小部件
滑块组件允许我们实现一个引人入胜且易于使用的小部件,我们的访问者应该会发现它吸引人且直观易用。它的基本功能很简单。滑块轨道表示一系列由沿着轨道拖动的手柄选择的值。
进度条部件用于显示任意过程的完成百分比。这是一个简单易用的组件,具有极其紧凑的 API,为访问者提供了出色的视觉反馈。
在本章中,我们将涵盖以下主题:
-
默认的滑块实现
-
滑块的自定义样式
-
更改配置选项
-
创建垂直滑块
-
设置最小值、最大值和默认值
-
启用多个手柄和范围
-
滑块的内置事件回调
-
滑块方法
-
进度条的默认实现
-
可配置的选项
-
小部件公开的事件 API
-
进度条公开的唯一方法
-
进度条的一些真实世界示例
在我们卷起袖子开始创建滑块之前,让我们看一下它由哪些不同的元素组成。以下图示显示了一个典型的滑块小部件:
正如您所见,这是一个简单的小部件,只由两个主要元素组成——滑块手柄(有时称为拇指)和滑块轨道。
引入滑块部件
创建默认的基本滑块所需的代码与我们迄今为止看过的任何其他小部件一样少。所需的基本 HTML 标记也很少。现在让我们创建一个基本的滑块。在文本编辑器的新页面中,添加以下代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Slider</title>
<link rel="stylesheet" href="development-bundle/themes/redmond/jquery.ui.all.css">
<script src="img/jquery-2.0.3.js"></script>
<script src="img/jquery.ui.core.js"></script>
<script src="img/jquery.ui.widget.js"></script>
<script src="img/jquery.ui.mouse.js"></script>
<script src="img/jquery.ui.slider.js"></script>
<script>
$(document).ready(function($){
$("#mySlider").slider();
});
</script>
</head>
<body>
<div id="mySlider"></div>
</body>
</html>
将此文件保存为slider1.html并在浏览器中查看。页面上有一个简单的容器元素;该元素将由小部件转换为滑块轨道。在代码的<head>部分中的<script>内,我们选择此元素并在其上调用slider方法。用于滑块手柄的<a>元素将由小部件自动创建。
当我们在浏览器中运行slider1.html文件时,我们应该会看到类似于上一个图示的东西。我们为默认实现使用了几个库资源,包括以下文件:
-
jquery.ui.all.css -
jquery-2.0.3.js -
jquery.ui.core.js -
jquery.ui.widget.js -
jquery.ui.mouse.js -
jquery.ui.slider.js
基本滑块的默认行为简单而有效。可以通过用鼠标指针拖动拇指或使用键盘上的左/下或右/上箭头键,在 x 轴上沿轨道的任何像素移动拇指。使用鼠标左键单击轨道上的任何位置将立即将手柄移动到该位置。
自定义样式
由于其简单性,很容易为滑块小部件创建自定义主题。使用 ThemeRoller 是其中一种主题化的方法:我们只需下载一个新主题,然后将其放入主题文件夹,并在代码中更改对新主题的引用名称。与所有其他小部件一样,滑块将被重新设计为使用新主题。
要完全改变小部件的外观和感觉,我们可以轻松创建自己的主题文件。在您的文本编辑器中创建以下样式表:
.background-div {
height: 50px; width: 217px; padding: 36px 0 0 24px;
background: url(../img/slider_outerbg.gif) no-repeat;
}
#mySlider {
background: url(../img/slider_bg.gif) no-repeat; height: 23px;
width: 184px; border: none; top: 4px; position: relative;
left: 4px;
}
#mySlider .ui-slider-handle {
width: 14px; height: 30px; top: -4px;
background: url(../img/slider_handle.gif) no-repeat;
}
将此文件保存为sliderTheme.css,放在css目录中。在slider1.html中,在页面的<head>标签中添加一个链接到样式表(在 jQuery UI 样式表之后),并将底层滑块元素包裹在一个新容器中:
<div class="background-div">
<div id="mySlider"></div>
</div>
将此文件保存为slider2.html。只需最少量的 CSS 和几张图片(这些可以在代码下载中找到),我们就可以轻松但显著地修改小部件的外观,如下面的屏幕截图所示:
让我们转向如何配置滑块小部件,使用一些选项。
配置基本滑块
还可以使用对象文字配置额外的功能,例如垂直滑块、多个手柄和步进,这些功能在初始化滑块时传递到小部件方法中。可以与滑块小部件一起使用的选项列在以下表格中:
| 选项 | 默认值 | 用法 |
|---|---|---|
animate | false | 当单击轨道时启用滑块手柄的平滑动画。 |
disabled | false | 当初始化小部件时禁用小部件。 |
max | 100 | 设置滑块的最大值。 |
min | 0 | 设置滑块的最小值。 |
orientation | auto | 设置滑块手柄移动的轴。这可以接受字符串垂直或水平。 |
range | false | 在它们之间创建一个可定制样式的元素范围。 |
step | 1 | 设置手柄沿轨道移动的步距。最大值必须能够被提供的数字整除。 |
value | 0 | 在初始化小部件时设置滑块手柄的值。 |
values | null | 接受一个值数组。每个提供的整数将成为滑块手柄的值。 |
创建一个垂直滑块
要创建一个垂直滑块,我们只需将orientation选项设置为vertical;小部件将为我们完成其余工作。
在slider1.html中,更改最后的<script>元素,使其如下所示:
<script>
$(document).ready(function($){
$("#mySlider").slider({
orientation: "vertical"
});
});
</script>
将此文件保存为slider3.html。我们只需要设置这个单一选项就可以将滑块放入vertical模式。当我们启动页面时,我们会看到滑块的操作与以前完全相同,只是现在它沿着 y 轴移动,如下图所示:
小部件默认高度为100px,除非我们在样式表中为.ui-slider-vertical提供自己的 CSS 规则。
设置最大值和最小值
默认情况下,滑块的最小值为0,最大值为100,但是我们可以使用min和max选项轻松更改这些值。将slider3.html中的配置对象更改为以下代码:
$("#mySlider").slider({
min: -50,
max: 50
});
将此文件保存为slider4.html。我们只需指定我们希望设置为起始和结束值的整数。value和values方法是滑块专有的,并且用于获取或设置单个或多个手柄的值。由于value选项默认设置为0,当我们运行slider4.html文件时,滑块拇指将从轨道中间开始,在-50和50之间。
在此示例中,当滑块手柄位于最小值时,value方法将返回-50,正如我们所期望的那样。为了证明这一点,我们可以修改slider4.html以在警报中显示此值。在滑块配置对象的下方立即添加以下代码:
$("#getValue").click(function(){
var value = $("#mySlider").slider("value");
alert("Value of slider is " + value);
});
在<body>标记中,将其更改如下:
<div id="mySlider"></div>
<p>
<button id="getValue">Get value of slider</button>
如果我们现在尝试在浏览器中预览更改,当您将手柄移动到滑块的最左端时,将会弹出一个警报。我们将在本章的使用滑块方法部分中探讨value选项。
使用滑块小部件进行步进
step选项是指滑块手柄在从轨道的最小位置移动到最大位置时跳跃的步数和位置。了解此选项如何工作的最佳方法是将其实际操作,因此将slider4.html中的配置对象更改为以下代码:
$("#mySlider").slider({
step: 25
});
将此文件保存为slider5.html。在此示例中,我们将step选项设置为25。我们尚未设置min或max选项,因此它们将采用默认值0和100。因此,通过将step设置为25,我们的意思是沿着轨道的每一步应该是轨道长度的四分之一,因为100(最大值)除以25(步长值)等于4。因此,手柄将沿着轨道从头到尾走四步。
滑块的max值应该被设置为step选项设置的任何值的整数倍;除此之外,我们可以自由选择任何值。step选项对于将访问者选择的值限制在一组预定义值中非常有用。
如果我们在这个例子中将step选项的值设置为27而不是25,滑块仍然可以工作,但手柄跳转到的轨道上的点将不相等。
对滑块小部件进行动画处理
滑块小部件配有内置动画,每当单击滑块轨道时,该动画会将滑块手柄平滑地移动到新位置。此动画默认情况下是禁用的,但我们可以通过将animate选项设置为true来轻松启用它。更改slider5.html中的配置对象,使其如下所示:
$("#mySlider").slider({
animate: true
});
将此文件保存为slider6.html。这个简单的改变可以让滑块感觉更加精致;当点击轨道时,滑块手柄不再立即移动到新位置,而是平滑地滑动到那里。
如果将step选项配置为1之外的值,并启用animate选项,则拇指将滑动到轨道上最近的步骤标记处。这可能意味着滑块拇指移动超过了被点击的点。
设置滑块的值
value选项,当在配置对象中设置为true时,确定滑块拇指的起始值。根据我们想要滑块表示的内容,手柄的起始值可能不是0。如果我们想要在轨道的中间开始而不是在开头,我们可以使用以下配置对象:
$("#mySlider").slider({
value: 50
});
将此文件保存为slider7.html。当在浏览器中加载文件时,我们可以看到手柄从轨道中间开始,而不是从开头开始,就像我们之前设置min和max选项时一样。我们也可以在初始化后设置此选项,以编程方式设置新值。
使用多个手柄
我之前提到过滑块可能有多个手柄;可以使用values选项添加额外的手柄。它接受一个数组,数组中的每个项都是一个手柄的起始点。我们可以指定尽可能多的项,直到max值(考虑到步骤):
$("#mySlider").slider({
values: [25, 75]
});
将此文件保存为slider8.html。这是我们需要做的一切;我们不需要提供任何额外的底层标记。小部件已为我们创建了两个新手柄,正如您将看到的,它们的功能都与标准单手柄完全相同。
下面的截图显示了我们的双手柄滑块:
我们可以利用双手柄滑块创建时间窗口以供日程安排使用。一个很好的例子是在旅行预订表格上。通常你需要手动输入日期,这可能有点笨拙。
相反,您可以使用双手柄滑块选择日期;用户只需将每个手柄向左或向右滑动以更改日期窗口。然后,我们可以使用本章前面描述的设置最小值和最大值部分中描述的方法来获取每个滑块手柄的位置值。
提示
当滑块有两个或更多手柄时,每个手柄都可以无障碍地移动到其他手柄之后;如果需要阻止此情况发生,可能需要考虑设置一个range。
使用范围选项
当使用多个手柄时,我们可以将range选项设置为true。这将在两个手柄之间添加一个样式化的范围元素。在slider8.html中,更改配置对象如下:
$("#mySlider").slider({
values: [25, 75],
range: true
});
将此文件保存为slider9.html。当页面加载时,我们应该看到一个样式化的<div>元素现在连接了我们的两个手柄,如下面的截图所示:
当使用两个手柄和一个范围时,两个手柄将无法在轨道上交叉。
最多可以使用两个手柄与range选项一起使用,但我们也可以仅启用一个手柄将上一个示例中的配置对象更改为以下内容:
$("#mySlider").slider({
range: "min"
});
将此文件保存为slider10.html。除了布尔值true,我们还可以提供字符串值min或max中的一个,但仅当仅使用一个手柄时。
在这个例子中,我们将其设置为min,所以当我们沿着轨道移动滑块手柄时,范围元素将从轨道的起点延伸到滑块手柄。如果我们将选项设置为max,范围将从手柄延伸到轨道的末端。
如果您想要捕获手柄在刻度上的位置,我们可以通过使用slide事件处理程序来实现。在这种情况下,我们只需要获取一个值(因为我们只有一个手柄),但是如果配置了第二个手柄,同样的原则也适用。
在slider4.html中,将以下函数添加到我们滑块的配置对象的上方:
function slideValues(event, ui){
var val0 = $("#mySlider").slider("values", 0),
endValue = parseInt(val0, 10);
$("#rangeValues").text("Range: 0 - " + endValue);
}:
然后,我们需要修改配置对象,以在适当的时候调用我们的slideValues事件处理程序:
$("#mySlider").slider({
range: "min",
slide: slideValues
});
因此,我们可以在现有标记的<body>部分下方添加以下内容以在屏幕上显示结果:
<div id="rangeValues"></div>
然后,我们可以按照我们的意愿操作该值;如果你预览结果,你将看到右侧的值发生变化;左侧的值将始终保持为0,因为这是我们代码中min选项的默认值。
使用滑块的事件 API
除了我们之前看到的选项外,还有另外五个选项用于定义在滑块交互期间不同时间执行的函数。我们使用的任何回调函数都会自动传递标准事件对象和表示滑块的对象。以下表格列出了我们可以使用的事件选项:
| 事件 | 触发时… |
|---|---|
change | 滑块的手柄停止移动并且其值已更改。 |
create | 滑块已创建 |
slide | 滑块的手柄移动。 |
start | 滑块的手柄开始移动。 |
stop | 滑块的手柄停止移动。 |
连接到这些内置的回调函数很容易。让我们组合一个基本示例来看看。将slider10.html中的配置对象更改为如下所示:
$("#mySlider").slider({
start: function() {
$("#tip").fadeOut(function() {
$(this).remove();
});
},
change: function(e, ui) {
$("<div></div>", {
"class": "ui-widget-header ui-corner-all",
id: "tip",
text: ui.value + "%",
css: { left: e.pageX-35 }
}).appendTo("#mySlider");
}
});
将此文件保存为slider11.html。在这个例子中,我们使用了两个回调选项——start和change。在start函数中,如果存在,我们选择提示工具元素,并使用 jQuery 的fadeOut()方法将其淡出。一旦从视图中隐藏,它将从页面中移除。
每次滑块手柄的值更改时都将执行change函数;当调用该函数时,我们创建工具提示并将其附加到滑块上。我们将其定位,使其出现在滑块手柄的中心上方,并给它一些框架类名称,以便根据使用的主题对其进行样式化。
在几个地方,我们使用传递给回调函数的第二个对象,即包含滑块有用信息的准备好的ui对象。在这个例子中,我们使用对象的value选项来获取滑块手柄的新值。
对于这个例子,我们还需要一个非常小的自定义样式表。在文本编辑器中,添加以下代码:
#mySlider { margin: 60px auto 0; }
#tip { position: absolute; display: inline; padding: 5px 0; width: 50px; text-align: center; font: bold 11px Verdana; top: -40px }
将此文件保存为css文件夹中的sliderTheme2.css,并从slider11.html的<head>中添加一个链接。当显示时,我们的工具提示应该如下图所示:
当所有事件选项一起使用时,事件将按以下顺序触发:
-
create -
start -
slide -
stop -
change
slide回调可能是一个相当密集的事件,因为它在每次选择手柄时都会触发鼠标移动,但它也可以通过从回调函数返回false来防止在某些情况下滑动。当同时使用stop和change回调时,change回调可能会覆盖stop回调。
与库中的所有组件一样,每个事件也可以在 jQuery 的on()方法中使用,只需在事件名前加上slider一词即可,例如,sliderstart。
使用滑块方法
滑块很直观,与库中的其他组件一样,它还配备了一系列方法,用于在初始化后以编程方式控制小部件。滑块特有的方法显示在下表中:
| 方法 | 用法 |
|---|---|
value | 将单个滑块手柄设置为新值。这将自动将手柄移动到轨道上的新位置。此方法接受一个参数,即表示新值的整数。 |
values | 当使用多个手柄时,设置指定手柄移动到新值。此方法与value方法相同,只是它接受两个参数——手柄的索引号,后跟新值。 |
destroy、disable、enable、option和widget方法对所有组件都是通用的,并且与我们期望的滑块的方式相同地工作。
正如我们在本章早些时候看到的,value和values方法是专门针对滑块的,并且可以用于获取或设置单个或多个手柄的值。当然,我们也可以使用option方法来实现这一点,所以这两种方法只是为了满足常见的实现需求而设置的快捷方式。让我们看看它们的作用。首先让我们看看value方法如何使用。
在slider11.html中,删除对sliderTheme2.css的<link>并在页面上的滑块容器后直接添加一个新的<button>元素:
<p><button type="button" id="setMax">Set to max value</button></p>
现在,更改最终的<script>元素,使其如下所示:
<script>
$(document).ready(function($){
$("#mySlider").slider();
$("#setMax").click(function() {
var maxVal = $("#mySlider").slider("option", "max");
$("#mySlider").slider("value", maxVal);
});
});
</script>
将此文件保存为slider12.html。我们为新的<button>添加了一个点击处理程序;每当它被点击时,此方法将首先确定滑块的最大值,方法是通过将一个变量设置为option方法的结果来指定我们想要获取的选项为max。一旦我们有了最大值,然后我们调用value方法,传入包含最大值的变量作为第二个参数;我们的变量将被用作新值。每当按钮被点击时,滑块手柄将立即移动到轨道的末端。
提示
将值作为选项或方法使用
在本章的许多示例中,我们提到了value(或values)作为选项或方法。这可能有点令人困惑;把value方法看作是在代码中使用值选项作为 getter 的快捷方式。
使用多个手柄同样简单,但涉及略有不同的方法。
在slider12.html中删除setMax按钮,并直接在滑块元素后添加以下两个按钮:
<p>
<button type="button" class="preset" id="low">Preset 1 (low) </button>
<button type="button" class="preset" id="high">Preset 2 (high) </button>
现在将<head>末尾的最后一个<script>元素更改为以下代码:
<script>
$(document).ready(function($){
$("#mySlider").slider({
values: [25, 75]
});
$(".preset").click(function() {
if (this.id === "low") {
$("#mySlider").slider("values", 0, 0).slider("values", 1, 25);
} else {
$("#mySlider").slider("values", 0, 75).slider("values" ,
1, 100);
}
});
});
</script>
将此文件保存为slider13.html。要触发多个手柄,我们在配置对象中指定了两个手柄的值。当页面上的两个<button>元素中的任何一个被点击时,我们会确定是单击了预设 1还是预设 2,然后根据点击的按钮设置手柄为低值或高值。
提示
你也可以使用数组表示法来设置滑块中的值;这将为所有手柄设置相同的值,而不管存在多少手柄。
values方法接受两个参数。第一个参数是我们想要更改的手柄的索引号,第二个参数是我们希望手柄设置的值。以下截图显示了在单击第二个按钮后页面应该显示的样子:
实际用途
HTML5 元素可能特别适合滑块小部件的实现是<audio>元素。此元素将自动添加控件,使访问者可以播放、暂停和调整正在播放的媒体的音量。
但是,默认控件无法进行样式化;如果我们希望改变它们的外观,就需要创建我们自己的控件。当然,滑块小部件是默认音量控制的绝佳替代品。让我们看看如何添加一个,作为你自己项目的基础,你可以在其中进一步发展。
在文本编辑器中创建以下新代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Slider</title>
<link rel="stylesheet" href="development-bundle/themes/redmond/jquery.ui.all.css">
<link rel="stylesheet" href="css/sliderTheme3.css">
<script src="img/jquery-2.0.3.js"></script>
<script src="img/jquery.ui.core.js"></script>
<script src="img/jquery.ui.widget.js"></script>
<script src="img/jquery.ui.mouse.js"></script>
<script src="img/jquery.ui.slider.js"></script>
<script>
$(document).ready(function($){
var audio = $("audio")[0];
audio.volume = 0.5;
audio.play();
$("#volume").slider({
value: 5,
min: 0,
max: 10,
change: function() {
var vol = $(this).slider("value") / 10;
audio.volume = vol;
}
});
});
</script>
</head>
<body>
<audio id="audio" controls="controls" src="img/prelude.mp3">
Your browser does not support the <code>audio</code> element.
</audio>
<div id="volume"></div>
</body>
</html>
将此文件保存为slider14.html。我们还需要添加一些样式来调整显示。在文本编辑器中的新页面中添加以下内容,并将其保存为sliderTheme3.css:
#volume { padding-top: 5px; }
#volume.ui-slider { width: 300px; }
.ui-slider-horizontal .ui-slider-handle { margin-left: -0.6em; top: -0.1em; }
不要忘记从主页添加到sliderTheme3.css的链接:
<link rel="stylesheet" href="css/sliderTheme3.css">
在slider14.html页面上,我们有一个<audio>标记,其src属性设置为来自互联网档案馆的音频剪辑。我们还有一个空的容器元素用于我们的音量控制。
注意
这个示例使用了 Jan Morgenstern 为大兔子电影创建的音乐配乐文件之一;你可以在 archive.org/details/JanMorgenstern-BigBuckBunny 下载它以及收藏中的其他文件。
在脚本中,我们首先使用标准的 jQuery 语法选择<audio>元素,并从 jQuery 对象中检索实际的 DOM 元素,以便我们可以从<audio>API 中调用方法。
接下来,我们为我们的滑块定义配置对象并设置初始最小和最大值。然后,我们添加一个用于更改当前播放音轨音量的change事件处理程序,使用volume属性方法。每当滑块被更改时,我们都会得到一个新的滑块值,并将其转换为所需的volume属性格式,方法是将滑块值除以10。一旦我们的变量被定义,我们就设置音频剪辑的音量,并立即使用play()方法播放音频剪辑。
当我们在支持的浏览器中运行此示例时,我们可以暂停或播放音频剪辑;如果移动滑块手柄,则剪辑的音量应该增加或减少,如下图所示:
创建一个颜色滑块
在某些应用程序中非常有用的滑块小部件的有趣实现是颜色滑块。让我们将学到的关于此小部件的知识付诸实践,制作一个基本的颜色选择工具。以下屏幕截图显示了我们将要制作的页面:
在你的文本编辑器中,将slider1.html中的<body>标记更改为以下代码:
<div id="container" class="ui-widget ui-corner-all ui-widget-content ui-helper-clearfix">
<label>R:</label>
<div id="rSlider"></div><br>
<label>G:</label>
<div id="gSlider"></div><br>
<label>B:</label>
<div id="bSlider"></div>
<div id="colorBox" class="ui-corner-all ui-widget-content"></div>
<label for="output" id="outputLabel">Color value:</label>
<input id="output" type="text" value="rgb(255,255,255)">
</div>
现在让我们为我们的演示添加script功能,所以请继续移除最后一个<script>元素的内容,并添加以下代码:
<script>
$(document).ready(function($){
$("#rSlider, #gSlider, #bSlider").slider({
min:0,
max: 255,
value: 255,
slide: function() {
var r = $("#rSlider").slider("value"),
g = $("#gSlider").slider("value"),
b = $("#bSlider").slider("value");
var rgbString = ["rgb(", r, ",", g, ",", b, ")"].join("");
$("#colorBox").css({
backgroundColor: rgbString
});
$("#output").val(rgbString);
}
});
});
</script>
将此文件保存为slider15.html。页面本身非常简单。我们有一些主要用于显示颜色滑块的不同组件的元素,以及将被转换为滑块小部件的各个容器元素。我们为我们的颜色选择器使用了三个滑块,每个滑块对应一个 RGB 通道。
我们还需要一些 CSS 来完善我们小部件的整体外观。在你的文本编辑器中新建一个页面,创建以下样式表:
#container { width: 426px; height: 146px; padding: 20px 20px 0; position: relative; font-size: 11px; background: #eee; }
#container label { float: left; text-align: right; margin: 0 30px 26px 0; clear: left; }
.ui-slider { width: 240px; float: left; }
.ui-slider-handle { width: 15px; height: 27px; }
#colorBox { width: 104px; height: 94px; float: right; margin: -83px 0 0 0; background: #fff; }
#container #outputLabel { float: right; margin: -14px 34px 0 0; }
#output { width: 100px; text-align: center; float: right; clear: both; margin-top: -17px; }
将此文件保存为colorSliderTheme.css在css文件夹中;别忘了在主文件中调用 jQuery UI 样式表后立即添加对此文件的链接:
<link rel="stylesheet" href="css/colorSliderTheme.css">
在我们的代码中,我们给容器和颜色框元素分配了来自 CSS 框架的类名,这样我们就可以利用诸如圆角之类的效果,以减少我们自己编写的 CSS 量。
关注 JavaScript 代码,我们首先设置配置对象。由于 RGB 颜色值范围从0到255,我们将max选项设置为255,将value选项也设置为255,这样小部件手柄就会在正确的位置开始(页面加载时,颜色框将具有白色背景)。
slide回调是行动发生的地方。每当移动一个手柄时,我们都会使用value方法更新r、g和b变量的值,然后从我们的变量值构造一个新的 RGB 字符串。这是必要的,因为我们不能直接将变量传递给 jQuery 的css()方法。我们还会更新<input>字段中的值。
运行示例时,我们应该发现一切都按预期工作。一旦我们开始移动任何一个滑块手柄,颜色框就开始变色,而<input>也会更新。
注意
slide事件在选定手柄后的每次鼠标移动时触发;这是一个潜在的密集型事件,在旧浏览器或慢速计算机上可能会引起问题。因此,在生产环境中使用时应谨慎,以使事件处理程序中的不必要操作最小化。
引入进度条小部件
小部件只由两个嵌套的<div>元素组成——一个外部<div>容器和一个内部<div>容器,用于突出显示当前进度。下图显示了一个完成 50%的进度条:
让我们来看看最基本的进度条实现。在文本编辑器中的新文件中,创建以下代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Progressbar</title>
<link rel="stylesheet" href="development-bundle/themes/redmond/jquery.ui.all.css">
<script src="img/jquery-2.0.3.js"></script>
<script src="img/jquery.ui.core.js"></script>
<script src="img/jquery.ui.widget.js"></script>
<script src="img/jquery.ui.progressbar.js"></script>
<script>
$(document).ready(function($){
$("#myProgressbar").progressbar();
});
</script>
</head>
<body>
<div id="myProgressbar"></div>
</body>
</html>
将此文件保存为jqueryui项目文件夹中的progressbar1.html。没有配置时,进度条当然是空的。我们的示例应该看起来像第一张截图,但没有显示任何进度(容器为空)。
进度条依赖以下组件:
-
jquery.ui.all.css -
jquery-2.0.3.js -
jquery-ui.core.js -
jquery-ui.progressbar.js
页面上所需的全部就是一个简单的容器元素。在这种情况下,我们使用了一个<div>元素,但是其他块级元素,比如<p>,也可以使用。小部件会在初始化时向指定的容器元素添加一个表示进度条值的嵌套<div>元素。
此小部件与其他一些小部件(如手风琴)一样,会自然填满其容器的宽度。其他也以类似方式工作的小部件包括标签页、手风琴、滑块和菜单——每个都需要某种形式的容器来限制其在屏幕上的大小。组件会给容器和内部<div>元素分别添加一系列属性和类名。类名从正在使用的theme文件中获取样式,并且组件完全支持 ThemeRoller。支持 ThemeRoller 意味着你选择的主题可以轻松地更改为另一个 jQuery ThemeRoller 主题,并且小部件将继续正常工作,无需对样式进行任何更改。
添加到小部件的其他属性符合 ARIA 规范,使小部件对使用辅助技术的访问者完全可访问。ARIA(Accessible Rich Internet Applications)定义了使 Web 内容对使用辅助技术(如屏幕阅读器)的人更具可访问性的方法。所有 jQuery 小部件都对 ARIA 有不同程度的支持,包括进度条;这是通过在代码中出现其他标签来提供的,例如以下代码中突出显示的标签:
<div id="myProgressbar" class="ui-progressbar ui-widget ui-widget-content ui-corner-all" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="20">
这些帮助将代码转换为辅助技术将理解的内容;没有它们,代码实际上是隐藏的,这会影响最终用户将看到或听到的内容。
列出进度条的选项
写作时,进度条有三个配置选项:
| 选项 | 默认值 | 用法 |
|---|---|---|
disabled | false | 禁用小部件 |
Max | 100 | 进度条的最大值 |
Value | 0 | 设置小部件的值(以百分比表示) |
设置进度条的值
更改progressbar1.html中的最终<script>元素,使其显示如下:
<script>
$(document).ready(function($){
$("#myProgressbar").progressbar({
value: 50
});
});
</script>
将此文件保存为progressbar2.html。value选项接受一个整数,并将小部件的内部<div>的宽度设置为相应的百分比。此更改将使小部件显示为本章第一个屏幕截图中的样子,进度条填充了一半。
进度条的事件 API
进度条公开了三个自定义事件,如下表所示:
| 事件 | 当...时触发 |
|---|---|
create | 初始化小部件 |
change | 小部件的值更改 |
complete | 小部件的值达到 100% |
与其他小部件一样,我们可以在配置对象中以匿名回调函数的形式提供这些事件的值,组件将自动为我们调用该函数,每次事件发生时。
要在progressbar2.html页面中看到此事件的实际效果,请添加以下<button>:
<p><button id="increase">Increase by 10%</button>
接下来,将最终的<script>块更改为以下内容:
<script>
$(document).ready(function($){
var progress = $("#myProgressbar"),
progressOpts = {
change: function() {
var val = $(this).progressbar("option", "value");
if (!$("#value").length) {
$("<span />", { text: val + "%", id: "value"}).appendTo(progress);
} else {
$("#value").text(val + "%");
}
}
};
progress.progressbar(progressOpts);
$("#increase").click(function() {
var currentVal = progress.progressbar("option", "value"),
newVal = currentVal + 10;
progress.progressbar("option", "value", newVal);
});
});
</script>
将此文件保存为progressbar3.html。我们还需要为我们的进度条添加一些样式,因此请添加以下内容到一个新文件,并将其保存为progressIncrease.css:
#value { margin-top: -28px; margin-right: 10px; float: right; }
不要忘记从页面的<head>中添加链接到新样式表(在标准 jQuery UI 样式表之后):
<link rel="stylesheet" href="css/progressIncrease.css">
在我们的示例中,我们首先缓存了进度条的选择器,然后为change事件定义了一个事件处理程序。在这个回调函数中,我们首先获取进度条的当前值,这个值将对应于其上次更新后的值。当在事件处理程序内部时,我们可以使用$(this)选择进度条。
假设值小于或等于 100(百分比),我们检查页面上是否已经存在具有id为value的元素。如果元素不存在(即其值没有长度),我们创建一个新的<span>元素,并将其文本设置为当前值。我们还给它一个id属性并将其定位,以便它出现在进度条内。如果元素已经存在,我们只需将其文本更新为新值。
提示
使用自关闭快捷标签选择器
您可能已经在代码中看到了$("<span />")的使用;这是 jQuery 用于生成标签的完整版本的快捷方式;在这种情况下,它会将其传递的任何内容封装在<span>…</span>标签中。
我们还为页面上添加的按钮添加了点击处理程序。每当按钮被点击时,我们首先使用getter模式中的option方法获取进度条的当前值。然后,在将值增加10之后,我们使用setter模式中的option方法将内部<div>的值增加10个百分点。将该值添加到<span>元素中以指示进度。
点击按钮的结果如下所示:
在本例中,每当**增加 10%**按钮被点击时,我们都手动设置进度条的值;我们使用标准的option方法,该方法适用于所有 UI 库组件,以检索有关进度条当前状态的信息。
不要忘记,像其他库组件一样,此事件也可以通过在事件名称上添加小部件名称前缀来使用 jQuery 的on()方法,例如,progressbarchange。
使用进度条方法
除了所有库组件都公开的常见 API 方法(如destroy、disable、enable、widget和option)之外,滑块 API 还公开了value方法,该方法是使用option方法设置进度条值的快捷方式。
我们可以完全像上一个示例中所做的那样,但代码更少,使用value方法。更改progressbar3.html中的最后一个<script>元素,使其如下所示:
<script>
$(document).ready(function($){
var progress = $("#myProgressbar");
progress.progressbar();
$("#increase").click(function() {
var currentVal = progress.progressbar("option", "value"), newVal = currentVal + 10;
progress.progressbar("value", newVal);
if (!$("#value").length) {
$("<span />", { text: newVal + "%", id: "value"
}).appendTo(progress);
} else {
$("#value").text(newVal + "%");
}
});
});
</script>
将此文件保存为progressbar4.html。在这个例子中,我们丢失了配置对象,因为它不是必需的。
使用value方法增加值的逻辑已经移到了<button>元素的点击处理程序中。在事件处理程序中,我们获取currentVal的值,然后加上10,并将其赋值给newVal。进度条小部件的value属性被更新为新值;进行检查以查看百分比计数文本是否存在。如果不存在(即#value的长度为零),则我们添加一个新的实例,其中包含更新后的数字,并在屏幕上显示此数字。
但随着更新代码移动到事件处理程序中,我们看到这使我们能够以更简洁的格式执行与上一个示例相同的操作。
添加不定支持
到目前为止,我们已经看到了在更新其结果时如何控制进度条应该使用的百分比值。但是,在某些情况下可能无法始终这样做 - 为了解决这个问题,可以使用一个不定选项。在 jQuery UI 1.10 中添加了这个选项,它允许在不能更新值的情况下使用。这是一个示例,如下图所示:
让我们看一些例子来比较设置已知值和不确定值之间的差异。在progressbar4.html中,将<script>元素更改为以下代码:
<script>
$(document).ready(function($){
$("#myprogressbar").progressbar({ value: false });
$("button").on("click", function(event) {
var target = $(event.target), progressbar = $("#myprogressbar"), progressbarValue = progressbar.find(".ui-progressbar-value");
if (target.is("#numButton")) {
progressbar.progressbar("option", { value: Math.floor(Math.random() * 100) });
} else if (target.is("#falseButton")) {
progressbar.progressbar("option", "value", false);
}
});
});
</script>
在代码的<body>元素中,将 HTML 更改为以下代码:
<div id="myprogressbar"></div>
<p>
<button id="numButton">Random Value - Determinate</button>
<button id="falseButton">Indeterminate</button>
将此文件另存为progressbar5.html。点击不定按钮的结果如下截图所示:
虽然在纸质版本中很难看到它的实际效果,但上一个例子显示了一个持续移动的进度条达到 100%,点击不定按钮会将value属性设置为false,告诉进度条假定值为 100%。在这种情况下,自动设置为 100%,表示我们正在取得进展。由于我们无法准确地得出在每个点上取得了多少进展,进度条小部件会自动假定该值为 100%。
相比之下,如果我们知道进度条应该使用的值,我们可以设置该值。点击随机值 - 确定按钮,在本章的示例中以类似的方式显示设置这样一个值的效果,如下截图所示:
响应用户交互
在其最基本的层面上,我们可以在响应用户交互时手动更新进度条。例如,我们可以指定一种向导式表单,其中有几个步骤要完成。在这个示例中,我们将创建一个如下截图所示的表单:
在每个步骤期间,我们可以手动递增进度条,以让用户知道他们进行到了多远的进程。在 progressbar5.html 中,用以下代码替换进度条容器和按钮:
<div class="form-container ui-helper-clearfix ui-corner-all">
<h1>Registration Form</h1>
<p>Progress:</p>
<div id="myProgressbar"></div>
<label id="amount">0%</label>
<form action="serverScript.php">>
<div class="form-panel">
<h2>Personal Details</h2>
<fieldset class="ui-corner-all">
<label for="name">Name:</label>
<input id="name" type="text">
<label for="dob">D.O.B:</label>
<input id="dob" type="text">
<label for="passwrd1">Choose password:</label>
<input id="passwrd1" type="password">
<label for="passwrd2">Confirm password:</label>
<input id="passwrd2" type="password">
</fieldset>
</div>
<div class="form-panel ui-helper-hidden">
<h2>Contact Details</h2>
<fieldset class="ui-corner-all">
<label for="email">Email:</label>
<input id="email" type="text">
<label for="tel">Telephone:</label>
<input id="tel" type="text">
<label for="address">Address:</label>
<textarea id="address" rows="3" cols="25"></textarea>
</fieldset>
</div>
<div class="form-panel ui-helper-hidden">
<h2>Registration Complete</h2>
<fieldset class="ui-corner-all">
<p>Thanks for registering!</p>
</fieldset>
</div>
</form>
<button id="next">Next</button>
<button id="back" disabled="disabled">Back</button>
</div>
将此文件保存为 progressbar6.html。在 <head> 部分,我们添加了一个链接到框架主题文件,就像我们在本章的其他示例中所做的那样,并且将需要添加一个链接到稍后添加的自定义样式表:
<link rel="stylesheet" href="css/progressTheme.css">
页面的 <body> 元素包含一些布局元素和一些文本节点,但主要元素是进度条的容器和 <form>。<form> 部分使用 <div> 和 <fieldset> 元素分隔为几个不同的部分。这样做的原因是我们可以隐藏表单的部分,使其看起来好像跨越了几个页面。
我们在进度条旁边添加了一个段落和一个 <label> 参数。我们将对它们进行定位,使它们出现在小部件内部。段落包含一个简单的文本字符串。标签将用于显示当前进度值。
外部容器被赋予几个类名;第一个是我们可以对元素应用一些自定义样式,但下一个两个是为了针对 jQuery UI CSS 框架的不同特性。ui-helper-clearfix 类用于自动清除浮动元素,并且是减少 <div> 元素的额外和不必要的清除混乱的好方法。在创建自己的小部件时,请不要忘记显式使用此类和其他框架类。
提示
我们在第二章中介绍了一些核心 CSS 类;CSS 框架 API 的更多详细信息可在learn.jquery.com/jquery-ui/theming/api/上找到。
ui-corner-all 类用于给容器元素(以及进度条本身,它们自动具有这些特性,以及我们的 <fieldset> 元素)添加圆角,使用了几个专有的样式规则。这些现在被大多数现代浏览器支持。我们还有一个下一个按钮来在每个面板之间前进,并且一个默认情况下被禁用的返回按钮。
我们在表单中使用 CSS 框架的另一个类。页面首次加载时需要隐藏多个面板;因此,我们可以使用 ui-helper-hidden 类来确保它们设置为 display: none。当我们想要显示它们时,我们只需删除此类名。
现在让我们添加 JavaScript。更改页面底部的最后一个 <script> 元素,使其显示如下:
$(document).ready(function($){
var prog = $("#myProgressbar"), progressOpts = {
change: function() {
prog.next().text(prog.progressbar("value") + "%");
}
};
prog.progressbar(progressOpts);
$("#next, #back").click(function() {
$("button").attr("disabled", true);
if (this.id == "next") {
prog.progressbar("option", "value",
prog.progressbar("option", "value") + 50);
$("form").find("div:visible").fadeOut().next()
.fadeIn(function(){
$("#back").attr("disabled", false);
if (!$("form").find("div:last").is(":visible")) {
$("#next").attr("disabled", false);
}
});
} else {
prog.progressbar("option", "value", prog.progressbar("option", "value") - 50);
$("form").find("div:visible").not(".buttons").fadeOut() .prev().fadeIn(function() {
$("#next").attr("disabled", false);
if (!$("form").find("div:first").is(":visible")) {
$("#back").attr("disabled", false);
}
});
}
});
});
我们首先缓存进度条的选择器,并定义我们的配置对象,利用change事件来指定一个匿名回调函数。每次事件被触发时,我们将使用value方法获取进度条的当前值,并将其设置为直接在进度条元素之后的<label>参数的文本。事件在更改发生后触发,因此我们获得的值将始终是新值。
一旦进度条被初始化,我们为表单后的按钮添加一个点击处理程序。在此处理程序函数内,我们首先禁用两个按钮,以防止重复点击<button>导致表单破坏。然后,我们使用if语句运行稍微不同的代码分支,具体取决于所点击的按钮。
如果点击了下一步按钮,则通过将value选项设置为当前值加上50%来将进度条的值增加50%。然后,我们淡出当前可见的面板,并淡入下一个面板。我们使用回调函数作为fadeIn()方法的参数,该函数将在动画结束时执行。
在此功能内,我们重新启用返回按钮(因为点击了下一步,所以第一个面板不可见,因此应该启用此按钮),并确定是否启用下一步按钮,只要最后一个面板不可见,就可以完成此操作。
外部if语句的第二个分支处理了点击返回按钮的情况。在这种情况下,我们将进度条减少50%,启用下一步按钮,并检查是否应启用返回按钮。
这现在是我们所需的所有 JavaScript 代码。现在我们所要做的就是添加一些基本的 CSS 来布置示例;在文本编辑器中的新文件中添加以下代码:
h1, h2 { font-family: Tahoma; font-size: 140%; margin-top: 0;}
h2 { margin: 20px 0 10px; font-size: 100%; text-align: left; }
p { margin: 0; font-size: 95%; position: absolute; left: 30px; top: 60px; font-weight: bold; }
#amount { position: absolute; right: 30px; top: 60px; font- size: 80%; font-weight: bold; }
#thanks { text-align: center; }
#thanks p { margin-top: 48px; font-size: 160%; position: relative; left: 0; top: 0; }
form { height: 265px; position: relative; }
.form-container { width: 400px; margin: 0 auto; position: relative; font-family: Verdana; font-size: 80%; padding: 20px; background-color: #C5DBEC; border: 1px solid #2E6E9E; }
.form-panel { width: 400px; height: 241px; position: absolute; top: 0; left: 0; }
fieldset { width: 397px; height: 170px; margin: 0 auto; padding: 22px 0 0; border: 1px solid #abadac; background-color: #ffffff; }
label { width: 146px; display: block; float: left; text-align: right; padding-top: 2px; margin-right: 10px; }input, textarea { float: left; width: 200px; margin-bottom: 13px; }
button { float: right; }
将此保存为 progressTheme.css 在 css 目录中。现在,我们应该有一个带有已连接的进度条的工作页面。当我们运行页面时,我们应该发现我们可以浏览表单的每个面板,并且进度条将相应地更新自身。
我们仍然依赖用户交互来设置进度条的值,在这个示例中,这是由访问者通过每个面板进行导航驱动的。
使用带有进度条的丰富上传
不再依赖用户交互来增加进度条的值,从而完成指定的任务,我们可以依赖系统来更新它,只要有可用的东西可以准确地更新它。
在我们最终的进度条示例中,我们可以整合 HTML5 文件 API,以便异步上传文件,并可以使用onprogress事件来在文件上传时更新进度条。
提示
此时,您可能想获取伴随本书的代码下载副本,以便您可以在学习示例的同时查看代码。
这个示例只有在安装了并配置了 PHP 的完整 Web 服务器时才能正常工作。在这个示例中,我们不会查看上传过程的服务器端部分;我们只对一旦上传完成,根据从系统收到的反馈来更新进度条感兴趣。
修改progressbar6.html中的<body>,使其包含以下元素:
<div id="container">
<h1>HTML5 File Reader API</h1>
<form id="upload" action="upload.php" method="POST" enctype="multipart/form-data">
<fieldset>
<legend>Image Upload</legend>
<input type="hidden" id="MAX_FILE_SIZE" name="MAX_FILE_SIZE"value="300000" />
<div>
<label for="fileselect">Image to upload:</label>
<input type="file" id="fileselect" name="fileselect[]"multiple="multiple" />
</div>
<div id="progress"></div>
</fieldset>
</form>
<div id="messages"></div>
</div>
在页面上,我们有一个file类型的<input>元素,后面跟着进度条的容器,就像往常一样。接下来,让我们添加脚本;将<head>末尾的最后一个<script>元素更改为以下代码:
$("document").ready(function($) {
if (window.File && window.FileList && window.FileReader) {
$("#fileselect").on("change", function(e) {
var files = e.target.files || e.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
ParseFile(f);
UploadFile(f);
}
});
}
});
将此文件保存为progressbar7.html。将以下代码添加到一个新文档中,并保存为uploads.js:
function ParseFile(file) {
$("#messages").html(
"<p>File information: <strong><br>" +
"</strong> type: <strong>" + file.type + "<br>" +
"</strong> size: <strong>" + file.size +
"</strong> bytes</p>"
);
if (file.type.indexOf("image") === 0) {
var reader = new FileReader();
reader.onload = function(e) {
$("#messages").prepend(
"<br>Image:<br><strong>" + file.name + "</strong><br />" +
'<img class="preview" src="img/' + e.target.result + '" /></p>'
);
};
reader.readAsDataURL(file);
}
}
function UploadFile(file) {
$("#progress").progressbar();
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = function updateProgress(e) {
var fileloaded = (e.loaded / e.total);
$("#progress").progressbar("value", Math.round(fileloaded * 100));
};
xhr.upload.onload = function() {
$("#progress").progressbar("value", 100);
};
xhr.open("POST", $("#upload").action, true);
xhr.setRequestHeader("X_FILENAME", file.name);
xhr.send(file);
}
最后,在文档的<head>元素下方立即添加以下内容:
<script type="text/javascript" src="img/uploads.js"></script>
首先,在progressbar7.html中,我们进行检查以确认浏览器是否支持 File API;如果可以,我们就会启动一个事件处理程序,该处理程序会在点击fileselect按钮时立即触发。
在更改处理程序中,我们获取所选文件的详细信息并将其保存到数组中;然后,我们调用ParseFile()函数(在uploads.js中)来首先启动输出消息,然后使用FileReader()加载和读取图像的副本,并将图像的副本输出到屏幕。同时,我们显示图像名称的详细信息。
继续到uploads.js,然后我们调用UploadFile函数,这就是真正的魔法发生的地方。我们首先初始化一个进度条的实例,给它一个progress ID,并使用一个<div>元素作为其容器。然后,代码设置了一个XMLHttpRequest()的实例,并打开了一个POST连接以上传文件。在这种情况下,文件实际上只上传到服务器上的一个测试文件夹(或在这种情况下,您的个人电脑上),称为 uploads;在这一点上,您将创建一个上传脚本,该脚本将把文件重定向到远程服务器上的适当位置。
每当XMLHttpRequest参数更新时,它都会触发onprogress事件处理程序来更新进度条;我们计算总文件大小与已上传内容之间的差异,然后将其转换为百分比,并用此百分比来更新进度条。一旦上传完成,我们就会触发onload()事件处理程序,以确保它显示 100% 完成。
对于这个示例,我们还需要一些 CSS;在一个新的文本文件中添加以下代码:
body { font-family: "Segoe UI", Tahoma, Helvetica, Freesans, sans-serif; font-size: 90%; margin: 10px; color: #333; background-color: #fff; }
#container { margin-left: auto; margin-right: auto; width: 430px; }
#messages { padding: 0 10px; margin: 1em 0; border: 1px solid #999; width: 400px; clear: both; height: 275px; }
#messages p { position: absolute; float: left; margin-left: 275px; width: 150px; }
#progress { margin-top: 3px; width: 390px; left: -2px; }
h1 { font-size: 1.5em; font-weight: normal; }
legend { font-weight: bold; color: #333; }
.preview { height: 60%; width: 60%; float: left; }
fieldset { width: 400px; }
此文件可以保存在css文件夹中,命名为uploads.css。大部分样式只是定位各个元素并设置进度条的宽度。我们也不需要链接到progressTheme.css,因此也可以将其删除。
当我们运行这个文件时,我们应该看到一旦选择了文件,它就会自动开始上传,并且进度条将开始填充。如果在本地进行测试,速度会相当快,所以最好使用相当大的文件进行测试。
以下屏幕截图显示了上传完成后的页面:
总结
在本章中,我们看了两个界面小部件,它们都可以提供某种形式的视觉反馈,无论是作为操作的结果还是设置特定的值。我们看到了如何快速、简单地将滑块小部件放在页面上,并且它需要最少的底层标记和仅一行代码来初始化。
我们探讨了可以设置的不同选项,以控制滑块的行为以及在初始化后如何配置它,同时提供可以在交互期间的重要时间执行代码的回调。我们还介绍了可以用于以编程方式与滑块进行交互的方法,包括用于设置手柄值的方法,或在初始化后获取和设置配置选项的方法。
我们还查看了具有紧凑 API 的进度条小部件,它在进程进行时提供了必要的访问者反馈。然后我们研究了在初始化之前或小部件正在使用时可以用来配置小部件的各种选项。我们还研究了可用于与进度条小部件一起工作的方法,看看我们如何可以轻松地对进度更改做出反应,或者在小部件完成后做出反应。
我们还看了进度条如何包含对不确定进度指示器的支持,用于在当前进程状态无法精确确定时使用。
在下一章中,我们将看到日期选择器小部件,它拥有库中所有小部件中最大、功能最丰富的 API,并包含完整的国际化支持。
第七章:日期选择器小部件
jQuery UI 日期选择器小部件可能是 jQuery 库中最精细和文档化的小部件。它具有最大的应用程序编程接口(API),可能提供了所有小部件中最多的功能。它不仅可以立即使用,而且还可以高度配置和健壮。
简单地说,日期选择器小部件提供了一个界面,让您网站或应用的访问者选择日期。无论何处需要填写日期的表单字段,都可以添加日期选择器小部件。这意味着您的访问者可以使用一个吸引人并且交互性强的小部件,而您可以得到您期望的日期格式。
在本节中,我们将讨论以下主题:
-
默认日期选择器的实现
-
探索可配置选项
-
实现触发按钮
-
配置替代动画
-
dateFormat选项 -
简单的本地化
-
多月日期选择器
-
数据范围选择
-
日期选择器小部件的方法
-
使用 AJAX 与日期选择器
内置到日期选择器中的其他功能包括自动打开和关闭动画以及使用键盘导航小部件界面的能力。在按住Ctrl键(或 Mac 上的命令键)时,键盘上的箭头可以用来选择新的日期单元格,然后可以使用返回键进行选择。
尽管易于创建和配置,但日期选择器是一个由各种底层元素组成的复杂小部件,如下图所示:
注意
尽管存在这种复杂性,但我们可以只用一行代码来实现默认日期选择器,就像我们迄今为止介绍的库中的其他小部件一样简单。
实现日期选择器小部件
要创建默认日期选择器,请在文本编辑器中的新页面中添加以下代码:
<!DOCTYPE html>
<html>
<head>
<meta charset = "utf-8">
<title>Datepicker</title>
<link rel="stylesheet" href="development-bundle/themes/redmond/jquery.ui.all.css">
<script src="img/jquery-2.0.3.js"></script>
<script src="img/jquery.ui.core.js"></script>
<script src="img/jquery.ui.widget.js"></script>
<script src="img/jquery.ui.datepicker.js"> </script>
<script>
$(document).ready(function($){
$("#date").datepicker();
});
</script>
</head>
<body>
<label for="date">Enter a date:</label>
<input id="date" />
</body>
</html>
将此保存为jqueryui项目文件夹中的datePicker1.html。我们页面上只有一个<label>和一个标准文本<input>元素。我们不需要为了渲染日期选择器小部件而指定任何空容器元素,因为创建小部件所需的标记会被库自动添加。
提示
尽管在您的<input>语句中使用 HTML5 的type="date"属性可能很诱人,但不建议这样做——这可能会导致冲突,即同时显示 jQuery UI 日期选择器和本机 HTML5 版本。
当您在浏览器中运行页面并聚焦于<input>元素时,默认日期选择器应该出现在输入框下方。除了一个<input>元素外,日期选择器也可以附加到一个<div>元素上。
除了外观漂亮之外,默认日期选择器还带有许多内置功能。当日期选择器打开时,它会平滑地从零到全尺寸进行动画,并且将自动设置为当前日期。选择日期将自动将日期添加到 <input> 并关闭日历(再次使用漂亮的动画)。
如果没有额外的配置并且只有一行代码,我们现在已经拥有了一个完全可用且具有吸引力的小部件,使日期选择变得容易。如果您只想让人们选择一个日期,这就是您所需要的全部。默认日期选择器所需的源文件如下:
-
jquery-2.0.3.js -
jquery.ui.core.js -
jquery.ui.widget.js -
jquery.ui.datepicker.js
使用内联日历选择日期
我们创建了一个基本的日期选择器小部件,将其链接到一个普通的文本 <input> 框中。虽然这样做完全没问题,但有时您可能不想使用普通输入框,而只需在页面中显示已打开的日历。
幸运的是,使用日期选择器小部件很容易实现。更改 HTML 代码以使用 <div> 元素,如下代码所示:
<body>
Enter a date: <div id="date"></div>
</body>
如果在浏览器中预览结果,您会注意到输入文本框已经消失,并且日历已经完全显示出来:
日期选择器的可配置选项
日期选择器具有大量可配置的选项(目前确切为 50 个)。以下表格列出了基本选项、它们的默认值,并简要描述了它们的用法:
| 选项 | 默认值 | 用法 |
|---|---|---|
altField | "" | 指定替代 <input> 字段的 CSS 选择器,其中还添加了所选日期。 |
altFormat | "" | 指定要添加到替代 <input> 中的日期的替代格式。有关此选项接受的值的澄清,请参见后面部分中的 dateFormat 选项。 |
appendText | "" | 在日期选择器 <input> 后添加文本以显示所选日期的格式。 |
autoSize | false | 自动设置 <input> 元素的宽度,以便根据指定的 dateFormat 容纳日期。 |
beforeShow | null | 允许日期选择器配置对象在调用之前更新日期选择器。 |
beforeShowDay | null | 接受日期作为参数,并返回值以指示该日期是否可选择,要添加到日期单元格的类名,以及日期的(可选)弹出工具提示。该函数在日期选择器中的每一天显示之前调用。 |
buttonImage | "" | 指定用于触发 <button> 的图像的路径。 |
buttonImageOnly | false | 设置为 true 以使用图像而不是触发按钮。 |
buttonText | "..." | 提供要显示在触发 <button> 上的文本(如果存在)。 |
calculateWeek | $.datepicker. iso8601Week | 接受一个函数,用于计算指定日期的一年中的周数。 |
changeMonth | false | 显示月份更改下拉列表。 |
changeYear | false | 显示年份更改下拉列表。 |
closeText | ||
constrainInput | true | 将 <input> 元素限制为小部件指定的日期格式。 |
currentText | "今天" | 用于当前日期链接的显示文本。必须与 showButtonPanel 属性一起使用才能显示此按钮。 |
dateFormat | 用于解析和显示日期的格式。在本章后面的 更改日期格式 部分显示了完整的格式列表。 | |
dayNames | [ "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" ] | 用于与 dateFormat 属性结合使用的长日期名称列表。 |
dayNamesMin | [ "日", "一", "二", "三", "四", "五", "六" ] | 包含在日期选择器小部件中列标题上显示的最小化日期名称的数组。这可以是本地化的,我们将在本章后面看到。 |
dayNamesShort | [ "周日", "周一", "周二", "周三", "周四", "周五", "周六" ] | 用于小部件的 dateFormat 属性的缩写日期名称列表。 |
defaultDate | null | 设置日期选择器打开时将突出显示的日期,当 <input> 元素为空时。 |
duration | "normal" | 设置日期选择器打开的速度。 |
firstDay | 0 | 设置一周的第一天,从星期日的 0 开始,到星期六的 6 结束。 |
gotoCurrent | false | 将当前日期链接设置为将日期选择器小部件移动到当前选择的日期,而不是今天。 |
hideIfNoPrevNext | false | 当不需要时隐藏上一个/下一个链接,而不是禁用它们。 |
isRTL | false | 控制所使用的语言是否从右到左绘制。 |
maxDate | null | 设置可选择的最大日期。接受日期对象或相对数字。例如:+7,或 +6m 等字符串。 |
minDate | null | 设置可选择的最小日期。接受数字、日期对象或字符串。 |
monthNames | 月份名称数组,例如 [ "一月", "二月", "三月"…] | 设置用于小部件中 dateFormat 属性的完整月份名称列表。 |
monthNamesShort | 缩写月份名称数组,例如["一月", "二月", "三月"…] | 设置日期选择器小部件中每个月头部使用的缩写月份名称列表,由 dateFormat 属性指定。 |
navigationAsDateFormat | false | 允许我们使用前一个、下一个和当前链接来指定月份名称。 |
nextText | "下一个" | 设置用于下一个月链接的显示文本。 |
numberOfMonths | 1 | 设置在单个日期选择器小部件上显示的月份数。 |
onChangeMonthYear | Function | 当日期选择器移到新的月份或年份时调用。 |
onClose | Function | 当日期选择器小部件关闭时调用,无论是否选择了日期。 |
onSelect | Function | 在选择日期选择器小部件后调用。 |
prevText | "Prev" | 设置上一个月链接的显示文本。 |
selectOtherMonths | false | 允许选择在当前月面板上显示的上一个月或下一个月的日期(参见showOtherMonths选项)。 |
shortYearCutoff | "+10" | 在使用年份表示时确定当前世纪;小于此数的数字被视为当前世纪。 |
showAnim | "show" | 设置日期选择器小部件显示时使用的动画。 |
showButtonPanel | false | 显示一个日期选择器小部件的按钮面板,包括关闭和当前链接。 |
showCurrentAtPos | 0 | 在多月份日期选择器中设置当前月的位置。 |
showOn | "focus" | 设置触发显示日期选择器的事件。 |
showOptions | {} | 包含控制配置动画的选项的对象文本。 |
showOtherMonths | false | 显示前一个月和下一个月的最后一天和第一天。 |
showWeek | false | 显示一个显示年周的列。使用calculateWeek选项确定周。 |
stepMonths | 1 | 使用上一个和下一个链接导航的月份数。 |
weekHeader | "Wk" | 设置要显示为年周列标题的文本。 |
yearRange | "-10:+10" | 指定年份下拉菜单中的年份范围。 |
我们将在本章中详细探讨其中一些选项。
使用基本选项
将datepicker1.html中的最终<script>元素更改为以下内容:
<script>
$(document).ready(function($){
$("#date").datepicker({
appendText: " (mm/dd/yy)",
defaultDate: "+5",
showOtherMonths: true
});
});
</script>
将此保存为datePicker2.html。下面的屏幕截图显示了在配置了这些选项之后小部件的外观:
我们在这个示例中使用了许多选项,只因为有这么多的选项可供选择。在日期选择器甚至显示之前的初始页面的外观可以使用appendText选项进行更改。这将使用<span>元素直接在<input>字段后面添加指定的文本字符串,与选择器关联。这有助于访问者澄清将用于日期的格式。
为了样式的目的,我们可以使用.ui-datepicker-append类名来定位新的<span>元素。
defaultDate选项设置了在日期选择器初始打开时突出显示的日期,而<input>元素为空。在这个示例中,我们使用了相对的+5字符串,因此当日期选择器小部件初始打开时,选择了距当前日期五天的日期。按下键盘上的Enter键将选择突出显示的日期。
除了相对字符串,我们还可以将 null 作为 defaultDate 的值来供应,将其设置为当前日期(主观上的今天),或者使用标准的 JavaScript 日期对象。
正如我们在上一个截图中所看到的那样,日期选择器小部件中当前日期的样式与显示默认日期的样式不同。这将因主题而异,但供参考的是,当前日期以粗体显示,并用浅色(橙色)显示,而所选日期具有比正常日期更深的边框与默认主题。
一旦选择了日期,随后再次打开日期选择器小部件时,将显示所选日期作为默认日期,这再次具有不同的样式(在 redmond 主题下,预选日期将为浅蓝色)。
通过将 showOtherMonths 选项设置为 true,我们已经向日期表格的开始和结束的空方块中添加了来自上个月和下个月的灰色(不可选择)日期。这些在上一个截图中可见,并且呈现为比可选择日期要浅得多的颜色。
最小和最大日期
默认情况下,日期选择器将无限制地向前或向后,没有上限或下限。如果我们想要将可选择的日期限制在特定范围内,我们可以轻松地使用 minDate 和 maxDate 选项来实现。将 datePicker2.html 中的配置对象更改为以下内容:
$("#date").datepicker({
minDate: new Date(),
maxDate: "+10"
});
将此保存为 datePicker3.html。在本例中,我们向 minDate 选项提供了一个标准的未修改的 JavaScript 日期对象,这将使过去的任何日期都无法选择。
对于 maxDate 选项,我们使用相对文本字符串 +10,这将使只有当前日期和接下来的 10 个日期可选择。您可以看到这些选项如何影响小部件的外观在以下截图中:
注意
minDate 和 maxDate 选项也可以采用诸如 +6w,-10m 或 1y 的字符串,分别代表周、月和年。您可以在 api.jqueryui.com/datepicker/#option-minDate 和 api.jqueryui.com/datepicker/#option-maxDate 上找到有关如何设置这些选项的更多详细信息。
更改日期选择器界面中的元素
日期选择器 API 公开了许多与在日期选择器中添加或删除额外 UI 元素直接相关的选项。要显示 <select> 元素,让访客选择月份和年份,我们可以使用 changeMonth 和 changeYear 配置选项:
$("#date").datepicker({
changeMonth: true,
changeYear: true
});
将此保存为 datePicker4.html。使用月份和年份的 <select> 元素,为用户提供了一个更快的方式来导航到可能遥远的日期。以下截图显示了启用这两个选项后小部件的外观:
默认情况下,年份选择框将包括上一个和下一个 10 年,总共涵盖 20 年的范围。我们可以使用前/后箭头链接进一步导航,但如果我们事先知道访问者可能会选择非常久远或未来的日期,我们可以使用yearRange选项更改年份范围:
$("#date").datepicker({
changeMonth: true,
changeYear: true,
yearRange: "-25:+25"
});
将其保存为datePicker5.html。这次运行页面时,我们应该发现年份范围现在总共覆盖了 50 年。
我们还可以对日期选择器的 UI 进行另一个更改,以启用按钮面板,这将在小部件底部添加两个按钮。让我们看看它实际操作时的效果。
更改datepicker5.html中的配置对象,使其如下所示:
$("#date").datepicker({ showButtonPanel: true })
将其保存为datePicker6.html。添加到小部件底部的按钮与对话框小部件中的按钮完全相同,您可以在下图中看到:
今天按钮将立即将日期选择器导航回显示当前日期的月份,而完成按钮将在不选择日期的情况下关闭小部件。
我们还可以更改今天按钮,使其转到所选日期而不是当前日期,方法是将其添加到小部件的配置对象中,如下所示:
$("#date").datepicker({
showButtonPanel: true,
gotoCurrent: true
});
如果您选择一个日期,然后滚动几个月,您可以通过点击今天按钮返回到所选日期。
添加一个触发按钮
默认情况下,当与其关联的<input>元素接收焦点时,日期选择器会打开。然而,我们可以非常轻松地更改这一点,使得日期选择器在按钮被点击时打开。最基本类型的<button>可以通过showOn选项仅启用。将datePicker6.html中的配置对象更改为以下内容:
$("#date").datepicker({
showOn: "button"
});
将其保存为datePicker7.html。在我们的配置对象中将showOn选项设置为true将会在关联的<input>元素后自动添加一个简单的<button>元素。我们还可以将此选项设置为both,这样当<input>聚焦时以及当<button>被点击时都会打开。
现在,日期选择器仅在点击<button>时打开,而不是在<input>聚焦时。此选项还接受字符串值"both",当<input>聚焦时和当<button>被点击时打开小部件。新的<button>如下图所示:
可以通过将新字符串提供为buttonText选项的值来轻松更改<button>上显示的默认文本(一个省略号);将之前的配置对象更改为以下内容:
$("#date").datepicker({
showOn: "button",
buttonText: "Open Calendar"
});
将其保存为datePicker8.html。现在,<button>上的文本应该与我们设置的buttonText选项的值匹配:
我们可以使用图像而不是文本作为<button>元素的标签。这是使用buttonImage选项配置的:
$("#date").datepicker({
showOn: "button",
buttonText: "Open Calendar",
buttonImage: "img/cal.png"
});
将此保存为datePicker9.html。buttonImage选项的值是一个字符串,由我们想要在按钮上使用的图像的路径组成。请注意,在此示例中,我们还设置了buttonText选项。之所以这样做的原因是,buttonText选项的值会自动用作<img>元素的title和alt属性,也就是添加到<button>中。
我们的触发按钮现在应该如下截图所示:
提示
在这个例子中,我们故意没有在这一点上为按钮设置样式,而是专注于添加一个标志。但是,您可以使用 jQuery UI 对其进行样式设置,正如我们将在第八章中看到的按钮和自动完成小部件。
如果我们不想使用按钮,我们根本不需要使用按钮;我们可以将<button>元素替换为<img>元素。因此,将datePicker9.html中的配置对象更改为以下内容:
$("#date").datepicker({
showOn: "button",
buttonImage: "img/date-picker/cal.png",
buttonText: "Open Calendar",
buttonImageOnly: true
});
将此保存为datePicker10.html。这应该为您提供一个漂亮的仅图片按钮,如下截图所示:
配置替代动画
日期选择器小部件带有一个吸引人的内置打开动画,使小部件看起来从无到完整大小。其灵活的 API 还公开了几个与动画相关的选项。这些是duration、showAnim和showOptions配置选项。
我们可以设置的最简单的动画配置是小部件打开和关闭的速度。要做到这一点,我们所要做的就是更改duration选项的值。此选项需要一个简单的字符串,可以采用字符串值slow、normal(默认值)或fast,或者表示以毫秒为单位的持续时间的数字。
将datePicker10.html中的配置对象更改为以下内容:
$("#date").datepicker({
duration: "fast"
});
将此变体保存为datePicker11.html。当我们在浏览器中运行此页面时,应该会发现打开动画明显更快。
除了更改动画的速度之外,我们还可以使用showAnim选项更改动画本身。默认使用的动画是简单的显示动画,但我们可以更改为使用库中包含的任何其他显示/隐藏效果之一(请参阅第十四章,UI 效果)。将前一个示例中的配置对象更改为以下内容:
$("#date").datepicker({
showAnim: "drop",
showOptions: {direction: "up"}
});
将其保存为datePicker12.html。我们还需要使用两个新的<script>资源来使用替代效果。 这些是jquery.ui.effect.js和我们希望使用的效果源文件,在本例中为jquery.ui.effect-drop.js。 我们将在第十四章中更详细地讨论这两种效果,但它们对于此示例的工作至关重要。 确保将它们添加到文件中,在日期选择器的源文件之后:
<script src="img/jquery.ui.datepicker.js">
</script>
<script src="img/jquery.ui.effect.js"></script>
<script src="img/jquery.ui.effect-drop.js"></script>
我们简单的配置对象通过showAnim选项配置了下落动画,并使用showOptions设置了效果的direction选项,由于日期选择器的绝对定位,这是必需的。 当您运行此示例时,日期选择器应该会下降到位,而不是打开。 其他效果可以以相同的方式实现。
显示多个月
到目前为止,我们所有的示例都只涵盖了单月日期选择器,一次只显示一个月。 但是,如果我们希望,我们可以很容易地通过一些配置选项来调整显示不同数量的月份。 在datePicker12.html中在配置对象之前删除效果源文件,并更改配置对象,以使其如下所示:
$("#date").datepicker({
numberOfMonths: 3
});
将其保存为datePicker13.html。 numberOfMonths选项接受一个整数,表示我们希望在任何时候在部件中显示的月份数。 我们的日期选择器现在应该看起来像这样:
注
可显示的月份数量没有上限;然而,随着每个额外月份的显示,部件的性能会降低。 在将焦点放在<input>上并显示部件之间还有明显的延迟。
此外,各个月份面板是并排的,由于它们的大小,很快将超出视口,导致出现水平滚动条。 但是,一旦使用滚动条,日期选择器将关闭,使得超出屏幕边界的月份无法使用。 出于这些原因,最好将显示的月份数量保持在最低限度。
还有几个与多月份日期选择器相关的配置选项。 stepMonths选项控制在使用上一个或下一个链接时更改多少个月份。
stepMonths的默认值为1,因此在我们先前的示例中,部件以当前月份显示为开始,接着显示接下来的两个月份。 每次单击上一个或下一个图标时,面板向左或向右移动一个空间。
如果我们将stepMonths设置为3,与显示的月份数相同,每次单击上一个或下一个链接时,每个月将向左或向右移动三个空间,因此每次单击时都会显示全新的面板。
showCurrentAtPos 选项指定了在显示日期选择器时当前月份显示的位置。在我们之前的例子中,当前月份显示为第一个月面板。每个月面板都有一个从零开始的索引号,所以如果我们希望当前月份显示在小部件的中间,我们会将此选项设置为 1。
以垂直方式显示日期选择器
在前面的示例中,注意到应将使用多个月份的情况保持在最低限度,因为如果日历向右滚动太远,我们无法更改用于宽度的样式。
我们可以通过调整 numberofMonths 选项来在一定程度上缓解这个问题。它接受两个属性:第一个是控制我们显示的月份数量,第二个是要使用的列数。如果我们根据 datepicker13.html 中的示例设置,将其设置为在单列中显示两个月,它可能如下所示:
要实现此效果,我们只需更改 datepicker13.html 中的配置对象如下所示:
$("#date").datepicker({
numberOfMonths: [2, 1]
});
您会发现日期选择器现在仅显示两个日历月份,并且现在以垂直格式显示。然后,我们可以使用一点 jQuery 来获取窗口的大小,并根据返回的大小设置 numberOfMonths 属性:
function responsive(){
var winWidth = $(window).width();
if((winWidth < 991)&&(winWidth >= 768)) {
// tablet
$("#date").datepicker("option", "numberOfMonths", [ 2, 1 ]);
} else {
//desktop
$("#date").datepicker("option", "numberOfMonths", 2 );
}
}
注意
无法手动使用 CSS 实现相同的效果;虽然大多数样式可以更改,但容器宽度是硬编码到库中的,无法更改。
更改日期格式
dateFormat 选项是我们可以使用的高级日期选择器区域设置之一。设置此选项可以让您快速轻松地设置选定日期的格式(显示在 <input> 中)使用各种简写引用。日期格式可以是以下任何字符的组合(它们区分大小写):
-
d: 这是月份中的日期(适用时为单个数字)
-
dd: 这是月份中的日期(两位数字)
-
m: 这是年份中的月份(适用时为单个数字)
-
mm: 这是年份中的月份(两位数字)
-
y: 这是年份(两位数字)
-
yy: 这是年份(四位数字)
-
D: 这是缩写的星期几名称
-
DD: 这是完整的星期几名称
-
M: 这是缩写的月份名称
-
MM: 这是完整的月份名称
-
'...': 这是任何文本字符串
-
@: 这是 UNIX 时间戳(自 1970 年 1 月 1 日起的毫秒数)
我们可以使用这些简写代码快速配置我们喜欢的日期格式,如以下示例所示。将 datePicker13.html 中的配置对象更改为以下内容:
$("#date").datepicker({
dateFormat:"d MM yy"
});
将新文件保存为 datePicker14.html。我们使用 dateFormat 选项来指定一个包含我们首选日期格式的字符串。我们设置的格式是日期的月份(尽可能使用单个数字)为 d,月份的全名为 MM,四位数的年份为 yy。
当选择日期并将其添加到相关的 <input> 中时,它们将按照配置对象中指定的格式,如下面的屏幕截图所示:
在将字符串用作配置日期的选项值时,我们还可以指定整个文本字符串。但是,如果我们这样做,而字符串中的任何字母都是用作简写的字母,则需要使用单引号对其进行转义。
例如,要将字符串 Selected: 添加到日期的开头,我们需要使用字符串 Selecte'd':,以避免将小写 d 作为月份格式的简写格式:
$("#date").datepicker({
dateFormat:"Selecte'd': d MM yy"
});
将此更改保存为 datePicker15.html。请注意,我们如何使用单引号将字符串 Selected 中的小写 d 转义起来。现在,当选择日期时,我们的文本字符串将被添加到格式化日期的前缀:
提示
为 标签添加样式
您可能希望将 width: 15em 添加为输入框的样式,以便您可以清楚地看到整个文本。我已经将这个添加到了附带本书的下载文件中。
还有一些内置的预配置日期格式,对应于常见的标准或 RFC 注释。这些格式作为常量添加到组件中,并可以通过 $.datepicker 对象访问。例如,让我们根据 ATOM 标准格式化日期:
$("#date").datepicker({
dateFormat: $.datepicker.ATOM
});
将此保存为 datePicker16.html。在此示例中选择日期时,输入到 <input> 中的值应该是如下屏幕截图所示的格式:
注意
ATOM 格式或技术上称为 RFC 3339/ISO 8601,是一个国际标准,旨在为日期和时间提供清晰的格式,以避免误解,特别是在数据在使用不同日期格式的国家之间传输时。
预定义日期格式的完整集合列在以下表中:
| 选项值 | 简写 | 格式为… |
|---|---|---|
$.datepicker.ATOM | "yy-mm-dd" | 2013-07-25 |
$.datepicker.COOKIE | "D, dd M y" | 星期三, 25 七月 2013 |
$.datepicker.ISO_8601 | "yy-mm-dd" | 2013-07-25 |
$.datepicker.RFC_822 | "D, d M y" | 星期三, 25 七月 11 |
$.datepicker.RFC_850 | "DD, dd-M-y" | 星期三, 25-七月-11 |
$.datepicker.RFC_1036 | "D, d M y" | 星期三, 25 七月 11 |
$.datepicker.RFC_1123 | "D, d M yy" | 星期三, 25 七月 2013 |
$.datepicker.RFC_2822 | "D, d M yy" | 星期三, 25 七月 2013 |
$.datepicker.RSS | "D, d M y" | 星期三, 25 七月 13 |
$.datepicker.TIMESTAMP | @ (UNIX 时间戳) | 1302649200000 |
$.datepicker.W3C | "yy-mm-dd" | 2013-07-25 |
更新额外的输入元素
有时我们可能想要使用所选日期更新两个 <input> 元素,也许以显示不同的日期格式。altField 和 altFormat 选项可用于满足此要求。在 datepicker16.html 页面中添加第二个 <input> 元素,其 id 属性为 dateAltDisplay,然后将配置对象更改为以下内容:
$("#date").datepicker({
altField: "#dateAltDisplay",
altFormat: $.datepicker.TIMESTAMP
});
将此保存为 datePicker17.html。altField 选项接受标准的 jQuery 选择器作为其值,并允许我们选择在主 <input> 更新时更新的额外 <input> 元素。altFormat 选项可以接受与 dateFormat 选项相同的格式。下面的截图显示了使用日期选择器选择日期后页面应该显示的方式:
更改日期格式
当使用日期选择器部件时,您可能已经注意到通过 getDate 方法(请参阅 日期选择方法 部分)以编程方式返回的日期遵循默认的 GMT 日期和时间标准。为了更改 API 返回的日期格式,应使用 $.datepicker.formatDate() 实用程序方法。让我们看看如何使用此功能。
在 datePicker17.html 中,将日期配置对象更改如下:
$("#date").datepicker({
dateFormat: 'yy-mm-dd',
onSelect: function(dateText, inst) {
var d = new Date(dateText);
var fmt2 = $.datepicker.formatDate("DD, d MM, yy", d);
$("#selecteddate").html("Selected date: " + fmt2);
}
});
将此保存为 datePicker18.html。我们需要添加一个额外的 CSS 样式规则,以便我们可以看到在部件中选择日期的结果。将以下内容添加到我们文件的 <head> 中:
<style type="text/css">
#selecteddate { margin-top: 250px; }
</style>
如果我们在浏览器中预览结果,您会发现在配置对象中使用 dateFormat 属性设置初始 <input> 字段中使用的日期格式;这被设置为 dd-mm-yy。在 onSelect 事件处理程序中,我们使用 $.datepicker.formatDate 将所选日期更改为以下截图中显示的日期:
本地化日期选择器部件
除了已列出的选项外,还有一系列本地化选项。它们可用于提供自定义区域设置支持,以便以替代语言显示日期选择器,或更改英语单词的默认值。
针对特定本地化使用的选项列在下表中:
| 选项 | 默认值 | 用途 |
|---|---|---|
closeText | "关闭" | 关闭按钮上显示的文本。 |
currentText | "今天" | 当天链接显示的文本。 |
dateFormat | "mm/dd/yy" | 当添加到 <input> 中时所选日期应采用的格式。 |
dayNames | ["星期日", "星期一","星期二",``"星期三", "星期四", "星期五","星期六"] | 一周中每天的名称数组。 |
dayNamesMin | ["Su", "Mo", "Tu","We", "Th", "Fr", "Sa"] | 一周内两个字母的日名称数组。 |
dayNamesShort | ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] | 一周内缩写的星期几名称数组。 |
firstDay | 0 | 指定日期选择器中的第一列天。 |
isRTL | false | 将日历格式设置为从右到左。 |
monthNames | ["January", "February",``"March", "April",``"May", "June", "July,``"August", "September",``"October", "November",``"December"] | 月份名称数组。 |
monthNamesShort | ["Jan", "Feb", "Mar",``"Apr", "May", "Jun",``"Jul", "Aug", "Sep",``"Oct", "Nov", "Dec"] | 月份缩写名称数组。 |
nextText | "Next" | 在下一个链接上显示的文本。 |
prevText | "Prev" | 显示在上一个链接上的文本。 |
showMonthAfterYear | false | 在小部件标题中将月份显示在年份后面。 |
yearSuffix | "" | 显示在月份标题中年份后面的附加文本字符串。 |
已经提供了大量不同的翻译,并存储在development-bundle/ui目录中的i18n文件夹中。每种语言翻译都有自己的源文件,要更改默认语言,我们只需包含替代语言的源文件即可。
在datePicker17.html中,在链接到jquery.ui.datepicker.js之后直接添加以下新的<script>元素:
<script src="img/jquery.ui.datepicker-fr.js">
</script>
移除配置对象的altField和altFormat属性:
$("#date").datepicker();
将此保存为datePicker19.html,并在浏览器中查看结果:
通过一个新资源的单个链接,我们已经将日期选择器中的所有可见文本更改为另一种语言,而且我们甚至不需要设置任何配置选项。如果我们想要真正国际化日期选择器,甚至有一个包含所有替代语言的汇总文件,我们可以使用它,而不需要包含多个语言文件。
在datepicker19.html中,将<head>中的jquery.ui.datepicker-fr.js的链接更改为以下代码:
<script src="img/jquery-ui-i18n.js">
</script>
接下来,将 datepicker 的配置对象更改为以下内容:
$(document).ready(function($){
$("#date").datepicker();
$("#date").datepicker("option", $.datepicker.regional["ar"]);
});
将文件保存为datepicker20.html。如果我们在浏览器中预览结果,您将看到它以阿拉伯语显示小部件。我们使用了日期选择器的选项属性将$.datepicker.regional设置为ar,这是 jQuery UI 对阿拉伯语的代码:
我们将在本章后面的动态本地化日期选择器示例中重新讨论本地化汇总文件。
实施自定义本地化
自定义本地化也非常容易实现。这可以使用包含配置的标准配置对象来完成,这些配置是上表选项的配置值。通过这种方式,可以实现未包含在汇总文件中的任何替代语言。
例如,要实现一个Lolcat日期选择器,删除datePicker20.html的现有配置对象,并添加以下代码:
$("#date").datepicker({
closeText: "Kthxbai",
currentText: "Todai",
nextText: "Fwd",
prevText: "Bak",
monthNames: ["January", "February", "March", "April", "Mai", "Jun", "July", "August", "Septembr", "Octobr", "Novembr", "Decembr"],
monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
dayNames: ["Sundai", "Mondai", "Tuesdai", "Wednesdai", "Thursdai", "Fridai", "Katurdai"],
dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Kat"],
dayNamesMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Ka"],
dateFormat: 'dd/mm/yy',
firstDay: 1,
isRTL: false,
showButtonPanel: true
});
将此更改保存为datePicker21.html。大多数选项用于提供简单的字符串替换。但是,monthNames、monthNamesShort、dayNames、dayNamesShort和dayNamesMin选项需要数组。
请注意,dayNamesMin选项和其他与日期相关的数组应从星期日(或相应的本地化)开始;在这里,我们使用firstDay选项将星期一设置为首先出现的选项。我们的日期选择器现在应该看起来像这样:
注意
对于那些好奇“Lolcat”一词的人,它是一个始于 2006 年的术语,但基于 20 世纪初创作的一系列图像。它用于表示一系列具有(尽管语法不正确或独特)短语的猫图片,旨在制造幽默。您可以在en.wikipedia.org/wiki/Lolcat了解更多关于这种独特幽默形式的信息。
实现回调
最终的配置选项集与小部件公开的事件模型相关。它由一系列回调函数组成,我们可以使用这些函数在与日期选择器的交互期间的不同时间点指定要执行的代码。
这些列在以下表格中列出:
| 事件 | 当...时触发 |
|---|---|
beforeShow | 日期选择器即将打开。 |
beforeShowDay | 在日期选择器中呈现每个单独的日期。可用于确定日期是否可选择。 |
onChangeMonthYear | 当前月份或年份发生变化。 |
onClose | 日期选择器已关闭。 |
onSelect | 选择了一个日期。 |
为了突出这些回调属性有多有用,我们可以将前一个国际化示例扩展为创建一个页面,让访问者可以选择i18n捆绑文件中找到的任何可用语言。
通过捆绑动态本地化日期选择器
本书早期,我们简要介绍了如何使用捆绑文件更改日期选择器显示的语言。这样可以避免引用多个语言文件,从而有助于减少对服务器的 HTTP 请求;不过,缺点是日期选择器小部件将始终以硬编码到小部件属性中的语言显示。
不过我们可以改变这一点。让我们看看如何通过添加语言选择下拉菜单来使用beforeShow回调,以显示选择的语言中的日期选择器。
在datePicker21.html中,向页面添加以下新的<select>框,并使用以下<option>元素。出于简洁起见,我仅在此处包含了一部分;您可以在本书附带的代码下载中看到完整的列表:
<select id="language">
<option id="en-GB">English</option>
<option id="ar">Arabic</option>
<option id="ar-DZ">Algerian Arabic</option>
<option id="az">Azerbaijani</option>
<option id="bg">Bulgarian</option>
<option id="bs">Bosnian</option>
<option id="ca">Catalan</option>
<option id="cs">Czech</option>
...
<option id="en-NZ">English/New Zealand</option>
<option id="en-US">English/United States</option>
<option id="eo">Esperanto</option>
<option id="es">Spanish</option>
<option id="et">Estonian</option>
<option id="zh-HK">Chinese</option>
<option id="zh-TW">Taiwanese</option>
</select>
接下来,如下链接到i18n.js捆绑文件:
<script src="img/jquery-ui-i18n.js">
</script>
现在更改最后一个<script>元素,使其如下所示:
<script>
$(document).ready(function($){
$("#date").datepicker({
beforeShow: function() {
var lang = $(":selected", $("#language")).attr("id");
$.datepicker.setDefaults($.datepicker.regional[lang]);
}
});
$.datepicker.setDefaults($.datepicker.regional['']);
});
</script>
将此文件保存为datePicker22.html。我们使用beforeShow回调来指定每次日期选择器显示在屏幕上时执行的函数。
在该函数内部,我们获取选定的<option>元素的id属性,然后将其传递给$.datepicker.regional选项。使用$.datepicker.setDefaults()实用方法来设置此选项。
当页面首次加载时,<select>元素不会有选定的<option>子元素,由于i18n roll-up 文件的顺序,日期选择器将设置为台湾语。为了将其设置为默认的英语,我们可以在日期选择器初始化后将regional实用程序设置为空字符串。
下图显示了在<select>元素中选择另一种语言之后的日期选择器:
我们可以进一步发展这一点;您可能已经注意到,语言直到点击<input>字段内部显示小部件之前都不会改变。
代码可以运行,但感觉有点笨拙;相反,如果我们改变如何显示小部件,我们就可以消除需要点击<input>字段内部的必要性。我已经在代码下载中包含了如何做到这一点的示例,命名为datepickerXX.html。
引入实用方法
在前面例子中,我们使用了日期选择器中可用的实用方法之一,setDefaults用于在所有日期选择器实例上设置配置选项。除此之外,还有几种其他实用方法可供我们使用;这些显示在下表中:
| 实用 | 用于... |
|---|---|
formatDate | 将date对象转换为指定格式的字符串。使用dateFormat选项时,使用formatDate方法以指定格式返回日期。此方法接受三个参数—转换日期的格式(见选择器的可配置选项中的dateFormat),要转换的date对象以及包含附加设置的可选配置对象。可以提供以下选项:dayNamesShort、dayNames、monthNamesShort和monthNames。 |
iso8601Week | 根据 ISO 8601 日期和时间标准返回指定日期所在的周数。该方法接受一个参数—要显示周数的日期。 |
noWeekends | 使周末日期不可选择。可以传递给beforeShowDay事件。 |
parseDate | 对formatDate的反操作,将格式化的日期字符串转换为日期对象。它还接受三个参数—要解析的日期的预期格式,要解析的日期字符串以及包含以下选项的可选设置对象:shortYearCutoff、dayNamesShort、dayNames、monthNamesShort和monthNames。 |
regional | 设置日期选择器的语言。 |
setDefaults | 在所有日期选择器上设置配置选项。此方法接受包含新配置选项的对象文字。 |
所有这些方法都是在$.datepicker管理器对象的单例实例上调用的,该对象在初始化时自动创建并用于与日期选择器的实例进行交互。无论在页面上创建了多少个日期选择器作为 jQuery 对象,它们始终会引用在该页面上创建的日期选择器小部件的第一个实例的属性和方法。
列出日期选择器方法
除了我们可以使用的广泛的配置选项之外,还定义了许多有用的方法,使得与日期选择器一起工作变得轻松自如。
除了在第一章中讨论的共享 API 方法 Introducing jQuery UI,如destroy、disable、enable、option和widget之外。日期选择器 API 还公开了以下独特的方法:
| 方法 | 用于… |
|---|---|
dialog | 在对话框小部件中打开日期选择器。 |
getDate | 获取当前选择的日期。 |
hide | 以编程方式关闭日期选择器。 |
isDisabled | 确定日期选择器是否已禁用。 |
refresh | 重绘日期选择器。 |
setDate | 以编程方式选择日期。 |
show | 以编程方式显示日期选择器。 |
让我们更详细地了解一些这些方法,首先是以编程方式选择日期。
以编程方式选择日期
有时(例如在动态、客户端 - 服务器网站上),我们希望能够在程序逻辑中设置特定日期,而无需访问者以通常的方式使用日期选择器小部件。让我们看一个基本示例。
在datePicker22.html中删除<select>元素,并直接在<input>元素之后添加以下<button>:
<button id="select">Select +7 Days</button>
现在将最后一个<script>元素更改为如下所示:
<script>
$(document).ready(function($){
$("#date").datepicker();
$("#select").click(function() {
$("#date").datepicker("setDate", "+7");
});
});
</script>
将其保存为datePicker23.html。setDate函数接受一个参数,即要设置的日期。与defaultDate配置选项一样,我们可以提供一个相对字符串(就像在此示例中所做的那样)或一个日期对象。
提示
您可以在api.jqueryui.com/datepicker/#utility-formatDate中查看设置日期对象的一些选项。
如果我们被迫使用字符串作为我们日期选择器的源,我们可以轻松将它们转换为日期对象;为了实现这一点,我们可以使用众多的日期 JavaScript 库,如Moment.js。我在本书的附带代码下载中包含了如何使用此库生成我们的日期对象的简单示例。
在对话框中显示日期选择器
dialog方法产生相同易于使用且有效的日期选择器窗口部件,但它将其显示在一个浮动的对话框中。该方法易于使用,尽管它影响日期选择器对话框的放置;对话框将显示为与日期输入字段分离,我们将会看到。
从页面中删除<button>并将datepicker23.html中的最终<script>元素更改为以下代码:
<script>
$(document).ready(function($){
function updateDate(date) {
$("#date").val(date);
}
$("#date").focus(function() {
$(this).datepicker("dialog", null, updateDate);
});
});
</script>
将此保存为datePicker24.html。首先我们定义一个名为updateDate的函数。当在日期选择器中选择日期时,将自动将所选日期传递给我们页面上的<input>元素。
我们使用focus事件调用dialog方法,该方法接受两个参数。在本例中,我们将第一个参数设为null,因此日期选择器默认为当前日期。
第二个参数是一个在选择日期时执行的回调函数,它映射到我们的updateDate函数。
我们还可以提供额外的第三和第四个参数;第三个是日期选择器的配置对象,第四个用于控制包含日期选择器的对话框的位置。默认情况下,它将在屏幕中央渲染对话框。
提示
您可以在api.jqueryui.com/datepicker/#method-dialog了解更多关于如何配置这些选项的信息。
实现启用 AJAX 的日期选择器
对于我们最终的日期选择器示例,我们将在其中加入一些魔法,并创建一个与远程服务器通信的日期选择器,以查看是否有任何不能选择的日期。然后,这些日期将在日期选择器窗口部件中被标记为不可选择的日期。
更改datepicker24.html的<body>,使其包含以下标记:
<div id="bookingForm" class="ui-widget ui-corner-all">
<div class="ui-widget-header ui-corner-top">
<h2>Booking Form</h2>
</div>
<div class="ui-widget-content ui-corner-bottom">
<label for "date">Appointment date:</label>
<input id="date">
</div>
</div>
<script>
$(document).ready(function($){
var months = [], days = [], x;
$.getJSON("http://www.danwellman.co.uk/bookedDates.php?
jsoncallback=?", function(data) {
for (x = 0; x < data.dates.length; x++) {
months.push(data.dates[x].month);
days.push(data.dates[x].day);
}
});
function disableDates(date) {
for (x = 0; x < days.length; x++) {
if (date.getMonth() == months[x] - 1 && date.getDate() == days[x]) {
return [false, "preBooked"];
}
}
return [true, ""];
}
function noWeekendsOrDates(date) {
var noWeekend = jQuery.datepicker.noWeekends(date);
return noWeekend[0] ? disableDates(date) : noWeekend;
}
$("#date").datepicker({
beforeShowDay: noWeekendsOrDates,
minDate: "+1"
});
});
</script>
我们脚本的第一部分最初声明了两个空数组,然后执行一个请求,从一个 PHP 文件获取 JSON 对象。JSON 对象包含一个名为 dates 的选项。该选项的值是一个数组,其中每个项也是一个对象。
每个子对象都包含月份和日期属性,表示应该使其不可选择的一个日期。月份或日期数组由 JSON 对象中的值填充,以供脚本稍后使用。
接下来,我们定义了在beforeShowDay事件上调用的noWeekendsOrDates回调函数。该事件对日期选择器中的 35 个单独日期方块中的每一个都会触发一次。甚至空白的方块也包括在内!
每个日期方块的日期都传递给此函数,该函数必须首先确定所选日期是否不是周末,使用 jQuery UI 的$.datepicker.noWeekends()函数。如果是,则它会自动传递给disableDates函数,否则将被标记为被禁用的。
如果将值传递给disableDates函数,则会将从noWeekendsOrDates函数发送到它的每个方块的日期传递给它,并且必须返回一个包含最多两个项的数组。
第一个是一个布尔值,指示该日期是否可选择,第二个是可选的日期给出的类名。我们的函数循环遍历我们的月份和日期数组中的每个项目,以查看传递给回调函数的任何日期是否与数组中的项目匹配。如果月份和日期项目都与日期匹配,数组将以false和自定义类名作为其项目返回。如果日期不匹配,则返回包含true以指示日期可选择的数组。这使我们能够指定日期选择器中无法选择的任意数量的日期。
最后,我们为日期选择器定义一个配置对象。对象的属性只是用于使 JSON 对象中指定的日期不可选择的回调函数,以及将设置为相对值+1的minDate选项,因为我们不希望人们选择过去的日期或当前日期。
除了 HTML 页面之外,我们还需要一些自定义样式。在您的编辑器中的一个新页面中,创建以下样式表:
#date { width: 302px; }
#bookingForm { width: 503px; }
#bookingForm h2 { margin-left: 20px; }
#bookingForm .ui-widget-content { padding: 20px 0; border-top: none; }
label { margin: 4px 20px 0; font-family: Verdana; font-size: 80%;
float: left; }
.ui-datepicker .preBooked span { color: #ffffff;
background: url(../img/red_horizon.gif) no-repeat; }
将其保存为datepickerTheme.css在css文件夹中。我们使用 PHP 来响应页面发出的请求并提供 JSON 对象。如果您不想在您的 Web 服务器上安装和配置 PHP,您可以使用我在示例中指定的 URL 放置的文件。对于任何有兴趣的人,使用的 PHP 如下所示:
<?php
header('Content-type: application/json');
$dates = "({
'dates':[
{'month':12,'day':2},
{'month':12,'day':3},
etc...
]
})";
$response = $_GET["jsoncallback"] . $dates;
echo $response;
?>
这可以保存为主jqueryui项目文件夹中的bookedDates.php。
预订日期只是硬编码到 PHP 文件中。同样,在一个适当的实现中,您可能需要一种更健壮的方式来存储这些日期,比如在数据库中。
当我们在浏览器中运行页面并打开日期选择器时,PHP 文件指定的日期应该根据我们的preBooked类进行样式设置,并且还应完全不响应,如下面的截图所示:
摘要
在本章中,我们看了一下由 jQuery UI 库中最大的 API 之一支持的日期选择器小部件。这为我们提供了大量可供使用的选项和从中接收数据的方法。我们首先看了默认实现以及小部件自动添加了多少行为。
我们看了日期选择器暴露的丰富 API,其中包括比任何其他组件更多的可配置选项。我们还看到了如何使用日期选择器管理器对象特有的实用函数。
我们看到了小部件是如何轻松实现国际化的。我们还看到,小部件已经被翻译成了其他34 种语言。每种语言都被打包成一个模块,可以与日期选择器轻松配合使用,以添加对其他语言的支持。我们还看到了如何创建自定义的语言配置。
我们介绍了在日期选择器交互过程中触发的一些事件,并查看了在代码中可用于处理和控制日期选择器的一系列方法。
在下一章中,我们将看到该库中两个较新的添加,即按钮小部件和自动完成小部件。