Kendo-UI-Web-开发学习指南-全-
Kendo UI Web 开发学习指南(全)
原文:
zh.annas-archive.org/md5/3ab3cfce404c21e16af4d5fcd6273d27
译者:飞龙
前言
今天的网络开发需要真正的 HTML5、JavaScript 和 CSS 专业知识。这些技术并非完全新颖,但围绕这种编程模型的增长如此之快,以至于在尝试创建新网站时很难找到方向。似乎每个流行的网站都有不同的、特殊的技巧来渲染吸引人的布局或在创建响应式和动态体验方面。初学者在尝试学习如何以这种方式编程时可能会感到绝望。
幸运的是,许多 JavaScript 库应运而生以满足这种强烈的需求。这些库中的大多数都通过特殊的快捷方式提供客户端功能,以便开发者可以在不编写,甚至不理解复杂的 JavaScript 代码的情况下利用非常强大的功能。jQuery 库是这方面的一个很好的例子;它们仅用几行代码就提供了丰富的功能和控制台,隐藏了下面的复杂编程。
Telerik 将此模型推进了一步。他们构建了一个强大的 JavaScript 框架,称为 Kendo UI,该框架建立在 jQuery 之上,但可以用更简单的代码创建完整的控件。不仅如此,它还包括服务器端代码库,使开发者能够在服务器上创建控件,并且所有 JavaScript 都会自动生成!这极大地提高了生产力,并使经验丰富的网络开发者和初学者能够在同一赛场上操作。本书将带您初步了解 Kendo UI 框架,并展示如何创建一套有用且强大的小部件,使您的网页像互联网上最好的网站一样闪耀。
本书涵盖内容
第一章,与数据交互:数据源、模板和网格,教授了 Kendo UI 数据源和模板 JavaScript 对象的基础知识。了解这些工具的基本知识以及所有小部件中最重要的网格。这些概念将成为您使用 Kendo UI 框架进行所有创作的基石。
第二章,自动完成小部件及其用法,展示了如何使用 Kendo UI 在文本框上创建一个单词轮或自动完成效果,以便在用户输入时显示单词建议。了解如何使用此小部件以及如何将其连接到不同的数据源。
第三章,使用和自定义日历,展示了如何使用非常少的代码在网页上创建一个功能齐全的日历控件。了解如何使用 Kendo UI 框架自定义此小部件以满足您的需求。
第四章,Kendo MVVM 框架,向您介绍了使用 Kendo UI 进行模型-视图-视图模型(MVVM)开发。JavaScript MVVM 框架是强大的系统,允许您通过声明 HTML 属性将动态数据绑定到网页上。这些系统可能很复杂,但 Kendo UI MVVM 框架可以做到尽可能简单。学习如何使用它来启用强大的动态网页。
第五章,HTML 编辑器和自定义工具,展示了 Kendo UI 编辑器小部件。这个 HTML 编辑器小部件允许您为用户提供一个有用的区域,用于使用样式和布局格式化文本输入。这对于博客、论坛和评论网站是一个完美的功能。学习如何使用和自定义这个小部件以适应您的网页。
第六章,菜单和 ListView,向您介绍了 Kendo UI 的菜单和 ListView 小部件,以便您可以在网页上有效地格式化和显示数据。菜单小部件创建了一个动态菜单,通过悬停效果打开,并允许自定义动画和行为。ListView 是一个非常灵活的小部件,允许您以任何您喜欢的方式格式化和模板数据。学习如何使用这些小部件在您的页面上显示数据。
第七章,实现 PanelBar 和 TabStrip,展示了如何在网页上构建手风琴控件和标签页。手风琴控件提供了一种在页面不增加尺寸的情况下包含大量内容的有用方式。它一次只能显示一个内容部分,同时仍然提供对其他内容的即时访问。标签页对于在页面上创建显示用户可以访问的网站其他区域的导航栏非常有用。您将学习如何使用 PanelBar 小部件创建手风琴控件,以及如何使用 TabStrip 小部件创建标签页。看看使用这些小部件如何使您的网页看起来更美观。
第八章,滑块基本知识,将教会您如何使用 Kendo UI 滑块小部件以吸引人的方式显示数字范围。这个小部件是一种非常方便的方法,可以从带有可滑动和步进移动的图形栏的网页表单中收集数值输入。学习如何将这些小部件添加到您的网页上,使您的网页表单更加出色。
第九章,实现 Splitter 和 TreeView 小部件,将展示如何在网页上布局可调整大小的内容区域,以及如何使用简单的小部件可视化层次数据。Splitter 小部件有助于将网页组织成可调整大小的区域。TreeView 小部件为层次数据创建动态显示。学习如何创建这些小部件并将它们连接到数据源。
第十章,上传和窗口小部件,提供了如何将强大的文件上传页面和交互式对话框构建到您的网站中的说明。上传小部件创建了一个功能强大的文件上传实用程序,它可以与 AJAX 一起工作,甚至允许拖放功能。窗口小部件创建模态对话框,使您的网页上的某些区域在必要时出现在其他内容之上。学习如何制作这些小部件并将它们添加到您的页面上。
第十一章,Web API 示例,介绍了您已经学到的关于 Kendo UI 小部件的知识,并带您进入使用 ASP.NET Web API 框架的更高级开发领域。Web API 为您的 Kendo UI 小部件提供了一个强大的服务器端后端,并打开了创意自定义开发的可能。学习如何使用 ASP.NET MVC 在自己的网络应用程序中管理这项技术。
您需要这本书什么
要完成这本书中的示例,您首先需要 Visual Studio 2012。如果您还没有安装,可以从www.microsoft.com/visualstudio下载 Visual Studio 的免费试用版。您还需要从 Telerik 获取的 Kendo UI Complete for ASP.NET MVC 安装包,您可以在www.kendoui.com/download.aspx
获取。
这本书面向谁
这本书是为初学网络开发人员设计的,他们开始学习如何利用 JavaScript 库来创建丰富和交互式的网络应用程序。用户应熟悉 JavaScript、HTML 和 CSS。一些关于 ASP.NET MVC 的知识有帮助,但不是必需的。
习惯用法
在这本书中,您将找到许多不同风格的文本,以区分不同类型的信息。以下是一些这些风格的示例及其含义的解释。
文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称如下所示:“both
标记位置选项将在滑块的两侧放置标记。”
代码块设置如下:
<style>
#stateOrTerritory {
width:200px;
}
</style>
<h2>AutoCompletePage</h2>
<input type="text" name="stateOrTerritory" id="stateOrTerritory" />
<script type="text/javascript">
当我们希望您注意代码块中的特定部分时,相关的行或项目将以粗体显示:
new StateTerritory{ Name = "Washington", IsContiguous = true,
IsState = true, IsTerritory = false },
new StateTerritory{ Name = "West Virginia", IsContiguous = true,
IsState = true, IsTerritory = false },
new StateTerritory{ Name = "Wisconsin", IsContiguous = true,
IsState = true, IsTerritory = false },
new StateTerritory{ Name = "Wyoming", IsContiguous = true,
IsState = true, IsTerritory = false }
新术语和重要词汇以粗体显示。您在屏幕上看到的单词,例如在菜单或对话框中,在文本中显示如下:“请注意,Kendo UI 窗口小部件的内容尚未显示,它必须首先通过事件激活;在这种情况下,该事件是点击显示窗口按钮。”
注意
警告或重要提示将出现在这样的框中。
小贴士
小贴士和技巧如下所示。
读者反馈
我们欢迎读者的反馈。请告诉我们您对这本书的看法——您喜欢什么或可能不喜欢什么。读者反馈对我们开发您真正能从中获得最大收益的标题非常重要。
要向我们发送一般反馈,只需发送一封电子邮件到<feedback@packtpub.com>
,并在邮件主题中提及书籍标题。
如果您在某个主题领域有专业知识,并且您对撰写或为书籍做出贡献感兴趣,请参阅我们的作者指南www.packtpub.com/authors。
客户支持
现在您已经是 Packt 书籍的骄傲拥有者,我们有一些事情可以帮助您从您的购买中获得最大收益。
下载示例代码
您可以从www.packtpub.com
的账户下载您购买的所有 Packt 书籍的示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support
并注册,以便将文件直接通过电子邮件发送给您。
错误清单
尽管我们已经尽一切努力确保我们内容的准确性,但错误仍然可能发生。如果您在我们的书中发现错误——可能是文本或代码中的错误——如果您能向我们报告这一点,我们将不胜感激。通过这样做,您可以节省其他读者的挫败感,并帮助我们改进本书的后续版本。如果您发现任何错误清单,请通过访问www.packtpub.com/submit-errata
,选择您的书籍,点击错误清单提交表单链接,并输入您的错误清单详情来报告。一旦您的错误清单得到验证,您的提交将被接受,错误清单将被上传到我们的网站,或添加到该标题的错误清单部分。任何现有的错误清单都可以通过从www.packtpub.com/support
选择您的标题来查看。
盗版
互联网上版权材料的盗版是一个跨所有媒体的持续问题。在 Packt,我们非常重视我们版权和许可证的保护。如果您在互联网上遇到任何我们作品的非法副本,无论形式如何,请立即提供位置地址或网站名称,以便我们可以寻求补救措施。
请通过<copyright@packtpub.com>
与我们联系,并提供疑似盗版材料的链接。
我们感谢您在保护我们的作者和我们为您提供有价值内容的能力方面的帮助。
问题
如果您在本书的任何方面遇到问题,可以通过<questions@packtpub.com>
联系我们,我们将尽力解决。
第一章. 与数据交互:数据源、模板、标签页和网格
今天是成为一名网页开发者的激动人心的时候。网络浏览器和网络标准已经发展到程序员现在有丰富的框架可供选择,以提升生产力,用更少的代码和更少的烦恼触及广泛的受众。HTML、CSS 和 JavaScript 已经合并成一个强大而连贯的单元,使得网络应用在美学和架构上既美丽又优雅。来自 Telerik 的 Kendo UI 是一个拥抱这些进步的现代框架,提供了一套工具,以实现丰富的网络开发和可配置的控件,所有这些都具有熟悉和易访问的语法。
沿着同样的思路,开发工具也在不断改进,Microsoft 的 Visual Studio 2012 就是一个很好的例子。JavaScript 现在是 Microsoft 世界中的第一公民,IDE 中对 JavaScript 开发的改进以及 HTML5 和 CSS3 的支持也得到了改善。这主要是为了支持 Windows 8 中的新编程模型,允许网络开发者将他们的技能带到 Windows 8 桌面,但这些改进也直接受益于 ASP.NET 开发——特别是 ASP.NET MVC。这是我们将在本书中使用的编程环境,用于演示和学习 Kendo UI 框架。
设置样本项目
Kendo UI for web development 是一个客户端、由 jQuery 驱动的 JavaScript 框架,它不依赖于任何特定的服务器技术或平台。这意味着您可以使用您选择的工具和调试/测试环境来编写和运行本书中的客户端示例。然而,Telerik 也发布了一套针对 Microsoft ASP.NET MVC 框架的服务器端扩展,这可以显著提高生产力。为了利用这两种模型,我将使用 Visual Studio 2012 和 ASP.NET MVC 4 项目模板来进行所有演示,并邀请您跟我一起学习。Visual Studio 2012 Express 可以从 www.microsoft.com/visualstudio/eng/products/visual-studio-overview
免费下载,如果您还没有安装它。
小贴士
是否想要下载完成的样本?
本书展示的样本可供下载,如果您不想自己设置所有步骤,也可以从完成的代码开始。
一旦您安装了 Visual Studio 2012,请从启动页面或从 文件 菜单中选择 新建项目。然后从项目选择中的 Web 组中选择 ASP.NET MVC 4 网络应用。如以下截图所示,我已经将我的项目命名为 LearningKendoUIWeb
:
选择此选项并单击 确定。下一个窗口将显示一些关于你想要使用的模板类型的选项。我选择了基本模板,但你可以选择任何模板,除了空模板,以便跟随示例。你不需要为本书的目的创建单元测试项目。
小贴士
下载示例代码
你可以从你购买的所有 Packt 书籍的账户 www.packtpub.com
下载示例代码文件。如果你在其他地方购买了这本书,你可以访问 www.packtpub.com/support
并注册以直接将文件通过电子邮件发送给你。
Visual Studio 将为你的新项目创建文件夹结构,并将所有必要的文件复制到该结构中,以便你可以在调试器中运行你的项目。一旦完成,你将在 Visual Studio IDE 的 解决方案资源管理器 部分看到你的项目树。
现在我们有了我们的结构,是时候下载 Telerik Kendo UI 文件并将它们放在正确的位置了。导航到 Telerik Kendo UI 网站 www.kendoui.com/download.aspx
,下载包含 ASP.NET MVC 服务器包装器的 Kendo UI 完整包的 30 天免费试用版。它将以 ZIP 文件的形式到达,包含你使用 Kendo UI 进行开发所需的所有内容。将 ZIP 文件的内容提取到你可以记住的地方,因为你将需要在本书的其余部分引用这些文件。此截图显示了 ZIP 文件应该包含的内容:
现在,按照以下步骤操作:
-
返回 Visual Studio,在 解决方案资源管理器 中的
Content
文件夹上右键单击,并选择 添加,新建文件夹。将新文件夹命名为kendo
。 -
右键单击你刚刚创建的
kendo
文件夹,再创建两个新的文件夹—Default
和textures
。现在,右键单击Default
文件夹,并选择 添加,现有项。 -
在显示的文件对话框中,导航到解压后的 Kendo 文件夹所在的文件夹,然后打开
Styles
文件夹,接着打开其内部的Default
文件夹。 -
选择此文件夹中的所有文件,然后单击 添加 按钮。这将把这些所有项目添加到 Visual Studio 项目中,以便在 解决方案资源管理器 中显示,并可以从 Visual Studio IDE 中进行管理。
-
接下来,按照相同的步骤将这些所有项目添加到
textures
文件夹中。一旦这些文件就位,再次在 解决方案资源管理器 中右键单击kendo
文件夹,并选择 添加,现有项。
在显示的对话框中,从解压的 kendo 文件夹的 Styles
文件夹中选择这两个特定的文件,并将它们也添加进去:
-
kendo.common.min.css
-
kendo.default.min.css
一旦这两个文件出现在解决方案资源管理器中,通过删除文件名中的.min
部分来重命名它们(kendo.default.min.css
变为kendo.default.css
);这将在接下来的几个段落中详细解释。当你完成时,解决方案资源管理器中的Content
文件夹应该看起来像这样:
接下来,我们将按照一些非常相似的步骤准备Scripts
文件夹。在解决方案资源管理器中,在Scripts
文件夹内创建一个kendo
文件夹,然后从下载的 Kendo 文件的js
文件夹中复制以下文件:
-
jquery.min.css
-
kendo.all.min.js
-
kendo.aspnetmvc.min.js
kendo.web.min.js
再次,删除文件名中的.min
部分。然而,我们稍后将需要两个版本的kendo.aspnetmvc.js
文件。现在,请复制该文件,但只从其中一个副本中删除文件名中的<code>.min</code>
部分。这样,你将有一个带有.min
文件名的文件副本,另一个没有.min
文件名的文件副本。完成后的kendo
文件夹在解决方案资源管理器中应该看起来像这样:
作为一名网页开发者,你肯定熟悉在网页头部引用脚本和样式的练习。ASP.NET MVC 4 自带一个很棒的功能,可以对这些脚本进行打包和压缩,同时内置缓存,以便浏览器可以更快地下载这些文件,从而在几乎不需要你做任何努力的情况下提高你网站的性能。此功能还适用于 CDN 位置,因此你可以在调试时使用本地文件,同时在网站部署时引用 CDN 托管的脚本或样式表。为了使我们的示例项目启用此功能,你需要在项目的App_Start
文件夹中的BundleConfig.cs
文件中添加以下代码。首先,在文件顶部添加此代码以启用 CDN 功能并保存我们想要使用的 CDN 位置的路径:
// Enable CDN
bundles.UseCdn = true;
// CDN paths for kendo stylesheet files
var kendoCommonCssPath = "http://cdn.kendostatic.com/2013.1.319/styles/kendo.common.min.css";
var kendoDefaultCssPath = "http://cdn.kendostatic.com/2013.1.319/styles/kendo.default.min.css";
// CDN paths for kendo javascript files
var kendoWebJsPath = "http://cdn.kendostatic.com/2012.2.710/js/kendo.web.min.js";
然后,在文件底部添加以下代码以创建您的 Kendo 文件捆绑包。通过将 CDN 位置作为 ScriptBundle
构造函数的第二个参数传递,Visual Studio 将在调试时使用您本地的文件构建解决方案,并在发布模式下使用 CDN 位置的文件构建解决方案。这也是我应该解释为什么我们移除了 JavaScript 和样式表文件名中的 .min
部分。ASP.NET MVC 的捆绑和压缩功能在调试期间有意忽略了文件名中包含 .min
的文件。这意味着在调试期间,您的 Kendo 下载中的所有脚本引用都不会工作,因为我们项目中没有包含预压缩的文件。互联网上有几种处理此问题的方法,但对我们项目来说,最简单的方法就是重命名文件以避免整个问题。
// Create the CDN bundles for kendo javascript files
bundles.Add(new ScriptBundle("~/bundles/kendo/web/js", kendoWebJsPath)
.Include("~/Scripts/kendo/kendo.web.js"));
// The ASP.NET MVC script file is not available from the Kendo Static CDN,
// so we will include the bundle reference without the CDN path.
bundles.Add(new ScriptBundle("~/bundles/kendo/mvc/js")
.Include("~/Scripts/kendo/kendo.aspnetmvc.js"));
// Create the CDN bundles for the kendo styleshseet files
bundles.Add(new StyleBundle("~/bundles/kendo/common/css", kendoCommonCssPath)
.Include("~/Content/kendo/kendo.common.css"));
bundles.Add(new StyleBundle("~/bundles/kendo/default/css", kendoDefaultCssPath)
.Include("~/Content/kendo/kendo.default.css"));
现在我们已经正确配置了 BundleConfig.cs
文件,我们可以调整 _Layout.cshtml
文件头部部分的引用。_Layout.cshtml
文件通过为所有页面创建统一的头部结构以及一个默认布局,在其中所有其他页面放置其特定内容,充当我们的默认母版页。在 Views
、Shared
文件夹中打开 _Layout.cshtml
文件并做一些修改。默认情况下,它将包含一些出现在页面主体部分的脚本引用,以及一些出现在头部部分的。
虽然无疑有很好的理由这样做,但由于在这些脚本引用出现之前,我们页面的主体中已经有了 Kendo 脚本的引用,因此我们需要将所有内容移动到头部部分。由于这个文件不是很长,我已经在这里包含了我的完成版本,以便您可以复制它:
@using Kendo.Mvc.UI;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
@Styles.Render("~/Content/css")
@Styles.Render("~/bundles/kendo/common/css")
@Styles.Render("~/bundles/kendo/default/css")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/kendo/web/js")
@Scripts.Render("~/bundles/kendo/mvc/js")
</head>
<body>
@RenderBody()
@RenderSection("scripts", required: false)
</body>
</html>
注意,我还已经在文件的顶部添加了一个 @using
语句,请确保也复制它,因为它将启用所有页面的 Intellisense。Intellisense 是 Visual Studio 的一个功能,可以在您编写代码时自动完成代码,并且是一个极大的生产力提升器。要完全启用此功能,您还需要将 Kendo.Mvc.dll
文件添加到您的 Visual Studio 项目中:
-
首先,在 Visual Studio 的 Solution Explorer 中右键单击 LearningKendoUIWeb 项目,并选择 添加引用。
-
接下来,单击 浏览 并在文件对话框中导航到您下载 Kendo 文件的位置。
-
找到名为
aspnetmvc
的文件夹,打开其中名为Binaries
的文件夹,然后打开该文件夹内名为Mvc3
的文件夹。 -
在这里您可以找到
Kendo.Mvc.dll
文件;单击它并选择 添加。 -
添加此引用后,您可以通过在名为
web.config
的文件中添加一个特殊条目,使该代码中的所有内容对您的所有网页可用。 -
此文件位于你的LearningKendoUIWeb项目的根目录中。打开
web.config
文件,找到名为namespaces
的部分。将Kendo.Web.UI
命名空间添加到列表中,如下所示:<pages> <namespaces> <add namespace="System.Web.Helpers" /> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Optimization" /> <add namespace="System.Web.Routing" /> <add namespace="System.Web.WebPages" /> <add namespace="Kendo.Mvc.UI" /> </namespaces> </pages>
现在在项目中创建一个文件夹来存放静态内容。在解决方案资源管理器中右键单击项目名称,选择添加,新建文件夹。将新文件夹命名为static
。这将是我们放置所有除 MVC 框架之外客户端示例的位置。
Visual Studio 2012 在 JavaScript Intellisense 方面有一些很好的改进,这将帮助我们编写代码。在脚本文件夹中打开名为"_references.js"
的文件,并删除其中的所有文本。这是我的"_references.js"
文件的全部内容,将其复制到你的文件中:
/// <reference path="kendo/jquery.js" />
/// <reference path="kendo/kendo.web.js" />
/// <reference path="kendo/kendo.aspnetmvc.js" />
Visual Studio 2012 使用此文件作为编辑器中 Intellisense 应使用的 JavaScript 库列表。我已经包含了 Kendo 压缩包中包含的 jQuery 文件以及我们将在大多数网页中使用的两个 JavaScript 文件。一旦你设置好这些,你将在 JavaScript 文件中获得一些非常有帮助的编码辅助,如下所示:
注意当你开始在编辑器中输入 JavaScript 代码时,所有的 Kendo 选项是如何显示出来的?当你在这本书的示例中编程时,这将变成帮助你的一项技能。
好的,现在我们准备好了!
KendoUI 语法风格
当你在网页中使用 KendoUI 框架时,你会发现有两种方法可以将小部件添加到你的内容中。标准方法是使用类似这样的 jQuery 语法在脚本元素中:
<input type="date" id="makeMeADatePicker" />
<script type="text/javascript">
$("#makeMeADatePicker").kendoDatePicker();
</script>
如所示,惯例是先通过 jQuery 选择元素,然后从 Kendo 命名空间中应用一个 JavaScript 方法,将内容转换为交互式的 Kendo UI 小部件。
现在还有一种方法,通过 HTML5 提供,可以通过称为声明性初始化的方法将 Kendo UI 小部件添加到你的内容中。这是一种通常添加以"data-"开头的特殊属性到你的元素中的实践,然后调用一个初始化器,该初始化器读取这些属性并应用适当的更改。以下代码是一个示例:
<input type="date" id="makeMeADatePicker" data-role="datepicker" />
<script type="text/javascript">
kendo.init($("#makeMeADatePicker"));
</script>
这种语法允许 JavaScript 和标记之间有更清晰的分离,这在我们在书中稍后要介绍的 MVVM 模式中非常重要。它也非常强大且表达力丰富,可以使代码更易于阅读,因为相关的属性直接包含在它们相关的元素中。包含代码的脚本块不一定出现在实际受影响的代码旁边,这可能会在复杂的项目中使追踪变得困难。
Kendo UI MVC – 基础
由于本书将大量使用 ASP.NET MVC,因此我应该定义一些重要术语,以避免以后产生混淆。MVC代表模型-视图-控制器;让我们围绕这些术语建立一个共同的理解。首先,一个网页被称为视图,当使用 C#的 Razor 语法时,网页有一个文件扩展名,cshtml
。还有使用 Visual Basic 的选项,在这种情况下,网页有一个文件扩展名,vbhtml
,但本书我们将使用 C#,所以你不会在示例中看到这一点。
其次,控制器是一个服务器端类文件,负责生成网页(视图)中包含的所有逻辑。控制器,连同路由表,还负责建立公开可访问的 URL,服务器将对此做出响应,并强制执行访问它们所需的 HTTP 动词。一般来说,控制器负责联系任何外部依赖项,如数据库或 Web 服务器,对从这些外部依赖项检索的数据执行任何必要的逻辑和计算,然后将所有处理过的数据打包成一个称为模型的对象。
然后,模型是一个对象容器,包含网页(视图)需要的数据,以便显示自己。在一个正确分离的系统里,控制器是执行所有逻辑、数据处理、用户输入处理、授权和安全的引擎。视图是数据展示者,只关心所提供数据的图形表示;除了展示所需的逻辑之外(不排除展示可能很复杂),不涉及任何其他逻辑。模型是控制器用来将其最终产品发送到视图进行展示的标准数据格式。
当在 ASP.NET MVC 环境中编程时,Kendo UI 提供了一套丰富的服务器端扩展,用于创建其小部件。你不需要编写 HTML 元素,指定其属性并将其连接到 Kendo UI JavaScript,整个过程可以使用出现在视图中的服务器端对象来完成。例如,在 MVC Razor 语法中创建一个DatePicker
小部件看起来像这样:
@(Html.Kendo().DatePicker().Name("datePickerField"))
没有 HTML,没有 JavaScript,只有 HTML 类的扩展方法。然而,当页面生成时,你可以看到发送到浏览器的内容:
<input class="k-input" id="datePicker" name="datePicker" type="date" />
<script>
jQuery(function(){jQuery("#datePicker").kendoDatePicker({format:"M/d/yyyy",
min:new Date(1900,0,1,0,0,0,0),max:new Date(2099,11,31,0,0,0,0)});});
</script>
扩展方法会动态创建所有 HTML、JavaScript 和 CSS 信息。你可以看到最终输出如何使用 jQuery 方法选择输入元素,并使用.kendoDatePicker(…)
通过 JavaScript 创建小部件。因此,尽管程序员没有编写 JavaScript,但 Kendo UI 仍然需要它;MVC 扩展只是正常 Kendo UI 客户端框架的包装器。
我还应该解释,尽管视图是生成发送到用户浏览器的最终网页的部分,但它首先在服务器上处理。Razor 语法(以@
开头的一切)永远不会出现在最终的页面标记中,它是在服务器上处理的,以便生成最终的标记。这意味着 Kendo MVC 扩展方法实际上是在服务器端创建最终标记的快捷方式,以便它们像在 JavaScript 中那样正常工作。
在 MVC 框架中编程允许在 Web 服务器内部实现非常清晰的关注点分离,这反过来又允许在视图的运行方式和它们对服务器端逻辑的依赖性方面有很大的灵活性。例如,使用数据的控件可以从视图本身接收这些数据(对服务器端逻辑的依赖),或者它们可以通过调用返回 JSON 的动作方法从客户端查询数据(对服务器端逻辑的依赖较少)。
作为服务器依赖实现的一个示例,这里有一个包含嵌入式模型数据的强类型视图,然后可以由页面上的控件使用。强类型视图是一个指定包含其模型数据的特定类型对象的视图页面。您可以在示例的第一行看到强类型模型对象,它以@model
开头:
@model IEnumerable<LearningKendoUIWeb.Models.StateTerritory>
<textarea id="serverData" style="display:none">
@Html.Raw(ViewBag.serverData)
</textarea>
<script type="text/javascript">
varserverData = eval($("#serverData").html());
for (var i = 0; i<serverData.length; i++) {
console.log(serverData[i].Name);
}
</script>
ViewBag
是一个动态对象,在控制器动作方法和视图页面上可用。它是一个字典对象,可以包含您在视图页面上需要的任何数据或对象。控制器可以添加任何您需要添加到ViewBag
中的内容,然后您的视图页面将能够访问这些数据或对象,就像这个示例代码所展示的那样。在这种情况下,控制器附加了一个名为serverData
的对象,其中包含其模型数据的 JSON 表示。我们使用名为eval()
的 JavaScript 函数将其解析为 JavaScript 对象,然后在 JavaScript 控制台上显示其内容。这仅仅是一个示例,说明如何将数据嵌入到视图本身,而无需使用额外的网络请求,例如 jQuery 函数$.get
或$.ajax
来检索显示在页面上的数据;在某些情况下,这可能是有益的,因为需要权衡网络流量和服务器可以预先提供的即时数据可用性。
ViewBag.serverData
属性在控制器中填充如下:
publicActionResultAutoCompletePage()
{
var repository = new SampleRepository();
var data = repository.GetStatesAndTerritories();
ViewBag.serverData = new JavaScriptSerializer().Serialize(data);
return View(data);
}
注意,在这个示例中,控制器既填充了这个ViewBag
属性,又将相同的数据作为强类型模型发送到视图;这不是必需的,但在这里很有用,因为我们可以利用服务器的JavaScriptSerializer
类在我们将其发送到视图之前为我们创建 JSON。以下是当我们用具有名称属性的数组对象的 JSON 表示填充ViewBag.serverData
时,JavaScript 控制台显示的内容:
从单独的端点请求数据,然后在获取后使用它的情况要常见得多。这允许使用来自外部源的数据,并打破了服务器在页面内部提供数据的依赖性,这意味着特定的服务器实现可能不太重要且更简单。jQuery 提供了几种常见且友好的方式来检索 JSON 数据,如$.ajax
、$.get
和$.getJSON
。Kendo 也通过其小部件的配置选项提供标准方式来检索外部数据,通常通过transport.read
属性方法。我们将在本章的其余部分以及本书的其余部分中看到更多关于此的内容,当我们讨论 DataSource 和 Grid 时。
管理数据
Kendo UI 框架由两部分组成——框架组件和用户界面(UI)小部件。本书中我们将涵盖的大部分内容与用户界面小部件及其使用方法相关,但我们将从如何在 Kendo UI 中管理数据这个重要主题开始。DataSource 组件和模板提供了一个良好的起点,并将为我们在这本书的其余部分使用的基础。
模板
Kendo UI 模板是包含一小部分页面标记的脚本块,这些标记由其他 Kendo UI 小部件用于显示重复内容。我们将首先介绍这些内容,因为它们将在我们接下来的所有示例中使用。以下是一个简单模板的示例:
var template = kendo.template("<span>#= horseColor #</span>");
$("#horseDiv").html(template({
horseColor: 'brown}));
运行此代码会将horseDiv
的 HTML 内容设置为包含传递到模板函数对象中的horseColor
值的 span 元素。它将产生以下代码输出:
<div id='horseDiv'><span>brown</span></div>
模板也可以在特殊类型的 HTML 脚本块中编写,这样它们的布局在 HTML 内容中看起来更自然。
<script type="text/x-kendo-template" id="template">
<tr>
<td>#= rank #</td>
<td>#= rating #</td>
<td>#= title #</td>
<td>#= year #</td>
</tr>
</script>
在这个模板示例中,请注意包含代码片段#= variable_name #
的行。这些表示由 Kendo UI 模板引擎解释的代码部分。当模板被使用时,这些代码块内的变量名被提供给模板。在模板内部使用的 JavaScript 属性名需要在调用模板时传递给模板的对象上的属性。请注意,脚本类型是x-kendo-template
而不是javascript
,这是很重要的,这样浏览器就不会尝试自行执行脚本块。以下是一个代码示例,展示了如何在 JavaScript 中初始化此模板:
<script type="text/javascript">
var template = kendo.template($("#template").html());
functionshowMovies() {
$("#moviesTable").html(template(
{rank: 1, rating: 9.2, title: 'Prometheus', year: 2012}
));
}
showMovies();
</script>
注意模板是通过调用 kendo.template()
来创建的。这个方法接受字面模板代码作为其参数,这就是为什么示例中显示了调用 jQuery 语句 $("#template").html()
,因为这段代码返回了模板脚本块在网页中出现的字面内容。因此,在这个例子中,它等同于调用 kendo.template('<tr><td>#= rank #</td>…')
。这意味着模板也可以通过直接在构造函数中键入确切的模板代码来创建。
当模板对象作为方法被调用时,它需要传入的数据作为参数。当上面的示例代码运行时,它会产生以下输出:
<table id="moviesTable">
<tr>
<td>1</td>
<td>9.2</td>
<td>Prometheus</td>
<td>2012</td>
</tr>
</table>
模板还可以包含 JavaScript,这使得执行更高级的操作成为可能,例如遍历数组并为数组中的每个项目单独渲染模板。在这种情况下,你需要向模板提供一个对象数组而不是之前的一个单独的对象。这次,使用显式的参数名 data
是至关重要的。注意 JavaScript 代码被单 #
符号包围,如 # javascript code #
,变量语句被 #=
和 #
包围,如 #= variable statement #
。还要注意 #
符号和内容之间的空格很重要。
<script type="text/x-kendo-template" id="template">
# for(vari=0; i<data.length; i++) { #
<tr>
<td>#= data[i].rank #</td>
<td>#= data[i].rating #</td>
<td>#= data[i].title #</td>
<td>#= data[i].year #</td>
</tr>
# } #
</script>
模板是构建功能 Kendo UI 小部件的重要组成部分,当与 DataSources 和 Grids 结合使用时,它们将变得更加有用,正如我们稍后将要看到的。
DataSource
Kendo UI DataSource 是一个 JavaScript 对象,为数据提供了各种 Kendo UI 小部件的共同接口。关于 DataSource 对象的完整文档可以在 Kendo UI 网站上的此地址找到:docs.kendoui.com/api/framework/datasource
。DataSource 是一个相当复杂的对象,依赖于一些需要单独解释的构建块。这些构建块是 Kendo 对象,称为 Schema、Transport 和 Model。让我们首先处理这些,然后再继续探索 DataSource 本身。
重要的是要注意,在创建 DataSource 对象时,你应该使用 new
关键字来实例化一个新对象,而不是仅仅使用对象字面量:
var dataSource = new kendo.data.DataSource({...<properties>...});
模型
模型对象来自命名空间 kendo.data.Model
,并继承自 Kendo 的 ObservableObject
。它为 DataSource 使用的提供了一种已知结构,或模型,同时也可以用来启用一些更高级的功能,例如变更跟踪。要创建一个新的模型,你必须通过方法 kendo.data.Model.define()
来实现。在这个方法中,你需要传递一个对象来定义模型的结构,并设置数据元素的可配置选项。以下是一个模型的示例:
var Service = kendo.data.Model.define( {
id: "serviceId", // the identifier of the model
fields: {
"serviceName": {
type: "string"
},
"unitPrice": {
type: "number"
},
"serviceId": {
type: "number"
}
}
});
var currentService = new Service( {
serviceName: "Rotate Tires",
unitPrice: 29.95,
serviceId: 400
});
console.log(currentService.get("serviceName")); // outputs "Rotate Tires"
console.log(currentService.get("unitPrice")); // outputs 29.95
在这个示例中,我们创建了一个具有三个属性的模型,并为每个属性设置了数据类型。然后,我们根据模型定义创建了一个新的模型对象,并演示了如何通过 model.get()
方法访问其属性。我们刚刚演示了模型对象的 ID 是通过名为 id
的属性定义的,字段是通过名为 fields
的属性定义的。在 fields
属性中,这些是可以设置以配置每个数据元素的选项:
fields: {
"serviceName": { // Property name for a field
type: "string", // "string"(default), "number", "boolean", or "date"
defaultValue: "Inspection", // Default value for field when model is
/ created. Default for string is "", number
// is 0, and date is new Date() (.i.e. today)
editable: true, // Specifies whether field is editable
nullable: false, // Specifies if default value should be used when empty
parse: function(){...} // Specifies custom parser for field value
validation: {...} // Specifies the validation options used by Kendo
// Validator such as 'required', 'min', and 'max'.
},...
}
这些并非都是必需的,但在你需要一个非常具体的配置时它们是可用的。以下是从 Kendo UI 网站上的一个示例:
var Product = kendo.data.Model.define( {
id: "id", // the identifier is the "id" field (declared below)
fields: {
/* name of the field */
name: {
type: "string", // the field is a string
validation: { // validation rules
required: true // the field is required
},
defaultValue: "<empty>" // default field value
},
/* name of the field */ price: {
type: "number", // the field is a number
validation: { // validation rules
required: true, // the field is required
min: 1 // the minimum value is 1
},
defaultValue: 99.99 // default field value
},
/* name of the field */ id: {
editable: false, // this field is not editable
nullable: true // a default value will not be assigned
}
}
});
由于模型中的属性是可观察的,你需要使用特殊的获取器和设置器方法来正确触发其他函数和对象观察到的行为。要检索这些属性之一的当前值,请使用 model_name.get()
,例如 currentService.get('unitPrice')
。要设置属性的值并因此更改它,请使用 model_name.set()
,例如 currentService.set('unitPrice', 14.95)
。可观察对象的概念是 MVVM 框架的一个关键特性,我们将在后面的章节中介绍。
模型对象上可用的另外两种方法是 isNew
和 toJSON
。isNew
方法检查模型是否为新的。这是通过检查 id
字段是否仍然设置为默认值来确定的。如果 id
字段没有设置为默认值,则模型对象不被视为新的。toJSON
方法返回模型属性和值的完整 JSON 表示。
正如我提到的,模型继承自 ObservableObject
,它公开了三个你可以附加自定义行为的事件——change
、get
和 set
。这些的语法是使用 model.bind()
,后面跟着事件名称和处理该事件的函数:
currentService.bind('change', function(e){
alert(e.field + " just changed its value to " +
currentService.get([e.field]));
});
Schema
DataSource 中的 schema
对象负责描述原始数据格式。它在模型之上工作,甚至可以包含模型定义。Schema 的任务是指导 DataSource 在原始数据对象中查找有关错误、聚合、数据、分组和总记录的信息。这些信息作为 schema
对象中的属性存在,如下所示:
schema: {
errors: function(response) {
return response.errors;
},
aggregates: function(response) {
return response.aggregates;
},
data: function(response) {
return response.data;
},
total: function(response) {
return response.totalCount;
}
}
在前面的代码示例中,每个属性都设置为函数,当传递原始数据对象时,将返回该对象内的适当数据。这些属性也可以设置为文本字段,在这种情况下,给定的字段名必须存在于对象的顶层,并且已经包含适当格式的适当数据:
schema: {
errors: "errors_field_name",
aggregates: "aggregates_field_name",
data: "data_field_name",
total: "total_field_name"
}
aggregates
属性需要以对象格式返回数据,其结构类似于以下示例。aggregates对象中的每个属性名都可以包含有关其聚合值的信息,例如最大值(max)、最小值(min)或总计数:
{
unitPrice: { // Field Name
max: 100, // Aggregate function and value
min: 1 // Aggregate function and value
},
productName: { // Field Name
count: 42 // Aggregate function and value
}
}
在这种情况下,数据在unitPrice字段上定义了最大值和最小值,在productName字段上定义了计数。数据源对象没有计算这些值;相反,它们已经存在于从远程服务器发送的原始数据中,并且模式已经向数据源对象指示了它们的位置。可以使用函数来计算聚合值,但通常原始数据已经包含由远程服务器返回的这些值。
如我之前所说,模式可以包含一个模型定义。如果是这种情况,数据源将为你调用kendo.data.Model.define
来处理模型定义,以便从原始数据中创建模型对象:
var dataSource = new kendo.data.DataSource({
schema: {
model: {
id: "ProductID",
fields: {
ProductID: {
editable: false,
nullable: true
},
...
如果你已经定义了一个模型定义,你可以简单地引用它,数据源将像使用它一样使用它:
vardataSource = new kendo.data.DataSource({
schema: {
model: Product // Use the existing Product model
}
});
schema
对象有一个parse
属性,你可以将其设置为在处理原始数据之前将被调用的函数。这给你提供了一个机会,如果你需要的话,进行任何预处理。还有一个type
属性,可以设置为json
或xml
。
传输
transport
对象包含数据源可以使用它来与远程服务器通信以执行其任何正常数据功能的属性。这些数据功能是create
、destroy
、read
和update
(对应于可以在记录上执行的不同操作)。这些数据功能作为transport
对象内的属性对象存在,并遵循相同的配置选项模式。我应该指出,并非所有数据功能都是必需的;只有那些需要在你的transport
对象中定义的功能才需要定义。这是transport
对象的基本配置结构。
transport: {
create: { // this sets configuration for creating new records
// on the remote server
},
destroy: { // this sets configuration for deleting records
// on the remote server
},
read: { // this sets configuration for reading records
// from the remote server
},
update: { // this sets configuration for updating records
// on the remote server
},
autoSync: false, // set true to automatically sync all changes
batch: false // set true to enable batch mode
}
这里是配置传输对象的远程数据操作的不同的选项。这四个属性遵循相同的配置模式,但在本代码示例中,我展示了不同的配置方式以供参考。在这个第一个代码示例中,我配置了创建操作,仅将 HTML 元素的值发送到远程服务器。
create: { // for creating data records on remote source.
url: "/orders/create", // the url to the create service.
data: { // data to send to the create service as part of the request.
// this can also be specified as a function call.
orderId: $("#input").val()
},
cache: true, // make false to force fresh requests every time.
contentType: "application/json", // default is
// "application/w-www-form-urlencoded"
dataType: "json", // "jsonp" is also common.
type: "POST" // which http verb to use.
}
在这个示例中,我们已将销毁方法设置为使用 jQuery $.ajax
函数将数据发送到远程服务器,而不是直接在销毁配置对象上配置它。如果你更喜欢 jQuery 语法并希望轻松地将回调函数附加到操作的结果,你可以这样做。
destroy: { // same options as "create", with some alternatives shown.
// this is how you use $.ajax() to run this remote service call.
// this option can be used with "create", "destroy", "read",
// and "update"
$.ajax( {
url: "/orders/destroy",
data: options.data, // the data field contains paging, sorting,
// filtering, and grouping data
success: function(result) {
// notify the DataSource that the operation is complete
Options.success(result);
}
});
}
在这个例子中,我们创建了一个函数作为读取操作的数据源。如果您需要在接收到远程数据之前执行一些自定义逻辑,或者由于某些原因需要完全绕过远程数据源,这可能很有用。
read: { // same options as above in "create" and "destroy".
data: function() { // this is how you specify data as a function.
return {
id: 42,
name: "John Doe"
};
}
}
请记住,您刚才看到的配置选项对任何传输操作都有效,我只是简单地展示了每个配置的不同操作作为示例。当 DataSource 配置了这样的传输配置时,它将使用这些选项中的属性和函数来执行相关操作。当它加载数据时将调用read
,当记录被更改时将调用update
,当记录被删除时将调用destroy
,当添加新记录时将调用create
。
其他 DataSource 属性
当从本地数据读取时,您需要通过使用名为data
的属性来引用它,如下所示:
var someData = [{ title: 'Prometheus', year: 2012, rating: 9, rank: 25 }];
var dataSource = new kendo.data.DataSource({
data: someData
});
我们尚未看到的 DataSource 的一些其他属性更多用于数据处理——aggregate
、filter
、group
、sort
、page
和pageSize
。它们可以在客户端数据上工作,或者可以通过使用serverAggregates
、serverFiltering
、serverGrouping
、serverSorting
和serverPaging
属性来请求服务器执行操作,通过将这些属性添加到 DataSource 对象属性列表并将它们设置为 true。
aggregate
属性接受一个字段名和聚合函数名的数组:
aggregate: [{ field: 'title', aggregate: 'count' }]
filter
属性可以接受一个简单的对象、简单对象的数组,或者一个具有更多逻辑的可配置对象,以指定应在数据上执行筛选:
// simple object
filter: { field: 'title', operator: 'startswith', value: 'Shawshank' }
// ...or array...
filter: [{field: 'year', operator: 'eq', value: '1998'}, {field: ...
// ...or configurable object...
filter:{
logic: "or",
filters: [
{ field: 'title', operator: 'startswith', value: 'Shawshank' }]
}
这些是可以与筛选对象一起使用的不同运算符。它们也可以在通过使用serverFiltering
属性向服务器请求筛选时使用。
-
等于:
eq
,==
,isequalto
,equals
,equalto
,equal
-
不等式:
neq
,!=
,isnotequalto
,notequals
,notequalto
,notequal
,ne
-
小于:
lt
,<
,islessthan
,lessthan
,less
-
小于或等于:
lte
,<=
,islessthanorequalto
,lessthanequal
,le
-
大于:
gt
,>
,isgreaterthan
,greaterthan
,greater
-
大于或等于:
gte
,>=
,isgreaterthanorequalto
,greaterthanequal
,ge
-
以...开头:
startswith
-
以...结尾:
endswith
-
包含:
contains
group
和sort
属性可以接受一个对象或对象数组来指定分组:
group: { field: 'year', dir: 'asc' }
sort: { field: 'title', dir: 'desc' }
page
和pageSize
属性都接受数字来分别表示页码和每页的记录数。
DataSource 方法
DataSource 方法用于更改或检索 DataSource 对象的某些元素。其中一些与刚刚讨论过的相同数据操作属性相关——aggregate
、aggregates
、filter
、group
、page
、pageSize
和 sort
。在这些情况下,不传递参数调用方法将返回 DataSource 中同名属性的当前值;调用带有参数值的方法将设置 DataSource 中同名属性的值为传入的新值:
// get the current group descriptors
var g = dataSource.group();
// set a new value for filtering
dataSource.filter({ field: 'year', operator: 'gt', value: 1990 });
此外,还有添加和删除记录的方法。add
和 insert
方法都向 DataSource 添加一个新记录。add
方法简单地接受一个模型对象或与 DataSource 中的项目当前数据格式匹配的对象字面量。insert
方法接受与 add
相同的对象,但还指定一个 index
属性,指示插入新记录的零基位置。remove
方法接受一个模型对象并将其从 DataSource 中删除:
// add a new item
dataSource.add({ year: 1997, title: 'The Fifth Element', rating: 10 });
// insert an item at the 6th position in the DataSource
dataSource.insert(5, {year: 1995, title: 'Twelve Monkeys', rating 9.5});
// remove an item from the DataSource
var movie = dataSource.at(5);
dataSource.remove(movie);
at
、get
和 getByUid
方法用于从 DataSource 中检索特定记录:
// get the 3rd item in the DataSource
var movie = dataSource.at(2);
// get the model instance with an id of 5
// (id is determined by the value of the schema.model.id property)
var movie = dataSource.get(5);
// get the model instance, or ObservableObject if no model has been set
// uid is a property inherited from ObservableObject
varuid = $("tr").data("uid");
var movie = dataSource.getByUid(uid);
fetch
、query
、read
、sync
、cancelChanges
和 view
方法用于管理 DataSource 的当前内容和结构:
// fetches data using the current filter/sort/group/paging information.
// will fetch data from transport if data is not already available in memory.
dataSource.fetch(); // can optionally take a callback function which
// is executed once the data is ready.
// executes a query over the data (i.e. paging/sorting/filtering/grouping)
// this effects what the call to dataSource.view() will return.
dataSource.query({ page: 5, pageSize: 20, group:{field:'year',dir:'asc'}});
// read data into the DataSource using the transport.read setting
dataSource.read(); // also conveniently causes the change event to fire
// synchronizes changes through the transport for any pending CRUD operations.
// if batch mode is enabled, it uses only one call per operation type (create,
// read, update, destroy)
dataSource.sync();
// discards all un-synced changes made to the DataSource
dataSource.cancelChanges();
// returns the current state of the items in the DataSource with all applied
//settings such as paging, sorting, filtering, and grouping.
// to ensure that data is available, this method should be used from
//within the change event of the DataSource
change: function(e){
...
kendo.render(template, dataSource.view());
}
为了完成列表,我们将查看 data
、total
和 totalPages
:
// retrieve an observable array of items (the current data within the DataSource)
var movies = dataSource.data();
// set the DataSource to some new data
datSource.data([{year: 2009, title: 'Cargo', rating: 6.8}, {year: ... ]);
// get, but not set, the total number of items in the DataSource
var total = dataSource.total();
// get, but not set, the total number of pages of items in the DataSource
var pages = dataSource.totalPages();
重要的是要注意,你必须调用 dataSource.read()
以使 DataSource 对象启动读取过程并自行填充数据。换句话说,在你调用 dataSource.read()
之前,你的 DataSource 中没有任何可读取的内容。
DataSource 事件
DataSource 对象上有三个可用的事件——change
、error
和 requestStart
。当数据从传输中更改或读取时,会触发 change
事件。当数据读取或数据同步过程中发生错误时,会触发 error
事件;如果 DataSource 中的 schema.errors
已设置,并且来自服务器操作的响应包含由 schema.errors
指定的字段中的数据,也会触发 error
事件。当数据请求即将开始时,会触发 requestStart
事件。与其他事件一样,这些事件可以作为 DataSource 定义的一部分设置,或者稍后通过 bind
方法设置。
// set event handler as part of DataSource definition
var dataSource = new kendo.data.DataSource({
change: function(e){
// handle event
}
});
// or set event handler later through the bind method
dataSource.bind("error", function(e){
// handle event
});
正如你稍后将会看到的,更改事件是一个很好的地方,可以在 DataSource 读取新记录时生成标记。它也是放置任何其他应该对 DataSource 中的更改做出响应的代码的适当位置。
开始使用基本用法
既然我们已经看到了 DataSource 内部组件的定义,我们将组合我们的第一个示例页面,以演示在 JavaScript 中使用 DataSource 对象的基本用法。向项目的静态文件夹中添加一个新的 HTML 文件,并将其命名为 DataSource.html
。首先添加以下代码:
<!DOCTYPE html>
<html>
<head>
<title>DataSource</title>
<script src="img/jquery.js"></script>
<script src="img/kendo.all.js"></script>
<link href="/Content/kendo/kendo.common.css" rel="stylesheet" />
<link href="/Content/kendo/kendo.default.css" rel="stylesheet" />
</head>
<body>
<div id="example" class="k-content">
<table id="movies">
<thead>
<tr>
<th>Rank</th>
<th>Rating</th>
<th>Title</th>
<th>Year</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="4"></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
我们已经在页面的头部引用了 jQuery 和 Kendo UI Web JavaScript 文件。现在让我们在div
标签之后添加一个模板块,以便我们可以编写脚本以创建额外的表格行:
<script id="template" type="text/x-kendo-template">
<tr>
<td>#= rank #</td>
<td>#= rating #</td>
<td>#= title #</td>
<td>#= year #</td>
</tr>
<script>
现在我们需要的是能够获取一些数据,并使用由这个模板定义的布局来填写表格,即使用数据源。在您刚才输入的模板脚本块之后添加以下代码:
<script type="text/javascript">
$(document).ready(function() {
// create a template using the above definition
var template = kendo.template($("#template").html());
var movies = [
{ "rank": 1, "rating": 9.2, "year": 1994,
"title": "The Shawshank Redemption" },
{ "rank": 2, "rating": 9.2, "year": 1972,
"title": "The Godfather" },
{ "rank": 3, "rating": 9, "year": 1974,
"title": "The Godfather: Part II" },
{ "rank": 4, "rating": 8.9, "year": 1966,
"title": "Il buono, ilbrutto, ilcattivo." },
{ "rank": 5, "rating": 8.9, "year": 1994,
"title": "Pulp Fiction" },
{ "rank": 6, "rating": 8.9, "year": 1957,
"title": "12 Angry Men" },
{ "rank": 7, "rating": 8.9, "year": 1993,
"title": "Schindler's List" },
{ "rank": 8, "rating": 8.8, "year": 1975,
"title": "One Flew Over the Cuckoo's Nest" },
{ "rank": 9, "rating": 8.8, "year": 2010,
"title": "Inception" },
{ "rank": 10, "rating": 8.8, "year": 2008,
"title": "The Dark Knight" }
];
var dataSource = new kendo.data.DataSource({
data: movies,
change: function () {
// subscribe to the CHANGE event of the data source
$("#movies tbody").html(
kendo.render(template, this.view())); // populate the table
}
});
// read data from the "movies" array
dataSource.read();
});
</script>
让我们逐步分析这段代码。你应该能认出前面几行,其中创建了一个 Kendo 模板,这个模板是从你刚才输入的脚本块中创建的。之后,你将看到一个包含关于各种电影数据的 JavaScript 对象数组。这个数组将成为下一个数据源对象的原始数据。数据源对象被实例化(注意new
关键字)到名为dataSource
的变量中。它将movies
数组作为其数据参数,并定义了一个处理数据源对象change
事件的函数。在这个change
事件内部,我们使用 jQuery 选择movies
表格,然后使用kendo.render()
从我们的template
变量为dataSource
对象中的每个项目生成标记。注意我们使用的模板不需要特殊的 JavaScript 来迭代集合;数据源对象通过this.view()
将所有数据传递给change
事件。最后,我们调用dataSource.read()
来读取数据,从而触发change
事件,将内容添加到我们的movies
表格中。
kendo.render()
方法将其第一个参数作为模板函数,第二个参数作为数据数组。它将数据通过模板运行,生成结果标记并返回给调用者。在上面的例子中,我们使用了 jQuery 将<tbody>
元素的 HTML 设置为kendo.render()
函数的结果。
绑定到远程数据
我们上一个例子是演示如何使用本地数据(一个 JavaScript 数组)与数据源结合使用。使用数据源与远程系统上存在的数据进行操作也是非常常见且重要的。为了模拟这种情况,我们将转向 ASP.NET MVC 框架来创建一个用于我们远程数据的服务器。
在 Visual Studio 的解决方案资源管理器窗口中,右键单击控制器文件夹,选择添加,控制器。将新控制器命名为KendoController,并保持打开的对话框的其余部分为默认设置。
新创建的控制器类将出现在 Visual Studio 的编辑器部分,你将看到文件中有一个通用的Index()
方法。这个方法被称为动作方法,用于处理返回给网页浏览器的 HTML 响应。上面的注释表明了用于定位此动作方法的路由和 HTTP 动词:
// GET: /Kendo/
public ActionResult Index()
{
return View();
}
在这种情况下,它表明键入路由"Kendo",如http://<server-name>/Kendo/
,将匹配此动作方法并导致它将视图返回到浏览器。指定http://<server-name>/Kendo/Index
也将有效,通常在正常路由中提供控制器名称"Kendo"和动作方法名称"Index"。按照惯例,MVC 框架使用后缀"Controller"命名所有控制器类,但在实际路由(如您网络浏览器地址栏中的路径)中引用控制器时不使用后缀。这意味着当KendoController
类是路由的一部分时,它被称为"kendo"。GET 是此控制器在浏览器请求此路由时将接受的默认 HTTP 动词。
在KendoController
顶部添加一个用于我们即将创建的命名空间LearningKendoUIWeb.Repository
的using
语句。还要添加Kendo.Mvc.UI
和Kendo.Mvc.Extensions
:
添加一个名为RemoteData
的新动作方法,并按照以下方式设置它:
publicJsonResultRemoteData()
{
var repository = new SampleRepository();
var data = repository.GetAllMovies();
returnJson(result, JsonRequestBehavior.AllowGet);
}
这是一个简单的实例化存储库(我们将在接下来的时刻创建它),从该存储库中收集一些数据,然后将它作为 JSON 返回给客户端的方法。Json()
方法的第二个参数通知控制器类,即使动词是 GET,也可以从这个方法返回 JSON 数据。
右键单击Models文件夹,然后单击添加,类。将新类命名为Movie.cs
。这是一个非常简单的类,用于存储有关电影的数据:
namespace LearningKendoUIWeb.Models
{
public class Movie
{
public int Rank { get; set; }
public double Rating { get; set; }
public int Year { get; set; }
public string Title { get; set; }
}
}
向项目中添加一个新文件夹,并将其命名为Repository
。向此文件夹添加一个名为SampleRepository.cs
的类:
using LearningKendoUIWeb.Models;
namespaceLearningKendoUIWeb.Repository
{
public class SampleRepository
{
public List<Movie>GetAllMovies()
{
var movies = new List<Movie>{
new Movie { Rank = 1, Rating = 9.2,
Title = "The Shawshank Redemption", Year = 1994 },
new Movie { Rank = 2, Rating = 9.1,
Title = "The Godfather", Year = 1974 }
};
Return movies;
}
}
}
随意添加更多电影到这个列表,越多越好。现在我们有一个简单的存储库类,可以返回电影对象的列表,因此我们在KendoController
中创建的动作方法最终是有效的。当调用RemoteData
动作方法时,它将以如下所示的 JSON 对象数组形式返回电影对象列表:
我已经向我的存储库添加了更多电影,但结果的结构是相同的。这正是 DataSource 知道如何使用的数据类型。以下是连接 DataSource 以使用它的方法,在RemoteData.cshtml
文件中找到创建dataSource
变量的 JavaScript 代码行,并更改代码,使其看起来像这样:
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: 'Kendo/RemoteData/'
}
},
change: function () {
$("#movies tbody").html(kendo.render(template, this.view()));
}
});
我们不是使用data
属性指向一个本地可用的对象数组,而是使用transport
属性告诉 Kendo 我们需要从远程源请求数据。在这种情况下,我们只指定了 DataSource 如何读取远程数据,这就是我们所需要的,因为我们对 DataSource 的唯一方法调用就在这一行:
dataSource.read();
这些例子只是触及了表面,但它确实展示了 DataSource 在实际页面上的应用。然而,真正独立演示 DataSource 对象是很困难的。实际上,DataSource 只有在它服务于数据丰富的控件时才有用,比如 Kendo UI Grid。在接下来的页面中,我们将探讨这个 Grid 控件,并能够展示一个 Grid 可以充分利用的更完全配置的 DataSource。我们还将看到如何在视图页面中通过 MVC Razor 语法配置 Grid 和 DataSource。
页面布局
现在我们已经讨论了 Kendo UI 框架的 DataSource 和 Template 功能,我们可以将注意力转向那些在网页上提供图形元素的控件。其中一些控件实际上帮助您组织页面上的内容或数据,Grid 就是一个很好的例子,我们将在下一部分进行介绍。
Grid
Kendo UI Grid 是一个非常实用的控件,需要熟悉。它是一种简单的方法,可以将数据转换成可使用和交互式的表格,这在通常需要完整的服务器控件(如 ASP.NET WebForms)或页面标记中的复杂且耗时的 JavaScript 开发中是常见的。实际上,设置一个简单的示例非常容易。假设我们有一些如下所示的 JavaScript 数据,我们想在网页中显示:
<script type="text/javascript">
var repairs = [{
name: "State Inspection",
price: 39.75,
labor: 1,
staff: 1
},
{
name: "Brake & Clutch System Service",
price: 149.95,
labor: 3,
staff: 1
},
{
name: "Power Steering Service",
price: 109.96,
labor: 3,
staff: 1
},
{
name: "Cooling System Service",
price: 126.95,
labor: 2,
staff: 1
},
{
name: "Oil Change",
price: 37.77,
labor: 1,
staff: 1
},
{
name: "CV Axle Replacement",
price: 271.11,
labor: 5,
staff: 2
},
{
name: "Battery Cabling Replacement",
price: 179.97,
labor: 2,
staff: 1
},
{
name: "Battery Replacement",
price: 118.38,
labor: 1,
staff: 1
},
{
name: "Fuel Induction Service",
price: 168.88,
labor: 3,
staff: 2
},
{
name: "Engine Air Filter Replacement",
price: 36.63,
labor: 1,
staff: 1
},
{
name: "Timing Belt Replacement",
price: 221.75,
labor: 3,
staff: 2
},
{
name: "Drive Belt Replacement",
price: 194.79,
labor: 3,
staff: 2
}
];
</script>
为了将其转换成一个格式良好的动态表格,通常需要一些循环和 HTML 标记生成,可能通过 jQuery 实现。然而,通过 Kendo UI,我们只需要创建一个 kendoGrid()
函数,我们就可以看到一些魔法在行动。注意,创建一个从这些数据中生成的表格所涉及的代码是多么少:
<div id="repairsGrid"></div>
<script type="text/javascript">
$("#repairsGrid").kendoGrid({
dataSource: repairs
});
</script>
下面是这段简单代码的页面输出:
看看相关的代码是否甚至不需要在网页中存在表格?Kendo UI 生成了它需要的一切,以便在页面上以表格的形式显示这些数据。现在我们可以将注意力转向创建更互动和智能的表格,并探索 Kendo UI Grid 控件在显示来自不同来源的数据方面能提供什么。
列
首先,我们可以通过在 columns
对象数组上指定属性来控制 Grid 的格式化。这个对象数组用于指示 Grid 如何适当地显示数据,以便它在页面上看起来像你想要的那样。以下是一个使用我们刚才看到的 Grid 的列对象示例,展示了可用于格式化的各种选项:
$("#repairsGrid").kendoGrid({
...
columns: [{
field: "name",
title: "Service",
width: 300
},
{
field: "price",
title: "Price",
width: 50,
format: "${0:##.##}"
},
{
field: "labor",
title: "Labor",
width: 50,
template: "#= labor# hour(s)"
},
{
field: "staff",
title: "Staff",
width: 50,
template: "#= staff # tech(s)"
}]
这里是输出效果:
还有一些简单的选项,通过指定哪些列是可筛选或可排序的,来启用一些动态交互行为。请注意,这些选项只有在 Grid 作为整体将 pageable
和/或 sortable
设置为 true
时才有用。
$("#repairsGrid").kendoGrid({
...
columns: [{
field: "name",
title: "Service",
width: 300,
sortable: true,
filterable: true
},
{
field: "price",
title: "Price",
width: 50,
format: "${0:##.##}",
sortable: true,
filterable: true
},
{
field: "labor",
title: "Labor",
width: 50,
template: "#= labor # hour(s)",
sortable: true,
filterable: true
},
{
field: "staff",
title: "Staff",
width: 50,
template: "#= staff # tech(s)",
sortable: false,
filterable: false
}],
sortable: true,
filterable: true
注意以下截图,服务列是如何按字母顺序排序的,我已经点击了过滤器图标,这使我能够对要在页面上显示的数据输入过滤器。您可以看到过滤器图标位于屏幕上打开窗口的上方,它看起来像一个小漏斗。Kendo UI 通过我们在网格上设置的dataSource
属性来处理实际的排序和过滤。这意味着您在提供给网格的dataSource
上设置的设置将被网格用于排序和过滤:
当网格配置为允许编辑数据时,columns
属性允许您指定一个自定义编辑函数,该函数可以在更改该列中的数据时使用。这是一种为用户提供更简单的方式来输入更改,甚至控制可以进行的更改类型的有用方式。例如,此更新的代码示例显示了向Labor
列添加编辑函数,以便在编辑时显示下拉列表,为用户提供一组特定的选项进行选择。这里还有一些其他更改,我们将在下一节中讨论:
$("#repairsGrid").kendoGrid({
dataSource: repairs,
columns: [
{
title: "Action",
width: 75,
command: ["edit"]
},
{
field: "name",
title: "Service",
width: 300,
sortable: true,
filterable: true
},
{
field: "price",
title: "Price",
width: 50,
format: "${0:##.##}",
sortable: true,
filterable: true
},
{
field: "labor",
title: "Labor",
width: 50,
template: "#= labor # hour(s)",
sortable: true,
filterable: true,
editor: function (container, options) {
varselectEditor = $("<select name=" + options.field +
"></select>");
selectEditor.append(new Option("1", 1));
selectEditor.append(new Option("2", 2));
selectEditor.append(new Option("3", 3));
selectEditor.append(new Option("4", 4));
selectEditor.append(new Option("5", 5));
selectEditor.appendTo(container);
}
},
{
field: "staff",
title: "Staff",
width: 50,
template: "#= staff # tech(s)",
sortable: false,
filterable: false
}],
sortable: true,
filterable: true,
editable: "inline"
这是editor
函数的输出,显示了当行进入编辑模式时出现的下拉列表。设置<select>
元素的name
属性非常重要,以便 Kendo 可以在编辑保存时将用户的选项绑定回dataSource
。
当使用此类自定义编辑函数时,传入的container
和options
对象具有一些特定的属性,这些属性在您编写函数时可能对您有所帮助。container
对象是您应该添加任何新标记的页面元素,正如我们在示例中所做的那样。options
对象包含两个属性:options.field
和options.model
。options.field
属性包含您应该在新的标记中使用的字段名称,以便 Kendo 可以正确绑定一切。options.model
属性包含对在dataSource
中指定的实际数据模型的引用(如果指定了的话);这使您能够访问在创建自定义逻辑时可能很重要的数据。
在代码示例中出现的其他更改包括在网格定义上的editable: "inline"
属性(这是编辑功能正常工作所必需的;inline
的替代方案是popup
,它打开一个特殊窗口以编辑记录),以及包含命令按钮的新列。列对象的命令属性接受一个命令按钮数组,用于在每一行中生成。此数组可用的选项包括edit
、create
、destroy
、save
和cancel
。当我们更详细地介绍如何将网格绑定到 CRUD 操作时,我们将很快回到这个话题。
注意,要向网格添加这些命令按钮,只需指定列对象的 command
属性即可。我没有向列添加任何 <button>
元素,也没有创建 JavaScript 事件处理器。Kendo UI 通过网格小部件的现有功能为我生成了所有这些必要的标记。
大部分网格功能可以通过描述网格当前能力的属性来启用。每个属性都以 -able 结尾。这些属性是 editable
、filterable
、groupable
、navigatable
、pageable
、scrollable
、selectable
和 sortable
。我们已经看到了 filterable
和 sortable
,并且当使用时它们接受简单的真/假值。我们也看到了 editable
,但这个选项还有更多可以做的:
...
editable: {
confirmation: "Are you sure?", // text displayed to confirm a delete operation
destroy: true, // whether or not to delete item when button is clicked
mode: "popup", // options are "incell", "inline", and "popup"
template: "#= ... #", // template to use for pop-up editing
update: true // switch item to edit mode when clicked?
}
groupable
属性允许用户通过将列拖动到屏幕顶部来对列进行分组。groupable
选项还包括一个属性 groupable.messages.empty
,它将在网格的空分组区域中显示。如果您指定此 messages
属性,则假定 groupable: true
值,并且不需要指定。navigatable
属性在网格内打开或关闭键盘导航。以下是我们的网格定义底部在 groupable
和 navigatable
启用时的外观:
...
sortable: true,
filterable: true,
editable: "inline",
navigatable: true,
groupable: {
messages: {
empty: "Drag column header here for grouping"
}
}
使用这些选项渲染时的页面输出:
pageable
选项可以简单地设置为 true
/false
,就像其他几个选项一样,但如果您需要更精细的控制,它也允许这样做:
...
pageable: {
pageSize: 10,
previousNext: true, // show buttons navigating to first/last/next/previous
numeric: true, // show numeric portion of the pager in the Grid?
buttonCount: 10, // number of buttons to show in numeric pager
input: true, // create input element allowing user to navigate to page
pageSizes: [5,10,20], //array of page size choices for user
refresh: true, // show a refresh button in the Grid?
info: true, // show a label with current paging information in it
messages: {
display: "Detail Template – {1} of {2} items", // info text
empty: "No Records", // text to show when there are no records
page: "Page", // first part of text of input option
of: "of Detail Template", // last part of text of input option
itemsPerPage: "items per page", // text for selecting page size
first: "Go to first page", // text of first page button tooltip
previous: "Go to the previous page", // previous page tooltip
next: "Go to next page", // next page tooltip
last: "Go to the last page", // last page tooltip
refresh: "Refresh" // text of refresh button tooltip
}
}
我们为每页 10 个项目配置的示例代码将看起来像这样:
...
sortable: true,
filterable: true,
editable: "inline",
navigatable: true,
groupable: {
messages: {
empty: "Drag column header here for grouping"
}
},
pageable: {
pageSize: 10
}
使用这些选项生成的输出:
scrollable
属性配置网格内部是否可以有一个垂直滚动条,通常在您在页面上限制了网格的高度时指定。它可以设置为简单的布尔值 true/false
。
selectable
属性指示在网格内是否启用或禁用选择。它的可能值是 row
、cell
、multiple, row
和 multiple, cell
。以下是我们的示例网格在 selectable: "multiple, cell"
时的外观。
注意,我已经选择了部分行进行显示。
toolbar
属性为网格启用一个具有一组命令的工具栏,类似于列对象的命令属性。toolbar
对象数组中的每个工具栏都可以配置 name
、template
和 text
:
...
toolbar: [
"create",
{ name: "save", text: "Save This Record" },
{ name: "cancel", text: "Cancel Changes: }]
注意工具栏可以是一个简单的文本值,指示要执行哪个命令。您还可以指定包含所需配置数据的对象(如前面的截图所示)。请参考以下截图:
摘要
在本章中,我们涵盖了大量的基础知识,以便您能够正确地开始创建启用 Kendo UI 的网页。理解如何使用模板以及如何使用数据源对于在 Kendo UI 框架中做很多事情至关重要。在这些之后,网格是 Kendo UI 框架的一个基本组件,了解如何配置它将在构建需要向用户显示表格数据的页面时给您带来先机。
在下一章中,我们将学习关于自动完成小部件的内容。它允许您向输入文本框添加一个单词轮效果,以帮助用户输入可以从数据源中查找的信息。这是一个许多用户都会被吸引的工具,它将为您的网页添加很多功能,而无需在编写代码上花费太多精力。
第二章. 自动完成小部件及其用法
Kendo UI 中的自动完成小部件在用户输入时会在输入框上创建“单词轮”效果。单词轮是一种效果,当用户输入时,单词会出现在文本框下方,帮助建议可能的搜索词。你经常在像 Google 和 Bing 这样的搜索引擎上看到这种效果。这可以用来给用户一个他们可以选择的批准选项列表,或者它也可以帮助用户准确输入特定的关键词,因为项目的规范形式会直接出现在输入框下方供用户选择。如果用户只需要输入可能的长搜索词中的一个或两个字符,这也可以节省用户的时间。Kendo UI 中的自动完成小部件非常容易配置,并且几乎不需要你做任何工作就能将此功能带给你的网站用户。
自动完成小部件 – 基础
打开上一章中创建的 Visual Studio 项目,然后打开Controllers
文件夹中的KendoController.cs
类。让我们为我们的初始自动完成测试页面添加一个新的操作方法。
public ActionResult AutoCompletePage()
{
return View();
}
右键单击操作方法的名称,然后选择添加视图。现在,选择对话框中出现的默认值,这将带您进入网页,以便我们可以开始操作。
将自动完成绑定到本地源
由于我们正在引用上一章中创建的默认布局,因此我们不需要重新输入任何内容就可以在我们的页面标题中获取所有需要的 Kendo 和 jQuery 文件。
我们将首先通过 JavaScript 和本地数据绑定来演示如何使用自动完成小部件。我们需要一个输入元素、一个 JavaScript 数组和一些 jQuery。
<style>
#stateOrTerritory {
width:200px;
}
</style>
<h2>AutoCompletePage</h2>
<input type="text" name="stateOrTerritory" id="stateOrTerritory" />
<script type="text/javascript">
varstatesAndTerritories = ["Alabama",
"Alaska",
"American Samoa",
"Arizona",
"Arkansas",
...
"Washington",
"West Virginia",
"Wisconsin",
"Wyoming"];
$("#stateOrTerritory").kendoAutoComplete({
dataSource: statesAndTerritories,
filter: "startswith",
placeholder: "Choose state or territory...",
separator: ", "
});
</script>
我们可以使用美国和领土的列表来展示字母表,并且列表足够长,可以进行演示。我们到目前为止所做的一切就是为自动完成创建了一些 JavaScript 数据,然后使用 jQuery 和 Kendo UI 将其连接到页面顶部的输入元素。我们指定了我们想使用statesAndTerritories
JavaScript 数组作为我们的数据源,我们想要在输入元素中使用占位符文本,并且数组中的项由逗号分隔。这些属性在章节末尾有更详细的解释。运行它,你应该能在浏览器中看到一个带有一些看起来不错的占位符文本的输入框。在它里面输入一些字母,你会立即得到一些州和领土的建议。
将自动完成绑定到远程数据
现在我们已经看到了如何使用本地 JavaScript 数据来配置 AutoComplete 小部件,接下来让我们看看如何使用远程数据来实现。在 Visual Studio 项目中,将名为StateTerritory.cs
的新类添加到Models
文件夹中。将其结构设计为包含关于州和地区的相关数据,以便我们可以在我们的页面上使用它。
namespace LearningKendoUIWeb.Models
{
public class StateTerritory
{
public string Name { get; set; }
public bool IsState { get; set; }
public bool IsTerritory { get; set; }
public bool IsContiguous { get; set; }
}
}
现在打开SampleRepository.cs
类文件,并添加一些逻辑来创建我们的州和地区数据仓库。请注意,我故意将哥伦比亚特区既视为一个州又视为一个地区,以便于未来的示例。
public List<StateTerritory>GetStatesAndTerritories()
{
var stateTerritories = new List<StateTerritory>{
new StateTerritory{ Name = "Alabama", IsContiguous = true,
IsState = true, IsTerritory = false },
new StateTerritory{ Name = "Alaska", IsContiguous = false,
IsState = true, IsTerritory = false },
new StateTerritory{ Name = "American Samoa", IsContiguous = false,
IsState = false, IsTerritory = false },
new StateTerritory{ Name = "Arizona", IsContiguous = true,
IsState = true, IsTerritory = false },
new StateTerritory{ Name = "Arkansas", IsContiguous = true,
IsState = true, IsTerritory = false },
...
new StateTerritory{ Name = "Washington", IsContiguous = true,
IsState = true, IsTerritory = false },
new StateTerritory{ Name = "West Virginia", IsContiguous = true,
IsState = true, IsTerritory = false },
new StateTerritory{ Name = "Wisconsin", IsContiguous = true,
IsState = true, IsTerritory = false },
new StateTerritory{ Name = "Wyoming", IsContiguous = true,
IsState = true, IsTerritory = false }
};
return stateTerritories;
}
现在我们有一些可以在服务器端操作的数据,但我们仍然需要通过 HTTP 公开它。回到KendoController.cs
类文件,并添加一个新动作方法,就像你在这个代码块中看到的那样:
public JsonResult AutoCompleteData()
{
var repository = new SampleRepository();
var data = repository.GetStatesAndTerritories();
returnJson(data, JsonRequestBehavior.AllowGet);
}
这将暴露我们的州和地区集合,作为StateTerritory
对象的 JSON 数组。请记住设置JsonRequestBehavior.AllowGet
属性,否则这不会工作。现在我们可以修改我们的AutoCompletePage.cshtml
文件,使用传输属性来获取其数据。
$("#stateOrTerritory").kendoAutoComplete({
dataSource: {
transport: {
read: {
url: "/Kendo/AutoCompleteData/"
}
}
},
dataTextField: "Name",
filter: "startswith",
placeholder: "Choose state or territory...",
});
再次运行页面,并观察它从服务器获取数据。我们必须指定哪个字段包含数据文本字段,因为我们的 JSON 数据是结构为对象,而不是简单的数组。我们也不再需要分隔符属性。
使用模型通过 MVC 使用 AutoComplete
我们可以将这一步更进一步,将我们的代码转换为 Razor 语法与 MVC 一起使用。首先,创建一个控制器动作方法,从服务器返回数据。
public ActionResult AutoCompletePage()
{
var repository = new SampleRepository();
var data = repository.GetStatesAndTerritories();
return View(data);
}
接下来,打开AutoCompletePage.cshtml
文件,并在<h2>
标签之后删除所有内容。在文件顶部,我们需要添加一个声明,以便这个视图页面成为我们的新模型类StateTerritory.cs
的强类型。
@model IEnumerable<LearningKendoUIWeb.Models.StateTerritory>
现在添加这段代码,它利用 HTML 辅助类和 Kendo 扩展方法。
<h2>AutoCompletePage</h2>
@(Html.Kendo().AutoComplete()
.Name("statesAndTerritories")
.DataTextField("Name")
.BindTo(Model)
.Filter("startswith")
.Placeholder("Choose state or territory...")
)
识别出语法了吗?除了BindTo(Model)
语句外,这些方法名与我们在 JavaScript 中使用的属性名相同(当然,它们的首字母都是大写的)。BindTo(Model)
的调用是 MVC 控制器将数据传递到 MVC 视图的方式。在这种情况下,我们将视图强类型化为StateTerritory
对象的集合(IEnumerable
),在这里的代码中,我们告诉 Kendo 框架这个模型包含要在 AutoComplete 中显示的数据。这个模型中的数据在服务器创建页面时使用,并且只能通过视图页面中的 Razor 语法代码语句访问。
尽管我们刚刚通过 MVC 将 AutoComplete 连接到服务器,但我们使用的方法并不真正像是对远程数据的调用。实际上,它是通过将服务器端的所有模型数据保存到 AutoComplete 初始化的 JavaScript 中来使用本地数据。只要我们不尝试将如此多的数据嵌入到页面中以至于它加载缓慢,这并没有什么问题。实际上,在某些情况下,这可能是提高性能的好方法,但了解数据的位置以及页面如何访问它很重要。如果我们想让页面从 URL 请求数据,我们需要对我们的视图做一些修改。
通过 Ajax 使用 AutoComplete 与 MVC 结合
打开视图并修改 AutoComplete()
扩展方法调用,就像这个代码块一样。
<h2>AutoCompletePage</h2>
@(Html.Kendo().AutoComplete()
.Name("statesAndTerritories")
.Placeholder("Choose state or territory...")
.DataTextField("Name")
.Filter("startswith")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("AutoCompleteData", "Kendo");
})
.ServerFiltering(false);
})
)
我们已经移除了 BindTo(Model)
并用 DataSource()
调用替换,我们在这里使用 lambda 表达式来定义如何创建数据源。在这种情况下,我们已将其配置为使用之前配置的返回 JSON 数据的动作方法,并且服务器没有执行任何过滤。这实际上将我们的网页设置得与原始使用 transport
属性从服务器获取 JSON 数据的 JavaScript 页面相同。
向服务器发送数据
我们希望能够在服务器端过滤 AutoComplete 小部件的数据。我们可以在 transport
JavaScript 对象中的 data
属性中使用,或者我们可以继续使用我们的 MVC 示例,并在 DataSource
lambda 表达式中指定要发送的数据。比如说,如果我们想能够选择在 AutoComplete 小部件中显示哪些州和领地类型,我们可以通过在请求中发送一些数据来实现这一点,然后让服务器修改它发送回的数据。用以下更新后的代码替换 AutoCompletePage.cshtml
的内容。
<h2>AutoCompletePage</h2>
<label for="stateType">Choose whether to see States:</label>
<select id="stateType" name="stateType">
<option value="true">Show States</option>
<option value="false">Show Only Territories</option>
</select>
<br />
@(Html.Kendo().AutoComplete()
.Name("statesAndTerritories")
.Placeholder("Choose state or territory...")
.DataTextField("Name")
.Filter("startswith")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("AutoCompleteData", "Kendo")
.Data("onAdditionalData");
})
.ServerFiltering(false);
})
)
<script type="text/javascript">
var autocomplete = $("#statesAndTerritories").data("kendoAutoComplete");
functiononAdditionalData() {
return {
showStates: $("#stateType").val()
}
}
</script>
注意 lambda 表达式中的 Data("onAdditionalData")
调用和同名的新的 JavaScript 方法 onAdditionalData()
。当读取 AutoComplete 的数据源时,它将触发这个 JavaScript 事件,并将带有 showStates
参数的结果发送到服务器。为了将此数据接收进你的动作方法,你需要添加一个具有匹配名称的参数。
public JsonResult AutoCompleteData(bool showStates = true)
{
// setting showStates = true means that it is an optional parameter
// with the default value of true.
var repository = new SampleRepository();
var data = repository.GetStatesAndTerritories();
if (!showStates)
{
data = data.Where(s =>s.IsState == false).ToList();
}
return Json(data, JsonRequestBehavior.AllowGet);
}
现在,当 AutoComplete 代码将其 showStates
参数作为其网络请求的一部分发送时,控制器将使用该值来确定是否过滤它发送回的数据。
使用模板自定义 AutoComplete
Kendo 模板可以用来自定义 AutoComplete 中项目的显示外观。这甚至可以变得相当复杂,包括图片和特殊样式。这里有一个简单的例子。将 AutoCompletePage.cshtml
页面的 Razor 部分更新为如下所示:
@{
var template = "#= Name # - #= IsState #";
}
@(Html.Kendo().AutoComplete()
.Name("statesAndTerritories")
.Placeholder("Choose state or territory...")
.DataTextField("Name")
.Filter("startswith")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("AutoCompleteData", "Kendo")
.Data("onAdditionalData");
})
.ServerFiltering(false);
})
.Template(template)
)
在这里,我们添加了一个名为template
的变量,它包含我们的 Kendo 模板定义。然后我们在AutoComplete()
设置代码中引用了它。运行页面并查看结果。
配置所有自动完成属性
自动完成小部件在初始化期间可以设置几个不同的属性来定制其行为。以下是一个结构化代码示例,展示了自动完成小部件上可用的功能。
$("autocomplete").kendoAutoComplete({
dataSource: dataSource, // see chapter 1
animation: {
close: {
effects: "fadeOut",
duration: 300,
hide: true,
show: false
},
open: {
effects: "fadeIn",
duration: 300,
show: true
}
},
dataTextField: "Name", // name of field in data source to display
delay: 500, // milliseconds before auto complete activates
enable: true, // set "false" to disable
filter: "contains", // type of filtration, passed to remote source
height: 200, // height of drop-down list
highlightFirst: true, // highlight first item in list?
ignoreCase: true,
minLength: 1, // minimum characters before activating drop-down list
placeHolder: "Enter value...", // placeholder text
separator: ", ", // separator for completion of search terms.
//allows for multiple search terms by using comma or
// other delimiter
suggest: false, // auto-type rest of search term?
template: template // see chapter 1
}
钩入自动完成小部件事件
自动完成小部件在执行页面上的操作时将触发几个不同的事件。您可以在自动完成小部件初始化后绑定它们,如下所示:
varautoComplete = $("#autoComplete").data("kendoAutoComplete");
$("#autoComplete").data("kendoAutoComplete").bind("change", function(e) {
// handle event
});
或者,您可以在自动完成小部件本身的属性中定义它们,如下所示:
$("#autoComplete").kendoAutoComplete({
close: function(e) {
// handle event
}
});
在任何情况下,这都是您可以附加您自己的代码的事件列表。
更改
当自动完成小部件中的选择更改时,将触发change
事件。您可以在初始化后绑定事件。
关闭
当从自动完成小部件关闭下拉列表时,将触发close
事件。
打开
open
事件在每次从自动完成小部件打开下拉列表时都会触发。
选择
当从自动完成小部件中选择任何元素时,将触发select
事件。它将e.item
参数传递给处理它的函数,以便您可以访问所选择的项。
使用 API 自动完成方法
要从 JavaScript 代码内部访问自动完成小部件,您可以通过以下方式通过 jQuery 调用 API:
var autocomplete = $("autocomplete").data("kendoAutoComplete");
一旦您有了自动完成小部件的变量引用,您就可以通过代码以您希望的方式调用 API 方法并对其进行操作。这些是自动完成小部件上可用的 API 方法。
关闭
close()
方法关闭自动完成小部件上的下拉列表。
// get a reference to the autocomplete widget
var autocomplete = $("autocomplete").data("kendoAutoComplete");
autocomplete.close();
数据项
dataItem()
方法返回指定索引处的数据记录。此dataItem
对象将是自动完成小部件数据源在指定索引处的特定对象。在我们的示例中,它将是一个特定的stateOrTerritory
对象。
var autocomplete = $("#autocomplete").data("kendoAutoComplete");
// get the dataItem corresponding to the passed index.
var dataItem = autocomplete.dataItem(1);
销毁
destroy()
方法准备自动完成小部件以安全地从 DOM 中移除。它断开所有事件处理程序并删除数据属性。它实际上并不执行从 DOM 中移除的最后一步;这是您必须自己编写的操作。
var autocomplete = $("#autocomplete").data("kendoAutoComplete");
// detach events
autocomplete.destroy();
启用
enable()
方法切换自动完成小部件的开启和关闭状态。
// get a reference to the autocomplete widget
var autocomplete = $("autocomplete").data("kendoAutoComplete");
// disables the autocomplete
autocomplete.enable(false);
// enables the autocomplete
autocomplete.enable(true);
刷新
refresh()
方法重新渲染自动完成小部件下拉列表中的项。
// get a reference to the Kendo UI AutoComplete
var autocomplete = $("autocomplete").data("kendoAutoComplete");
// re-render the items in drop-down list.
autocomplete.refresh();
搜索
search()
方法使用提供的参数过滤自动完成小部件的数据源,然后重新绑定下拉列表。
// get a reference to the autocomplete widget
var autocomplete = $("autocomplete").data("kendoAutoComplete");
// Searches for item which has "Inception" in the name.
autocomplete.search("Inception");
选择
select()
方法从自动完成小部件中选择下拉列表项,并设置自动完成输入框的文本。
// get a reference to the autocomplete widget
var autocomplete = $("autocomplete").data("kendoAutoComplete");
// selects by jQuery object
autocomplete.select(autocomplete.ul.children().eq(0));
建议
suggest()
方法将建议强制应用到自动完成小部件的文本上。
// note that this suggest is not the same as the configuration method
// suggest which enables/disables auto suggesting for the AutoComplete
//
// get a reference to the Kendo UI AutoComplete
varautoComplete = $("#autoComplete").data("kendoAutoComplete");
// force a suggestion to the item with the name "Inception"
autoComplete.suggest("Inception");
价值
value()
方法获取或设置自动完成小部件的值。
// get a reference to the autocomplete widget
var autocomplete = $("autocomplete").data("kendoAutoComplete");
// get the text of the autocomplete.
var value = autocomplete.value();
摘要
自动完成小部件是帮助网站用户的一个很好的方式。任何输入框的值可以被预测的情况,例如当它们来自一组特定的值或搜索常用术语时,自动完成小部件将立即使您的网站更容易使用,并且用户肯定会注意到并欣赏它。不仅如此,配置非常简单,您几乎不需要费力就可以启用它。
在下一章中,我们将学习如何使用日历小部件。这个小部件将允许您在网页中显示和配置交互式日历控件,以便用户可以轻松选择日期。它还将为您提供一种将数据绑定到日历上的方法,以显示重要日期。Telerik Kendo UI 日历小部件将帮助将复杂的 JavaScript 日历转换为开发出色网页的简单易用工具。
第三章. 使用和自定义日历
日历长期以来一直是需要一些巧妙 JavaScript 的网页功能。HTML5 正在努力使这一切变得更加简单,但浏览器的支持仍然不统一。这就是 Kendo UI 成为完美解决方案的地方,因为它是一个结合 HTML5 和 JavaScript 的框架,使用最新的标准创建跨浏览器的统一性。像往常一样,Kendo UI 解决方案的实施非常简单。
日历小部件 – 基础
Kendo UI 日历小部件将一个简单的 HTML 元素,例如div
,转换成一个显示日历的专用 HTML 表格。它还为此表格连接 JavaScript 功能,以支持所有日历小部件事件和方法。要查看此小部件的最简单实现,请在 Kendo 控制器中创建一个新的操作方法,以便我们有一个“calendar”的 URL:
public ActionResult Calendar()
{
return View();
}
然后为这个操作方法添加一个视图,并设置一个空的div
来容纳 Kendo 日历小部件:
@{
ViewBag.Title = "Calendar";
}
<h2>Calendar</h2>
<div id="calendar">
</div>
<script type="text/javascript">
$("#calendar").kendoCalendar();
</script>
考虑到我们编写的代码如此之少,输出效果令人惊叹:
在日历上点击并观察它已经具有多少功能。日历顶部的箭头可以向前或向后导航一个月。日历顶部的文本(如前一个截图中的2012 年 10 月所示)可以导航到更广泛的日期级别,这使得选择不同的年份或十年变得容易。日历底部的日期是一个超链接,可以直接导航到当前日期。随着我们在本章后面添加功能,我们可以使日历做得更多。
配置日历小部件
由于日历小部件只有少数属性,让我们先检查它们,然后再转到使用它们的示例。日历小部件有两种不同类型的属性:
-
数据/模板属性:这些属性配置了日历小部件背后的数据
-
显示/格式化属性:这些属性配置了日历在页面上的渲染方式以及数据的格式化方式
这里以代码格式列出这些属性。将此代码添加到页面并运行它:
$("#calendar").kendoCalendar({
culture: 'en-US', // specifies the culture
depth: 'month', // specifies navigation depth
//(century/decade/month/year)
max: new Date(2012,11,31), // latest date calendar can show
min: new Date(1980, 0, 1), // oldest date calendar can show
start: 'year', // specifies the start view (century/decade/month/year)
value: new Date(2012,9,25), // initially selected date
format: 'yyyy/MM/dd' // format string used when the value() of this
//calendar is requested
});
当日历配置如上所述时,它最初通过显示当前选中年份内可用的月份来渲染(start: 'year'
)。由于我们已配置它允许进入每个月份的导航深度(depth: 'month'
),我们可以点击一个月份,然后看到该月份及其所有可用日期:
注意
即使当前视图是“年”,今天的日期仍然在日历页脚中可见。
谈到页脚,让我们看看日历提供的哪些数据/模板属性。这里的主要属性有三个:data
、month
和footer
,它们是自定义日历小部件的主要方式。为了演示如何自定义日历中特定日期的简单示例,将以下代码添加到页面中并运行它:
<h2>Calendar</h2>
<div id="calendar">
</div>
<style type="text/css">
.specialDay {
color: white;
background-color: orange;
border:1px solid black;
}
</style>
<script type="text/x-kendo-template" id="redDays">
# if ($.inArray(+data.date, data.dates) != -1) { #
<div class="specialDay">#= data.value #</div>
# } else { #
#= data.value #
# } #
</script>
<script type="text/javascript">
var datesArray = [+new Date(2012, 5, 15), +new Date(2012, 5, 21)];
$("#calendar").kendoCalendar({
culture: 'en-US', // specifies the culture
depth: 'month', // specifies navigation depth
max: new Date(2012, 5,31), // latest date calendar can show
min: new Date(2012, 5, 1), // oldest date calendar can show
start: 'month', // specifies the start view
value: new Date(2012,5,11), // initially selected date
format: 'yyyy/MM/dd', // format string used to format the date values
dates: datesArray,
month: {
content: $("#redDays").html(),
empty: "X"
},
footer: "Today is #= kendo.toString(data, 'd') #"
});
</script>
让我们一起逐步分析这段代码。首先,我们有一个特殊的样式指令,用于显示特殊日期的方式。在这种情况下,橙色背景上的白色文本和实线黑色边框。我们还指定了一个 Kendo UI 模板块和 JavaScript,以确定正在渲染的日期是否是我们特殊日期之一。如果是特殊日期之一,则我们希望将其应用自定义样式;否则,按常规渲染。
<style type="text/css">
.specialDay {
color: white;
background-color: orange;
border:1px solid black;
}
</style>
<script type="text/x-kendo-template" id="redDays">
# if ($.inArray(+data.date, data.dates) != -1) { #
<div class="specialDay">#= data.value #</div>
# } else { #
#= data.value #
# } #
</script>
接下来,我们定义日历小部件的实际配置。在这里,month
属性和dates
属性之间的关系变得明显:dates
属性提供了month
属性用来在日历上渲染日期所需的数据。在我们定义的模板中,我们检查当前正在渲染的日期是否包含在dates
数组中,然后使用data.value
来渲染当前正在执行的日期编号。注意,我们还将在dateArray
中的日期前面加上加号+
,以强制它们成为我们可以轻松与$.inArray()
比较的数字日期。这不是每个情况下的要求,但适用于这个示例。
<script type="text/javascript">
var datesArray = [+new Date(2012, 5, 15), +new Date(2012, 5, 21)];
$("#calendar").kendoCalendar({
culture: 'en-US', // specifies the culture
depth: 'month', // specifies navigation depth
max: new Date(2012, 5,31), // latest date calendar can show
min: new Date(2012, 5, 1), // oldest date calendar can show
start: 'month', // specifies the start view
value: new Date(2012,5,11), // initially selected date
format: 'yyyy/MM/dd', // format string used to format the date values
dates: datesArray,
month: {
content: $("#redDays").html(),
empty: "X"
},
footer: "Today is #= kendo.toString(data, 'd') #"
});
</script>
其他需要注意的事项是,有一个名为footer
的新属性,用于渲染日历页脚的模板,它可以通过传递给它的data
属性访问今天的日期。此外,请注意,month
对象还有一个名为empty
的属性,用于渲染位于min
或max
属性值范围之外的日期。
以这种方式设置日历后,在浏览器中的外观如下:
注意
注意通过dateArray
提供的日期的特殊显示、范围之外的日期以及页脚中使用的新的文本。
使用 MVC 的日历小部件
日历小部件也可以通过 ASP.NET MVC 扩展方法进行配置。为了模仿我们刚刚创建的日历,你可以用以下代码替换你的视图内容:
<h2>Calendar</h2>
<style type="text/css">
.specialDay {
color: white;
background-color: orange;
border:1px solid black;
}
</style>
<script type="text/x-kendo-template" id="redDays">
# if ($.inArray(+data.date, data.dates) != -1) { #
<div class="specialDay">#= data.value #</div>
# } else { #
#= data.value #
# } #
</script>
<script type="text/javascript">
var datesArray = [+new Date(2012, 5, 15), +new Date(2012, 5, 21)];
</script>
@(Html.Kendo().Calendar()
.Name("mvcCalendar")
.Depth(CalendarView.Month)
.Max(new DateTime(2012, 6, 30))
.Min(new DateTime(2012, 6, 1))
.Start(CalendarView.Month)
.Value(new DateTime(2012, 6, 11))
.Format("yyyy/MM/dd")
.MonthTemplate("# if ($.inArray(+data.date, datesArray) != -1) { #" +
"<div class='specialDay'>#= data.value #</div>" +
"# } else { #" +
"#= data.value #" +
"# } #")
.Footer("Today is #= kendo.toString(data, 'd') #")
)
使用此新代码的输出如下:
很相似,不是吗?注意,MVC 扩展隐藏了max
和min
以下的日期,并且在month
上没有提供空属性。还有一些其他独特的事情需要注意。首先,请注意我们仍然在视图中通过 JavaScript 使用日期数组。这是因为month
模板是在 JavaScript 中运行的,而不是通过 MVC 扩展,并且需要在客户端访问这些数据。由于这个原因,以及 MVC 扩展不提供dates
属性的事实,我们必须将模板从使用data.dates
更改为实际的 JavaScript 数组名称——datesArray
。在这个例子中,我直接将模板代码输入到 MVC 扩展方法中,但还有一个名为MonthTemplateId()
的方法,你可以传递页面上已经存在的模板的 HTML id
。
此外,请记住始终在每个 Kendo MVC 扩展对象上调用.Name()
方法;这是代码正常工作的必要条件。这就是 MVC 扩展方法如何为渲染的 HTML 输出分配唯一的name
和id
属性,以及如何将所有 JavaScript 方法和事件正确地连接到网页浏览器中。如果你不包括.Name()
方法,当你尝试运行页面时,你也会看到运行时错误。
日历小部件上的可用方法
日历小部件公开了几个可以在页面上与之交互的方法。这些方法可以通过更改其属性或实时触发特定功能来配置小部件。以下是针对 Kendo UI 日历小部件的特定可用方法的代码形式:
var calendar = $("calendarId").data("kendoCalendar");
// Set a new max date
calendar.max(new Date(2013,11,31));
// Retrieve the current max date
var lastDay = calendar.max();
// Set a new min date
calendar.min(new Date(2011, 11, 31);
// Retrieve the current min date
var oldestDay = calendar.min();
// Navigate to a specific date using a specific view
calendar.navigate(new Date(2012,2,5), "month");
// Navigate down to a lower view (i.e. goes from "year" to "month")
calendar.navigateDown(new Date(2012,6,7)); // date is optional
// Navigate to the future
calendar.navigateToFuture();
// Navigate to the past
calendar.navigateToPast();
// Navigate up to a higher view (i.e. goes from "year" to "decade")
calendar.navigateUp("year");
// Set a new value (selected date) for the calendar
calendar.value(new Date(2012,4,7));
// Get the current value (selected date) of the calendar
var selectedDate = calendar.value();
让我们以其中的一些为例,看看它们在我们页面上的实际效果。修改我们为 MVC 视图创建的代码如下:
<h2>Calendar</h2>
<style type="text/css">
.specialDay {
color: white;
background-color: orange;
border:1px solid black;
}
</style>
<script type="text/x-kendo-template" id="redDays">
# if ($.inArray(+data.date, data.dates) != -1) { #
<div class="specialDay">#= data.value #</div>
# } else { #
#= data.value #
# } #
</script>
<script type="text/javascript">
var datesArray = [+new Date(2012, 5, 15), +new Date(2012, 5, 21)];
</script>
@(Html.Kendo().Calendar()
.Name("mvcCalendar")
.Depth(CalendarView.Month).Start(CalendarView.Month)
.Value(new DateTime(2012, 6, 11))
.Format("yyyy/MM/dd")
.MonthTemplate("# if ($.inArray(+data.date, datesArray) != -1) { #" +
"<div class='specialDay'>#= data.value #</div>" +
"# } else { #" +
"#= data.value #" +
"# } #")
.Footer("Today is #= kendo.toString(data, 'd') #")
)
<br />
<button type="button" id="navigateUp">Navigate Up</button><br />
<button type="button" id="navigateDown">Navigate Down</button><br />
<button type="button" id="showValue">Pop-Up Value</button>
<script type="text/javascript">
$("#navigateUp").click(function () {
var calendar = $("#mvcCalendar").data("kendoCalendar");
calendar.navigateUp();
});
$("#navigateDown").click(function () {
var calendar = $("#mvcCalendar").data("kendoCalendar");
calendar.navigateDown(calendar.value());
});
$("#showValue").click(function () {
var calendar = $("#mvcCalendar").data("kendoCalendar");
alert(calendar.value());
});
</script>
为了将日历小部件作为 JavaScript 对象使用,我们必须在包含我们创建的日历的页面元素上调用.data()
函数。点击页面上的按钮并观察它们的行为。这应该能给你一些关于日历小部件能提供什么以及如何将你自己的交互式代码插入日历以改善用户体验的思路。
日历小部件触发的事件
Kendo UI 日历小部件有两个事件——change
和navigate
。这些事件在它们命名的动作发生后触发。当选定的日期改变时,Change
事件被触发,当日历被导航时(例如,当月份改变或视图从“月份”移动到“年份”时),navigate
事件被触发。
如果你想让日历只在用户在页面上选择某个输入框时出现,并将它的值放入该输入元素中,你会怎么做?你可以尝试这样做。修改我们正在工作的页面的最终script
块,使其看起来像以下示例:
<script type="text/javascript">
$(function () {
$("#mvcCalendar").hide();
});
$(document).ready(function () {
$("#mvcCalendar").data("kendoCalendar").bind("change", function (e) {
var date = $("#mvcCalendar").data("kendoCalendar").value();
$("#showTheCalendar").val(kendo.toString(date, 'd'));
});
});
$("#showTheCalendar").focusin(function () {
$("#mvcCalendar").slideDown();
});
$("#nameInput").focusin(function () {
$("#mvcCalendar").slideUp();
});
$("#ageInput").focusin(function () {
$("#mvcCalendar").slideUp();
});
$("#navigateUp").click(function () {
var calendar = $("#mvcCalendar").data("kendoCalendar");
calendar.navigateUp();
});
$("#navigateDown").click(function () {
var calendar = $("#mvcCalendar").data("kendoCalendar");
calendar.navigateDown(calendar.value());
});
$("#showValue").click(function () {
var calendar = $("#mvcCalendar").data("kendoCalendar");
alert(calendar.value());
});
</script>
在这里,我们有一些由简单的 jQuery 和 jQuery UI 连接的事件,它们可以显示或隐藏日历,并在选择时获取其值。日历的 change
事件用于确定何时将新的日期值放入页面的输入元素中。这就是页面首次渲染时的样子。
日历在用户点击第一个文本框之前是隐藏的。一旦发生这种情况,我们连接的事件就会使日历出现,以便用户可以选择页面的适当日期。
摘要
Kendo UI 日历小部件易于配置,并在您的页面上提供了一个丰富的元素,可以使处理日期变得简单得多。它可以由 JavaScript 或 MVC 扩展进行配置,并使用 Kendo 模板进行高度可定制的格式化和显示。我仅展示了使用模板和事件可以完成的基本示例;您可以使用这些示例来创建一些非常有用的交互式内容。
在下一章中,我们将学习 Kendo UI 框架中最强大的功能之一,即模型-视图-视图模型(MVVM)框架。这个框架允许您通过简单的 HTML 属性将数据和功能绑定到您的页面上,并启用对数据的实时更改,或对服务器进行更改,同时为用户提供即时反馈。MVVM 框架是一个您希望在所有页面上都想要使用的强大工具。
第四章:Kendo MVVM 框架
自从 JavaScript 的诞生以及丰富 MVVM 框架的出现以来,JavaScript 开发已经走了很长的路,这无疑是这一演变的美好证明。这些框架允许开发者将代码中的责任分离,以更好地处理复杂性。它们还提供了一个简洁的语法,使得 MVVM 框架本身可以处理将动态数据绑定到网页上的繁琐工作。如果你之前从未使用过 JavaScript MVVM 框架,那么 Kendo MVVM 框架将为你带来一场盛宴。
理解 MVVM - 基础
MVVM 代表模型(M)、视图(V)和视图模型(VM)。它是与系统架构相关的设计模式家族的一部分,将责任分离到不同的单元中。一些其他相关的模式是模型-视图-控制器(MVC)和模型-视图-表示器(MVP)。它们在框架的每个部分负责的内容上有所不同,但它们都试图通过相同的设计原则来管理复杂性。在这里不深入不必要的细节,只需说这些模式对于开发可靠和可重用的代码是好的,如果你正确实现了它们,你无疑会从中受益。幸运的是,好的 JavaScript MVVM 框架通过为你连接组件,让你专注于代码而不是“管道”工作,使得这变得容易。
在 Kendo UI 的 JavaScript MVVM 模式中,你需要为想要显示和操作的数据(模型)、结构化整个网页的 HTML 标记(视图)以及处理用户输入、响应事件并将静态标记转换为动态元素的 JavaScript 代码(视图模型)创建定义。另一种说法是,你将拥有数据(模型)、展示(视图)和逻辑(视图模型)。
在实践中,模型是 MVVM 模式中最不明确的部分,甚至不一定在实现中作为一个独特的实体存在。视图模型可以直接在其内部包含模型数据属性,而不是作为单独的单元引用它们,从而承担模型和视图模型的双重角色。这是可以接受的,并且在 ASP.NET MVC 中也可以看到,当视图使用ViewBag
或ViewData
集合而不是引用强类型模型类时。如果模型没有像视图模型和视图那样定义得很好,请不要让它困扰你。任何模式的实现都应过滤到对您的应用程序真正有意义的内容。
简单的数据绑定
作为入门示例,考虑您有一个需要显示数据表的网页,并且还提供用户通过单击特定的单行或元素与该数据交互的能力。数据是动态的,因此您事先不知道将显示多少条记录。此外,任何更改都应该立即反映在页面上,而不是等待从服务器完全刷新整个页面。您如何实现这一点?
一种传统的方法是使用可以动态从数据源创建表格并能够连接一些 JavaScript 交互性的特殊服务器端控件。这种方法的问题通常是需要服务器和浏览器之间进行一些复杂的额外通信,无论是通过“视图状态”,隐藏字段,还是长而丑陋的查询字符串。此外,这些特殊控件生成的输出通常很难进行定制或以重要方式进行操作,这减少了您网站外观和行为的选择。另一个选择是创建特殊的 JavaScript 函数,以异步从端点检索数据,在表格内生成 HTML 标记,然后为按钮和链接连接事件。这是一个好的解决方案,但需要大量的编码和复杂性,这意味着调试和精炼可能需要更长的时间。这也可能超出了某些开发者没有重大研究的能力范围。第三个选项,通过 JavaScript MVVM 如 Kendo UI 提供,在这两种位置之间取得平衡,通过减少 JavaScript 的复杂性,但仍然在页面内提供强大且简单的数据绑定功能。
创建视图
这是一个简单的 HTML 页面,展示视图是如何基本工作的:
<!DOCTYPE html>
<html >
<head>
<title>MVVM Demo 1</title>
<script src="img/jquery.js"></script>
<script src="img/kendo.all.js"></script>
<link href="/Content/kendo/kendo.common.css" rel="stylesheet" />
<link href="/Content/kendo/kendo.default.css" rel="stylesheet" />
<style type="text/css">
th {
width: 135px;
}
</style>
</head>
<body>
<table>
<caption>People Data</caption>
<thead>
<tr>
<th>Name</th>
<th>Hair Color</th>
<th>Favorite Food</th>
</tr>
</thead>
<tbody data-template="row-template"
data-bind="source: people"></tbody>
</table>
</body>
</html>
这里有一个简单的table
元素,包含三个列,但不是body
包含任何tr
元素,而是有一些特殊的 HTML5 data-*
属性,表明这里正在进行一些特殊操作。这些data-*
属性本身并不做任何事情,但 Kendo UI 会读取它们(如下所示),并解释它们的值,以便将视图与视图模型链接起来。data-bind
属性指示 Kendo UI,这个元素应该绑定到一个名为people
的对象集合。
data-template
属性告诉 Kendo UI,应该使用 Kendo UI 模板格式化people
对象。以下是模板的代码:
<script id="row-template" type="text/x-kendo-template">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: hairColor"></td>
<td data-bind="text: favoriteFood"></td>
</tr>
</script>
这是一个简单的模板,为表格中的每一行定义了一个tr
结构。td
元素上也有data-bind
属性,这样 Kendo UI 就知道要插入某个属性的值作为 HTML 元素的“文本”,在这种情况下意味着将值放置在<td>
和</td>
之间作为页面上简单的文本。
创建模型和视图模型
为了建立这个连接,我们需要一个执行数据绑定的视图模型。以下是这个视图的视图模型代码:
<script type="text/javascript">
var viewModel = kendo.observable({
people: [
{name: "John", hairColor: "Blonde", favoriteFood: "Burger"},
{name: "Bryan", hairColor: "Brown", favoriteFood: "Steak"},
{name: "Jennifer", hairColor: "Brown", favoriteFood: "Salad"}
]
});
kendo.bind($("body"), viewModel);
</script>
通过调用 kendo.observable()
来声明一个 Kendo UI 视图模型,这会创建一个 可观察对象,该对象用于视图中的数据绑定。可观察对象是一个特殊对象,它将一个普通的 JavaScript 变量包装起来,并在该变量的值发生变化时触发事件。这些事件会通知 MVVM 框架更新任何使用该变量值的绑定数据,以便它们可以立即更新并反映变化。这些数据绑定也是双向的,因此如果绑定到可观察对象变量的字段发生变化,绑定到该字段的变量也会实时更改。
在这个例子中,我创建了一个名为 people
的数组,其中包含三个具有关于一些人的属性的对象。这个数组在这个例子中充当模型,因为它包含了数据和数据的结构定义。在代码示例的末尾,你可以看到调用 kendo.bind($("body"), viewModel)
,这是 Kendo UI 实际执行 MVVM 连接的方式。我传递了一个 jQuery 选择器作为 body
标签的第一个参数,因为这个 viewModel
对象适用于我的整个 HTML 页面,而不仅仅是其中的一部分。
将所有内容组合起来,以下是这个简化示例的完整源代码:
<!DOCTYPE html>
<html >
<head>
<title>MVVM Demo 1</title>
<scriptsrc="img/jquery.js"></script>
<scriptsrc="img/kendo.all.js"></script>
<link href="/Content/kendo/kendo.common.css" rel="stylesheet" />
<link href="/Content/kendo/kendo.default.css" rel="stylesheet" />
<style type="text/css">
th {
width: 135px;
}
</style>
</head>
<body>
<table>
<caption>People Data</caption>
<thead>
<tr>
<th>Name</th>
<th>Hair Color</th>
<th>Favorite Food</th>
</tr>
</thead>
<tbody data-template="row-template"
data-bind="source: people"></tbody>
</table>
<script id="row-template" type="text/x-kendo-template">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: hairColor"></td>
<td data-bind="text: favoriteFood"></td>
</tr>
</script>
<script type="text/javascript">
var viewModel = kendo.observable({
people: [
{name: "John", hairColor: "Blonde", favoriteFood: "Burger"},
{name: "Bryan", hairColor: "Brown", favoriteFood: "Steak"},
{ name: "Jennifer", hairColor: "Brown", favoriteFood: "Salad" }
]
});
kendo.bind($("body"), viewModel);
</script>
</body>
</html>
这里是页面动作的截图。注意 JavaScript people
数组中的数据是如何自动填充到表格中的:
尽管这个例子包含模型、视图和视图模型,但所有三个单元都出现在同一个 HTML 文件中。当然,您可以将 JavaScript 分离到其他文件中,但将它们像这样放在一起也是可以接受的。希望您已经看到了这个 MVVM 框架能为您做什么。
可观察数据绑定
使用声明性属性将数据绑定到您的 HTML 网页(视图)中是非常好且非常有用的,但 MVVM 框架还提供了一些更重要的功能,我们在上一个示例中没有看到。MVVM 框架不仅将数据附加到视图并保持不变,而且还维护了视图模型所有属性的运行副本,并实时更新这些属性的引用。这就是为什么视图模型是用名为 "observable" 的函数创建的原因。内部属性是可观察的,它们会向上报告变化,以便数据绑定的字段始终反映最新的数据。让我们看看一些示例。
动态添加数据
在我们刚刚看到的示例的基础上,在 HTML 页面中的表格下方添加这条水平线和表单:
<hr />
<form>
<header>Add a Person</header>
<input type="text" name="personName" placeholder="Name"
data-bind="value: personName" /><br />
<input type="text" name="personHairColor" placeholder="Hair Color"
data-bind="value: personHairColor" /><br />
<input type="text" name="personFavFood" placeholder="Favorite Food"
data-bind="value: personFavFood" /><br />
<button type="button" data-bind="click: addPerson">Add</button>
</form>
这在页面上添加了一个表单,以便用户可以输入应出现在表格中的新人员数据。注意,我们添加了一些data-bind
属性,但这次我们绑定的是输入字段的value
而不是text
。还要注意,我们在表单底部的button
上添加了一个data-bind
属性,将那个button
的click
事件与视图模型内部的函数绑定。通过将click
事件绑定到addPerson
JavaScript 方法,每次点击这个按钮时,addPerson
方法都会被触发。
这些绑定始终将那些输入字段的值与视图模型对象链接起来。如果其中一个输入字段的值发生变化,例如当用户在框中输入某些内容时,视图模型对象会立即看到这个变化,并更新其属性以匹配;它还会更新任何绑定到该属性值的页面区域,以便它们与新的数据匹配。
按钮的绑定是特殊的,因为它允许视图模型对象将自身的事件处理器附加到该元素的点击事件上。将事件处理器绑定到事件本身并不是什么特别的事情,但通过这种方式(通过data-bind
属性)进行绑定是很重要的,这样页面内的特定运行视图模型实例就能将其中的一个函数附加到该事件上,使得事件处理器内部的代码能够访问这个特定视图模型的数据属性和值。这还允许将一个非常具体的上下文传递给事件,否则将很难访问。
下面是我在视图模型中添加到people
数组下面的代码。在这个例子中,我们拥有的前三个属性构成了模型。它们包含被观察并绑定到页面其余部分的数据:
personName: "", // Model property
personHairColor: "", // Model property
personFavFood: "", // Model property
addPerson: function () {
this.get("people").push({
name: this.get("personName"),
hairColor: this.get("personHairColor"),
favoriteFood: this.get("personFavFood")
});
this.set("personName", "");
this.set("personHairColor", "");
this.set("personFavFood", "");
}
你看到的第一个几个属性是我们上面在输入表单中绑定的相同属性。它们以空值开始,因为当页面首次加载时,表单不应该有任何值。在视图模型内部声明这些空属性仍然很重要,以便在它们发生变化时跟踪它们的值。
数据属性之后的函数addPerson
是我们绑定到输入表单按钮点击事件的函数。在这个函数中,我们正在访问people
数组,并根据用户在表单字段中提供的信息向其中添加一条新记录。请注意,我们必须使用this.get()
和this.set()
函数来访问视图模型内部的数据。这很重要,因为在这个视图模型中的属性是特殊的可观察属性,直接访问它们的值可能不会得到你预期的结果。
您应该注意到的最重要的事情是addPerson
函数与页面上的数据通过 View-Model 属性进行交互。它没有使用 jQuery、document.querySelector
或任何其他 DOM 交互来读取元素的值!由于我们在输入元素的值上声明了data-bind
属性到我们的 View-Model 属性,我们可以通过访问 View-Model 本身始终从这些元素中获取值。这些值始终被跟踪。这允许我们在addPerson
函数和 HTML 页面中检索并更改这些 View-Model 属性,HTML 页面将立即显示这些更改。通过在属性上调用this.set()
并将它们的值更改为空字符串,HTML 页面将清除用户刚刚输入并添加到表格中的值。再一次,我们更改 View-Model 属性而不需要我们自己访问 HTML。
这里是这个示例的完整源代码:
<!DOCTYPE html>
<html >
<head>
<title>MVVM Demo 2</title>
<scriptsrc="img/jquery.js"></script>
<scriptsrc="img/kendo.all.js"></script>
<link href="/Content/kendo/kendo.common.css" rel="stylesheet" />
<link href="/Content/kendo/kendo.default.css" rel="stylesheet" />
<style type="text/css">
th {
width: 135px;
}
</style>
</head>
<body>
<table>
<caption>People Data</caption>
<thead>
<tr>
<th>Name</th>
<th>Hair Color</th>
<th>Favorite Food</th>
</tr>
</thead>
<tbody data-template="row-template" data-bind="source: people"></tbody>
</table>
<hr />
<form>
<header>Add a Person</header>
<input type="text" name="personName" placeholder="Name" data-bind="value: personName" /><br />
<input type="text" name="personHairColor" placeholder="Hair Color" data-bind="value: personHairColor" /><br />
<input type="text" name="personFavFood" placeholder="Favorite Food" data-bind="value: personFavFood" /><br />
<button type="button" data-bind="click: addPerson">Add</button>
</form>
<script id="row-template" type="text/x-kendo-template">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: hairColor"></td>
<td data-bind="text: favoriteFood"></td>
</tr>
</script>
<script type="text/javascript">
var viewModel = kendo.observable({
people: [
{name: "John", hairColor: "Blonde", favoriteFood: "Burger"},
{name: "Bryan", hairColor: "Brown", favoriteFood: "Steak"},
{name: "Jennifer", hairColor: "Brown", favoriteFood: "Salad"}
],
personName: "",
personHairColor: "",
personFavFood: "",
addPerson: function () {
this.get("people").push({
name: this.get("personName"),
hairColor: this.get("personHairColor"),
favoriteFood: this.get("personFavFood")
});
this.set("personName", "");
this.set("personHairColor", "");
this.set("personFavFood", "");
}
});
kendo.bind($("body"), viewModel);
</script>
</body>
</html>
这里是页面动作的截图。您会看到通过填写表格,表中已经增加了一名额外的人员。自己试一试,看看这个代码与您之间的即时交互:
在 View 中使用可观察属性
我们刚刚看到在 View-Model 中向可观察集合添加新数据是多么简单,以及这如何导致任何数据绑定元素立即显示新数据。让我们添加一些更多功能来展示如何处理单个元素,并看看它们的可观察值如何更新页面内容。
为了演示这个新功能,我在表格中添加了一些列:
<table>
<caption>People Data</caption>
<thead>
<tr>
<th>Name</th>
<th>Hair Color</th>
<th>Favorite Food</th>
<th></th>
<th>Live Data</th>
</tr>
</thead>
<tbody data-template="row-template" data-bind="source: people"></tbody>
</table>
第一列新列没有标题文本,但将在页面上为每个表格行包含一个按钮。第二列新列将显示表格中显示的每个对象的“实时数据”在 View-Model 中的值。
这里是更新后的行模板:
<script id="row-template" type="text/x-kendo-template">
<tr>
<td><input type="text" data-bind="value: name" /></td>
<td><input type="text" data-bind="value: hairColor" /></td>
<td><input type="text" data-bind="value: favoriteFood" /></td>
<td><button type="button"
data-bind="click: deletePerson">Delete</button></td>
<td><span data-bind="text: name"></span> -
<span data-bind="text: hairColor"></span> -
<span data-bind="text: favoriteFood"></span></td>
</tr>
</script>
注意,我已经将所有的简单text data-bind
属性替换为输入元素和valuedata-bind
属性。我还添加了一个带有clickdata-bind
属性的按钮和一个显示三个属性文本的列,这样您就可以实时看到可观察行为。
View-Model 为删除按钮获得了一个新方法:
deletePerson: function (e) {
var person = e.data;
var people = this.get("people");
var index = people.indexOf(person);
people.splice(index, 1);
}
当通过 Kendo UI 创建的绑定调用此函数时,它会传递一个事件参数,这里称为e
,到包含数据属性的函数中。这个数据属性是对用于渲染特定数据行的模型对象的引用。在这个函数中,我创建了一个person
变量来引用这一行的人员,以及一个对people
数组的引用;然后我们使用这个人员的索引从数组中移除它。当您点击删除按钮时,您可以观察到表格立即对变化做出反应。
这里是更新后的 View-Model 的完整源代码:
<script id="row-template" type="text/x-kendo-template">
<tr>
<td><input type="text" data-bind="value: name" /></td>
<td><input type="text" data-bind="value: hairColor" /></td><td><input type="text" data-bind="value: favoriteFood" /></td>
<td><button type="button" data-bind="click:
deletePerson">Delete</button></td>
<td><span data-bind="text: name"></span> -
<span data-bind="text: hairColor"></span> -
<span data-bind="text: favoriteFood"></span></td></tr>
</script><script type="text/javascript">
var viewModel = kendo.observable({
people: [
{name: "John", hairColor: "Blonde", favoriteFood: "Burger"},
{name: "Bryan", hairColor: "Brown", favoriteFood: "Steak"},
{name: "Jennifer", hairColor: "Brown", favoriteFood: "Salad"}
],
personName: "",
personHairColor: "",
personFavFood: "",
addPerson: function () {
this.get("people").push({
name: this.get("personName"),
hairColor: this.get("personHairColor"),
favoriteFood: this.get("personFavFood")
});
this.set("personName", "");
this.set("personHairColor", "");
this.set("personFavFood", "");
},
deletePerson: function (e) {
var person = e.data;
var people = this.get("people");
var index = people.indexOf(person);
people.splice(index, 1);
}
});
kendo.bind($("body"), viewModel);
</script>
</body>
</html>
这里是新的页面截图:
点击 删除 按钮可以看到一个条目消失。你还可以看到我向表中添加了一个新的人,并且我在表格的输入框中做了更改,这些更改立即显示在右侧。这表明视图模型正在跟踪实时数据,并相应地更新其绑定。
更好地利用可观察数组
在最后几个例子中,我们一直在使用一个名为 people
的数组来展示带有 Kendo UI 绑定的动态表格。到目前为止,这运行得很好,但随着模型和功能的更加复杂,我们可能会遇到所谓的“瓶颈”。例如,没有方法能让“实时数据”直接来自模型对象本身;我们不得不在模板中将三个 span
元素连接起来以形成最终的输出。这可能会给更复杂和功能更全面的页面带来问题,在这些页面上,你可能有一个需要能够自行处理事件和计算值的模型对象数组,而不是在视图模型级别上。
按照以下方式修改行模板:
<script id="row-template" type="text/x-kendo-template">
<tr>
<td><input type="text" data-bind="value: name.stuff" /></td>
<td><input type="text" data-bind="value: hairColor.stuff" /></td>
<td><input type="text" data-bind="value: favoriteFood.stuff" /></td>
<td><button type="button"
data-bind="click: deletePerson">Delete</button></td>
<td data-bind="text: dataString"></td>
</tr>
</script>
我们在 data-bind
声明中更改了属性名称,以便它们指向我们为它们创建的内部属性,称为 stuff
。示例中的重要部分是我们还更改了最后一列,使其指向一个名为 dataString
的计算值函数。随着我们继续,这个含义将变得清晰。接下来,更新视图模型的 JavaScript 块,使其看起来像这样:
<script type="text/javascript">
var viewModel = kendo.observable({
people: [],
personName: "",
personHairColor: "",
personFavFood: "",
addPerson: function () {
this.get("people").push(new person({
name: this.get("personName"),
hairColor: this.get("personHairColor"),
favoriteFood: this.get("personFavFood")
}));
this.set("personName", "");
this.set("personHairColor", "");
this.set("personFavFood", "");
},
deletePerson: function (e) {
var person = e.data;
var people = this.get("people");
var index = people.indexOf(person);
people.splice(index, 1);
}
});
var person = function (data) {
var self = this;
this.name = kendo.observable({ stuff: data.name });
this.hairColor = kendo.observable({ stuff: data.hairColor });
this.favoriteFood = kendo.observable({ stuff: data.favoriteFood });
this.dataString = function () {
returnself.name.get("stuff") + " - " +
self.hairColor.get("stuff") + " - " +
self.favoriteFood.get("stuff");
}
};
viewModel.get("people").push(new person({ name: "John",
hairColor: "Blonde",
favoriteFood: "Burger" }));
viewModel.get("people").push(new person({ name: "Bryan",
hairColor: "Brown",
favoriteFood: "Steak" }));
viewModel.get("people").push(new person({ name: "Jennifer",
hairColor:"Brown",
favoriteFood: "Salad" }));
kendo.bind($("body"), viewModel);
</script>
我们做了几项更改,让我们仔细地一步步来看。第一个重要的更改就在顶部,我们将静态数组声明替换为 people
属性作为一个空数组,使用方括号表示法 []
。其次,我们创建了一个新的对象类型 person
,并给它提供了一个构造函数,其中包含它自己的内部可观察对象。这些可观察对象中的每一个都需要一个对象来管理,简单的值并不完全适用,所以我们为它们创建了一个任意属性,称为 stuff
。这里发生的事情只是这个新的 person
对象类型的属性指向了可观察对象而不是简单数据。为什么?因为如果属性不是可观察的,那么视图模型将不会通知变化,用户界面也不会通过数据绑定进行更新。
这次变更的目的是为了使对象特定实例的计算值本地化,我们已经在person
构造函数内部通过dataString
函数实现了这一点。正如你所见,dataString
函数从本地可观察的属性中提取值,并以格式化的字符串形式返回它们。这很重要,因为它意味着每个person
对象都有其自己的函数副本,并且视图模型本身并不参与这个计算。这意味着视图模型内部的每个对象都可以观察其特定的变化,并基于这些变化计算值。这种类型的模型在高级场景中非常有用。
在声明person
构造函数之后,我们手动向people
数组中添加了一些新的person
对象,然后像往常一样调用kendo.bind()
。当渲染时,页面看起来和表现就像上一个例子一样,但现在模型对象更智能了。以下是更新后的视图模型的完整源代码:
<script id="row-template" type="text/x-kendo-template">
<tr>
<td><input type="text" data-bind="value: name.d" /></td>
<td><input type="text" data-bind="value: hairColor.d" /></td>
<td><input type="text" data-bind="value: favoriteFood.d" /></td>
<td><button type="button"
data-bind="click: deletePerson">Delete</button></td>
<td data-bind="text: dataString"></td>
</tr>
</script>
<script type="text/javascript">
var viewModel = kendo.observable({
people: [],
personName: "",
personHairColor: "",
personFavFood: "",
addPerson: function () {
this.get("people").push(new person({
name: this.get("personName"),
hairColor: this.get("personHairColor"),
favoriteFood: this.get("personFavFood")
}));
this.set("personName", "");
this.set("personHairColor", "");
this.set("personFavFood", "");
},
deletePerson: function (e) {
var person = e.data;
var people = this.get("people");
var index = people.indexOf(person);
people.splice(index, 1);
}
});
var person = function (data) {
var self = this;
this.name = kendo.observable({ d: data.name });
this.hairColor = kendo.observable({ d: data.hairColor });
this.favoriteFood = kendo.observable({ d: data.favoriteFood });
this.dataString = function () {
returnself.name.get("d") + " - " +
self.hairColor.get("d") + " - " + self.favoriteFood.get("d");
}
};
viewModel.get("people").push(new person({
name: "John", hairColor: "Blonde",
favoriteFood: "Burger"
}));
viewModel.get("people").push(new person({
name: "Bryan", hairColor: "Brown",
favoriteFood: "Steak"
}));
viewModel.get("people").push(new person({
name: "Jennifer", hairColor: "Brown",
favoriteFood: "Salad"
}));
kendo.bind($("body"), viewModel);
</script>
</body>
</html>
页面运行时的输出如下:
Kendo MVVM 的数据绑定属性
在data-bind
Kendo UI 属性内部可以使用十三种不同的值类型。以下是它们定义和用法的总结。
attr
属性
attr
属性用于将视图模型的值绑定到页面元素的特定 HTML 属性。例如,这对于设置图像的src
属性或锚点的href
属性非常有用。
... //View-Model definition
imageSource: 'http://www.images.com/randomImage.jpg',
...
<img data-bind="attr: {src: imageSource}" />
这样的绑定将确保图像会随着视图模型的变化而变化,从而允许在网页上动态加载或更改图像。
注意,当属性以逗号分隔时,attr
属性可以一次设置多个属性,如下所示:
data-bind="attr: {attribute1: value, attribute2: value, attribute3: value, ...}"
此属性可以与任何 HTML 元素以及任何有效的 HTML 属性(包括自定义 HTML5 data-*
属性)一起使用。
checked
属性
checked
属性用于绑定类型为checkbox
或radio
的输入元素的选中状态。对于复选框,数据绑定属性可以是布尔值(true
/false
)或数组。对于单选选择,属性需要是字符串。例如:
isChecked: true, ...
// Simple Boolean binding
// The data-bound property will be updated when the user clicks the checkbox
<input type="checkbox" data-bind="checked: isChecked" />
animals: ["cow", "pig"], ...
// Array binding for checkboxes
// The array will change based on which checkboxes are checked by the user
// The initial page will show both the "cow" and "pig" inputs as checked
<input type="checkbox" value="horse" data-bind="checked: animals" />
<input type="checkbox" value="cow" data-bind="checked: animals" />
<input type="checkbox" value="pig" data-bind="checked: animals" />
tablet: "surface", ...
// String binding for radio buttons
// The string will change based on which radio option is selected by the user
// The initial page will show the input with the value "surface" as checked
<input type="radio" name="tablet" value="surface" data-bind="checked: tablet" />
<input type="radio" name="tablet" value="ipad" data-bind="checked: tablet" />
<input type="radio" name="tablet" value="android" data-bind="checked: tablet" />
如你稍后所见,checked
绑定可以与visible
/invisible
绑定结合使用,这样页面上的复选框或单选按钮将动态显示或隐藏页面上的其他部分。
点击属性
click
属性将按钮的点击事件绑定到视图模型内的一个函数。它是我们稍后将看到的events
绑定的一种快捷方式。与传统的点击事件连接不同,Kendo UI 框架将传递上下文数据到事件处理器,以允许更丰富的事件处理体验。例如,当在行模板内绑定点击事件时,传递给事件处理器的参数将能够访问源集合中的项目。这使得事件处理器可以直接操作该模型数据,而无需进行任何进一步的 DOM 探索,并保持所有可观察的功能不变。
从技术上讲,Kendo UI 将包装在 jQuery 事件对象中的 DOM 事件传递给绑定中指定的事件处理器,但它也像我们在上一段中讨论的那样管理数据属性。由于事件参数仍然与 DOM 事件相关联,因此您可以在该事件参数上调用stopPropagation()
和preventDefault()
来阻止 DOM 在页面上执行任何其他操作。
我们在上面提供的代码示例中已经看到了click
绑定的例子,所以这里有一些我们当时使用的代码片段:
// Our example row template that included the click binding that will
// pass the data property to the event handler
<script id="row-template" type="text/x-kendo-template">
<tr>
<td><input type="text" data-bind="value: name.d" /></td>
<td><input type="text" data-bind="value: hairColor.d" /></td>
<td><input type="text" data-bind="value: favoriteFood.d" /></td>
<td><button type="button"
data-bind="click: deletePerson">Delete</button></td>
<td data-bind="text: dataString"></td>
</tr>
</script>
// Our example form that included the click binding that has no
// relevant data property to pass to the event handler
<form>
<header>Add a Person</header>
<input type="text" name="personName" placeholder="Name"
data-bind="value: personName" /><br />
<input type="text" name="personHairColor" placeholder="Hair Color"
data-bind="value: personHairColor" /><br />
<input type="text" name="personFavFood" placeholder="Favorite Food"
data-bind="value: personFavFood" /><br />
<button type="button" data-bind="click: addPerson">Add</button>
</form>
...
// This version of the click binding does not use the event argument
addPerson: function () {
this.get("people").push(new person({
name: this.get("personName"),
hairColor: this.get("personHairColor"),
favoriteFood: this.get("personFavFood")
}));
this.set("personName", "");
this.set("personHairColor", "");
this.set("personFavFood", "");
},
// This version of the click binding uses the event argument to
// current data item from the source collection
deletePerson: function (e) {
var person = e.data;
var people = this.get("people");
var index = people.indexOf(person);
people.splice(index, 1);
}
自定义属性
Kendo UI 允许自定义绑定,以便您可以为页面的视图模型创建与自定义行为相关的功能。Kendo UI 文档站点上的一个示例使用基于视图模型中布尔值的 jQuery UI slideDown
和slideUp
调用作为一些 UI 转换的快捷方式。有关自定义绑定的更详细 API 参考,请参阅 Kendo UI 文档。
禁用/启用属性
disabled
和enabled
绑定作用于输入、选择和文本区域 HTML 元素。正如它们的名称所暗示的那样,它们分别禁用或启用绑定的元素。这些绑定是为与布尔属性一起使用而设计的,但为了 JavaScript 的宽松类型,它们将非布尔值0
、null
、undefined
和""
(空字符串)视为false
,并将所有其他非布尔值视为true
。以下是一个示例代码:
allowEdit: false, ...
// This input element will be initially disabled until the View-Model's allowEdit
// View-Model's allowEdit property is changed to true
<input type="text" data-bind="enabled: allowEdit" />
事件属性
events
绑定是方便地将视图模型中的事件处理器连接到视图中的 HTML 元素事件的一种方式。正如我们上面看到的,点击绑定是这个模式的一个具体例子,并且以完全相同的方式运行。例如:
<button type="button" data-bind="events: {blur: blurHandler, click: clickHandler,
mouseover: mouseHandler,...}">Interactive Button</button>
html/text 属性
html
绑定使用视图模型中属性的值设置 HTML 元素的innerHTML
内容。与text
绑定不同,它不会在生成输出之前对 HTML 标签进行编码,这意味着视图模型属性中的 HTML 标签将被渲染为 HTML 而不是文本(如果您使用html
绑定,这可能是您想要的)。以下是一个示例:
spanContent: "<strong>Some Content</strong>",...
<span data-bind="html: spanContent"></span>
这将在渲染页面的源代码中生成如下输出:
<span><strong>Some Content</strong></span>
text
绑定与 html
绑定的工作方式完全相同,不同之处在于它设置元素标签之间的简单文本,并且在输出之前会编码 HTML,因此不要在包含要显示的文本的属性中放置 HTML,除非你希望标签作为文本输出的一部分显示。
无形/可见属性
invisible
和 visible
绑定用于 HTML 元素,您希望动态地显示或隐藏这些元素。正如它们的名称所表明的,它们分别使给定元素不可见或可见。这些绑定旨在与布尔属性一起使用,但为了 JavaScript 宽松类型,它们将非布尔值 0
、null
、undefined
和 ""
(空字符串)视为假,并将所有其他非布尔值视为真。以下是一个示例代码:
showDetails: true, ...
// This element will be initially visible unless the View-Model's
// showDetails property is changed to false
<pdata-bind="visible: showDetails">All sorts of text here...</p>
如前所述,将复选框或单选按钮的值与页面上的其他元素的可见状态连接可能非常有用。这允许你根据用户的选择更改页面上显示的数据。以下是一个简单的示例:
showDetails: false, ...
<input type="checkbox" data-bind="checked: showDetails" name="showDetails" />
<p data-bind="visible: showDetails">All sorts of text and details…</p>
这段代码将使复选框控制包含某些文本的段落元素的可见性,这些文本仅在复选框被选中时才显示。这可能比在普通 Web 应用程序中使用的代码要简单,但它说明了基本原理。
source
属性
source
绑定旨在使用视图模型属性的值来渲染 Kendo UI 模板。如果该属性是数组,则 Kendo UI 框架将为数组的每个元素渲染模板。此模板由附加到相关 HTML 元素上的 data-template
属性指定,并且应通过其 id
属性指示模板。当模板被渲染时,它们将直接放置在具有 source
属性的元素下方 DOM 中。这就是为什么你会在表格的 tbody
元素上放置 source
属性,以便 Kendo UI 模板中的 tr
元素将被渲染并直接放置在 DOM 中,这样它们就会作为表格中的行出现。此绑定可以在任何合理包含一组低级元素的元素上工作,table
只是一个自然的例子;其他很好的用途包括 ul
、ol
和 select
元素。
我们已经在我们的代码示例中看到了 source
绑定。我将粘贴其中一部分作为提醒:
// table with the source binding on the tbody element
<table>
<caption>People Data</caption>
<thead>
<tr>
<th>Name</th>
<th>Hair Color</th>
<th>Favorite Food</th>
<th></th>
<th>Live Data</th>
</tr>
</thead>
<tbody data-template="row-template" data-bind="source: people"></tbody>
</table>
...
// the template that creates the rows
<script id="row-template" type="text/x-kendo-template">
<tr>
<td><input type="text" data-bind="value: name.d" /></td>
<td><input type="text" data-bind="value: hairColor.d" /></td>
<td><input type="text" data-bind="value: favoriteFood.d" /></td>
<td><button type="button"
data-bind="click: deletePerson">Delete</button></td>
<td data-bind="text: dataString"></td>
</tr>
</script>
这是一个使用对象数组 source
绑定的好例子。source
绑定也可以与简单值数组一起使用,在这种情况下,你会在模板内部使用关键字 this
而不是对象内的属性名称:
<script id="row-template" type="text/x-kendo/template">
<tr>
<td data-bind="text: this"></td>
</tr>
</script>
source
绑定也可以与单个对象(而不是数组)一起使用,在这种情况下,它表现得就像绑定到一个只有一个元素的数组一样。如果您想访问 View-Model 中的单个属性,也可以将其绑定到 View-Model 本身,在这种情况下,您将 source
作为 this
关键字的一个属性来引用:
// table with the source binding on the tbody element
<table>
<caption>People Data</caption>
<thead>
<tr>
<th>Name</th>
<th>Hair Color</th>
<th>Favorite Food</th>
<th></th>
<th>Live Data</th>
</tr>
</thead>
<tbody data-template="row-template" data-bind="source: viewModel"></tbody>
</table>
...
// the template that creates the rows
<script id="row-template" type="text/x-kendo-template">
<tr>
<td><input type="text" data-bind="value: this.name" /></td>
<td><input type="text" data-bind="value: this.hairColor" /></td>
<td><input type="text" data-bind="value: this.favoriteFood" /></td>
<td><button type="button"
data-bind="click: deletePerson">Delete</button></td>
<td data-bind="text: dataString"></td>
</tr>
</script>
...
<script type="text/javascript>
var viewModel = kendo.observable({
name: "john",
hairColor: "blonde",
favoriteFood: "burger"
});
...
</script>
注意,结构看起来就像您在引用一个单一对象一样,但我们使用 this
关键字,因为我们直接引用了 View-Model。
当绑定到 select
元素时,请注意,您可以使用一个简单的值数组或一个对象数组。如果您只有一个对象数组,请使用 data-text-field
来指示包含要显示在每个 option
中的文本的属性,并使用 data-value-field
来指示包含每个 option
元素中的值的属性。
样式属性
样式绑定是创建您 View-Model 中的数据与页面上的 CSS 样式之间动态关系的一种极好方式。这是一个非常简单的绑定,它直接在 View-Model 中的属性和您的标记中的样式之间建立关系。例如:
<span data-bind="style: {color: myColor, fontWeight: myFontWeight}" />
<script type="text/javascript">
var viewModel = kendo.observable({
myColor: "orange",
myFontWeight: "bold"
});
</script>
显然,如果您将一些逻辑与页面中使用的样式绑定在一起,这将变得非常有用,例如,改变交替表格行的样式或根据某些特殊标准(如透支余额看起来是红色)改变文本颜色。
注意,我们使用了 fontWeight
样式属性,这可能会让您感到奇怪。如果您需要引用通常包含连字符(font-weight
)的样式,您需要在绑定中使用驼峰式版本,以便它作为一个有效的 JavaScript 属性名称工作。因此,font-weight
在实际的绑定语句中变为 fontWeight
。
最后,如果您将样式值设置为空字符串,它将重置值回到其原始设置。
值属性
value
绑定与 text
绑定非常相似,不同之处在于它设置输入元素的值而不是显示元素的文本。默认情况下,在 View-Model 中绑定的值在失去焦点时更新,例如,当您按下 Tab 键离开页面上的输入元素。如果您想根据不同的 DOM 事件更新 View-Model 属性,您可以在具有绑定的同一元素上设置 data-value-update
属性。我们已经在代码示例中看到了 value
绑定的使用。以下是一个使用 data-value-update
绑定来自定义某些行为的示例:
// the row template
<script id="row-template" type="text/x-kendo-template">
<tr>
<td><input type="text" data-bind="value: name"
data-value-update="keyup" /></td>
</tr>
</script>
记住,这是一个双向绑定,并且对于从用户那里检索数据(当他们填写表单时)非常有用。
与我们上面看到的 checked
绑定类似,value
绑定以类似的方式与 select
元素一起工作。通过将 select
元素的 value
绑定到一个字符串属性,如果选项有值,它将绑定到 select
元素内部的选中 option
元素的值;如果没有 value
,则绑定到选中 option
元素的 text
。以下是这种绑定在标记中的样子:
// Binding using the value, the selectedCar property will be bound to the numbers
<select data-bind="value: selectedCar">
<option value="1">Honda</option>
<option value="2">Toyota</option>
<option value="3">Ford</option>
</select>
// Binding using the text, the selectedCar property will be bound to the text
// between the option tags
<select data-bind="value: selectedCar">
<option>Honda</option>
<option>Toyota</option>
<option>Ford</option>
</select>
当然,你也可以将 select
元素的 source
和 value
都绑定到 View-Model。你不仅限于在 data-bind
属性中只有一个绑定。同样,正如你所期望的,如果你将一个多选元素绑定到一个数组(而不是一个简单的字符串),你也可以绑定其值。
通过 Data-Role MVVM 属性进行声明性小部件
Kendo 的 MVVM 还允许通过 data-role
属性进行声明性小部件初始化。声明性初始化是通过使用 data-role
属性而不是通过 JavaScript 设置小部件来创建 Kendo 小部件的一种不同方法。这不如 JavaScript 方法灵活,但它几乎不需要代码就能实现很多功能。以下是从 Kendo UI 网站上摘取的一段代码,展示了作为介绍的一些基本设置。这些小部件的完整细节可以在那里找到。
<table>
<tr>
<th>Widget</th>
</tr>
<tr>
<td>
<h4>AutoComplete</h4>
<input data-role="autocomplete" data-text-field="name"
data-bind="source: colors, value: autoCompleteValue"/>
</td>
</tr>
<tr>
<td>
<h4>ComboBox</h4>
<select data-role="combobox"
data-text-field="name" data-value-field="value" data-bind="source:
colors, value: comboBoxValue"></select>
</td>
</tr>
<tr>
<td>
<h4>DatePicker</h4>
<input data-role="datepicker" data-bind="value: datePickerValue" />
</td>
</tr>
<tr>
<td>
<h4>DropDownList</h4>
<select data-role="dropdownlist"
data-text-field="name" data-value-field="value" data-bind="source:
colors, value: dropDownListValue"></select>
</td>
</tr>
<tr>
<td>
<h4>Grid</h4>
<div data-role="grid"
data-sortable="true" data-editable="true"
data-columns='["Name", "Price", "UnitsInStock",
{"command": "destroy"}]'
data-bind="source: gridSource"></div>
</td>
</tr>
<tr>
<td>
<h4>NumericTextBox</h4>
<input data-role="numerictextbox" data-format="c"
data-bind="value: numericTextBoxValue" />
</td>
</tr>
<tr>
<td>
<h4>Slider</h4>
<input data-role="slider" data-bind="value: sliderValue" />
</td>
</tr>
<tr>
<td>
<h4>TimePicker</h4>
<input data-role="timepicker" data-bind="value: timePickerValue" />
</td>
</tr>
<tr>
<td>
<h4>TabStrip</h4>
<div data-role="tabstrip" data-animation="false">
<ul>
<li class="k-state-active">First</li>
<li>Second</li>
</ul>
<div>
<h4>First page:</h4>
Pick a time: <input data-role="timepicker"
data-bind="value: timePickerValue"/>
</div>
<div>
<h4>Second page:</h4>
Time is: <span data-bind="text:
displayTimePickerValue"></span>
</div>
</div>
</td>
</tr>
<tr>
<td>
<h4>TreeView</h4>
<div data-role="treeview"
data-animation="false"
data-drag-and-drop="true"
data-bind="source: treeviewSource"></div>
</td>
</tr>
</table>
这是一个使用多个绑定一起使用的绝佳例子,以及哪些绑定正确地适用于哪些小部件。
摘要
Kendo MVVM 框架将复杂的交互式 JavaScript 带入了简单的 HTML 属性、模板和 View-Model 函数的领域。这是一个非常强大的功能,你可能会很快习惯在网页中使用它。在编写代码时请记住,Kendo 是一个可以非常优雅地构建特性的系统;例如,你可以使用 Kendo 数据源对象作为 table
或 select
列表的源绑定。
当你手头有这样的强大工具时,你会发现功能丰富的页面变得正常,而不是异常困难,你的编程体验将比以往任何时候都要好。在下一章中,我们将学习关于 Kendo UI HTML 编辑器小部件。这个小部件将一个功能齐全的 HTML 编辑框添加到你的网页中,以便用户可以在一个友好的输入区域中创建带有格式、图片和超链接的内容。如果用户可以在你的网站上贡献内容,例如通过博客或论坛,这尤其有用。
第五章。HTML 编辑器和自定义工具
交互式 HTML 编辑器是任何鼓励用户发布自己书面内容的网站的的重要组成部分。论坛和博客经常提供这些控件,以便用户可以像在文字处理程序中创建内容一样创建具有吸引力的样式的内容。对于不熟悉如何使用 HTML 标签或 CSS 样式格式化文本的用户来说,这尤其有用。就这一点而言,甚至熟悉 HTML 和 CSS 的用户也会欣赏不必全部输入。本章将介绍以下主题:
-
Kendo 编辑器小部件基础
-
配置编辑器小部件工具
-
使用 HTML 片段
-
自定义编辑器小部件工具
理解 HTML 编辑器
Kendo 编辑器小部件在网页上创建了一个区域,用户可以在其中创建格式化文本内容。要查看一个基本示例的实际操作,请将此代码复制到一个名为 HtmlEditor.html
的新 HTML 页面中。这将允许您在真实页面上查看小部件的使用情况,并为本章的其余部分提供一个起点。
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="img/jquery.js"></script>
<script src="img/kendo.all.js"></script>
<link href="/Content/kendo/kendo.common.css" rel="stylesheet" />
<link href="/Content/kendo/kendo.default.css" rel="stylesheet" />
<style type="text/css">
textarea {
width: 100%;
height: 300px;
}
</style>
</head>
<body>
<textarea id="editor"></textarea>
<script type="text/javascript">
$(document).ready(function () {
$("#editor").kendoEditor();
});
</script>
</body>
</html>
这是假设所有默认设置,因为没有明确设置任何设置或选项。
注意
注意,我们已经将 kendoEditor
函数绑定到 textarea
元素上,这是很重要的,您应该始终将 HTML 编辑器控件绑定到 textarea
元素上,以便在可能不支持所需 JavaScript 功能的浏览器中功能可以优雅地降级。
如果我们使用 ASP.NET MVC 实现了这个功能,那么在视图中看起来会是这样:
@using Kendo.Mvc.UI;
@{
ViewBag.Title = "Html Editor";
}
<style type="text/css">
textarea {
width: 100%;
height: 300px;
}
</style>
<h2>Html Editor</h2>
@(Html.Kendo().Editor()
.Name("htmlEditor"))
再次注意,Kendo MVC 扩展将在 textarea
元素内生成 HTML 编辑器,这就是为什么 textarea
元素的样式声明在页面输出中起作用的原因。
无论您使用 HTML 还是 MVC 视图,这是在所有默认设置假设下的页面输出外观。我使用 HTML 编辑器功能添加了一些文本,以说明控件的目的:
查看编辑器小部件顶部的所有工具按钮。在键入文本时单击它们,以观察它们的作用。此外,请注意,Kendo HTML 编辑器生成的不同按钮都支持 HTML tabindex
,因此您可以使用 Tab 键和 Shift + Tab 键组合来分别在前一个和下一个命令之间移动,如果您想这样做的话。
对于许多网站来说,这已经足够的功能了。要使用用户创建的格式化文本,只需检索 textarea
元素的值,它将包含内容和 HTML 标记。
小贴士
不要忘记检查您的输入
由于你允许用户在其数据内容中公开发布 HTML 标记,因此在将其放入数据库或加载到另一个页面之前,请务必对输入进行清理。即使 Kendo 工具生成的 HTML 标记是安全的,你也永远不能信任从用户的浏览器发送到服务器的最终标记,并且必须始终将其视为可能包含有害代码。
然而,在使用格式化文本之前,你还需要检查你正在处理的值是否已被 HTML 编码。如果你从 DOM 中检索 textarea
元素的原始值,你将得到 HTML 编码的数据。这意味着 <strong>text</strong>
变为 <strong>text</strong>
,这可能是你想要的,也可能不是。
要获取非 HTML 编码的数据,你需要使用如下代码在 kendoEditor
对象上调用 value()
函数:
var editor = $("#editor").data("kendoEditor");
var nonEncodedText = editor.value();
但再次提醒,你需要小心行事。你不能在不绕过一些重要安全措施的情况下将非 HTML 编码的数据像这样发布到大多数 Web 服务器上。更安全的选项是将数据以 HTML 编码的形式发布到 Web 服务器上,然后在服务器端对其进行解码和清理,然后再使用它。这样,你仍然可以在开始解释用户输入之前,直接拒绝页面中的一些潜在恶意代码。
这里是一个更新后的页面,其中包含一些按钮,展示了 DOM val()
函数与 kendoEditor value()
函数的不同输出:
<!DOCTYPE html>
<html>
<head>
<title></title>
<scriptsrc="img/jquery.js"></script>
<scriptsrc="img/kendo.all.js"></script>
<link href="/Content/kendo/kendo.common.css" rel="stylesheet" />
<link href="/Content/kendo/kendo.default.css" rel="stylesheet" />
<style type="text/css">
textarea {
width: 100%;
height: 300px;
}
</style>
</head>
<body>
<textarea id="editor"></textarea>
<button name="showKendoVal" id="showKendoVal" type="button">Show Kendo Value</button><br />
<button name="showHtmlVal" id="showHtmlVal" type="button">Show HTML Value</button>
<script type="text/javascript">
$(document).ready(function () {
$("#editor").kendoEditor();
$("#showHtmlVal").click(function () {
alert($("#editor").val());
});
var editor = $("#editor").data("kendoEditor");
$("#showKendoVal").click(function () {
alert(editor.value());
});
});
</script>
</body>
</html>
这是从 Kendo value()
函数检索到的文本。
这是从编辑器小部件的 innerHTML
中检索到的文本。
从工具栏添加和删除按钮
HTML 编辑器工具栏中还有一些标准工具,默认情况下并未包含:
-
下标
-
上标
-
查看 HTML
要包含这些工具,你需要在创建 kendoEditor
对象时指定 tools
属性,如下所示,并列出你想要显示的具体工具:
$("#editor").kendoEditor({
tools: [
"bold",
"italic",
"underline",
"strikethrough",
"fontName",
"fontSize",
"foreColor",
"backColor",
"justifyLeft",
"justifyCenter",
"justifyRight",
"justifyFull",
"insertUnorderedList",
"insertOrderedList",
"indent",
"outdent",
"formatBlock",
"createLink",
"unlink",
"insertImage",
"subscript",
"superscript",
"viewHtml"
]
});
如果你指定了 tools
,则需要命名所有标准工具,如果你省略了任何工具,它们将不会显示在你的页面工具栏上。相反,以下是使用 ASP.NET MVC 添加下标和上标工具的方法,令人好奇的是,这种方法中不可用 viewHtml
:
@(Html.Kendo().Editor()
.Name("htmlEditor")
.Tools(tools => tools
.SubScript()
.SuperScript()))
这几乎是最简洁的,特别是使用这种方法时,所有默认工具都被假定,你只需要添加你想要包含的工具。如果你想清除默认的工具列表,然后只添加你想要的工具,你首先需要在 Tools
lambda 表达式中调用 Clear()
,然后添加你想要的特定工具。
这里是包含所有标准工具的输出:
添加样式工具
样式工具可以被添加到 HTML 编辑器工具栏中,使用户能够访问一些预定义的样式。如果您的用户正在使用特殊的主题,或者如果存在用户需要轻松访问的全局样式,这可能很有用。要启用此功能,您通过kendoEditor
对象配置工具,并指定哪些选项应该出现在样式下拉列表中。以下是一个示例:
$("#editor").kendoEditor({
tools: [
"bold",
"italic",
"underline",
"strikethrough",
"fontName",
"fontSize",
"foreColor",
"backColor",
"justifyLeft",
"justifyCenter",
"justifyRight",
"justifyFull",
"insertUnorderedList",
"insertOrderedList",
"indent",
"outdent",
"formatBlock",
"createLink",
"unlink",
"insertImage",
"subscript",
"superscript",
"viewHtml",
"style"
],
style:[
{text: "Big Blue", value:"bigBlue"},
{text: "Dark Grey", value:"darkGrey"}
],
stylesheets:[
"css/StyleTool.css"
]
});
这里是StyleTool.css
文件的内容:
.bigBlue {
font-size:large;
color:blue;
}
.darkGrey {
color:white;
background-color:#111111;
}
要使这生效,我向工具列表中添加了样式工具,然后添加了style
配置属性和可选的stylesheets
配置属性。style
配置属性定义了在样式下拉列表中出现的不同选项,以及当这些样式被选中应用于 HTML 编辑器textarea
中的某些文本时,应该应用哪些 CSS 类名。stylesheets
配置选项允许您导入一些额外的样式表,如果它们对于显示自定义样式是必要的。
下面是如何使用 ASP.NET MVC 实现这些样式的示例:
@(Html.Kendo().Editor()
.Name("htmlEditor")
.Tools(tools => tools
.SubScript()
.SuperScript()
.Styles(styles => styles
.Add("Big Blue", "bigBlue")
.Add("Dark Grey", "darkGrey"))
)
.StyleSheets(css =>css
.Add("/Content/StyleTool.css"))
)
下面是这段代码的输出结果:
我为了演示的目的添加了一些样式化的文本,并点击了样式下拉列表来展示该列表中的选项也是按照它们各自的 CSS 类进行样式的。
插入 HTML 片段的工具
Snippets 工具是一个特殊的工具栏选项,它设计用来通过单次点击将预定义的文本块插入到编辑器窗口中。它可以用来添加常见的问答模板、签名块、时间戳,或者任何需要预输入文本的场景。要启用此功能,就像样式选项一样,您通过kendoEditor
对象配置工具,并指定哪些选项应该出现在样式下拉列表中。以下是一个示例:
$("#editor").kendoEditor({
tools: [
"bold",
"italic",
"underline",
"strikethrough",
"fontName",
"fontSize",
"foreColor",
"backColor",
"justifyLeft",
"justifyCenter",
"justifyRight",
"justifyFull",
"insertUnorderedList",
"insertOrderedList",
"indent",
"outdent",
"formatBlock",
"createLink",
"unlink",
"insertImage",
"subscript",
"superscript",
"viewHtml",
"style",
"insertHtml"
],
style:[
{text: "Big Blue", value:"bigBlue"},
{text: "Dark Grey", value:"darkGrey"}
],
stylesheets:[
"css/StyleTool.css"
],
insertHtml:[
{ text: "Today's date", value: "December 7, 2012" },
{ text: "Signature", value: "<p>Sincerely,<br/>John Adams</p>" }
]
});
注意,这只需要非常少的配置即可启用。我们在tools
配置属性中包含了insertHtml
选项,并在kendoEditor
定义的末尾添加了insertHtml
配置属性。在insertHtml
配置属性内部,我们包含了一个非常简单的对象数组。它们定义了应该出现在下拉列表中的每个项目的标题,以及当选择标题时应该粘贴到 HTML 编辑器中的确切标记。
下面是如何使用 ASP.NET MVC 实现这些片段的示例:
@(Html.Kendo().Editor()
.Name("htmlEditor")
.Tools(tools => tools
.SubScript()
.SuperScript()
.Styles(styles => styles
.Add("Big Blue", "bigBlue")
.Add("Dark Grey", "darkGrey"))
.Snippets(snippets => snippets
.Add("Today's Date", DateTime.Today.Date.ToShortDateString())
.Add("Signature", "<p>Sincerely,<br/>John Adams</p>"))
)
.StyleSheets(css =>css
.Add("/Content/StyleTool.css"))
)
下面是这段代码的输出结果:
自定义 HTML 编辑器工具
Kendo HTML 编辑器控件允许您将自定义选项添加到工具栏中。这是 Kendo UI 框架中的一个显著灵活性体现,如果您觉得现有的内置工具不完全满足您的需求,这可能会非常有用。HTML 编辑器可以接受至少三种类型的自定义工具。可能还有更多,但这些三种在 Kendo UI 网站上发布的文档中有所体现:
-
覆盖内置工具
-
自定义模板工具
-
自定义内联工具
下拉列表工具
如果您想修改一些内置的下拉列表工具,您可以重新定义其中显示哪些选项。这不会改变工具的本质或工具的功能。它只决定当您点击工具时,下拉列表中显示哪些选项。例如,考虑限制字体工具中显示的选项。通过替换items
数组的内容,您可以自定义工具在页面显示时精确显示哪些选项:
$("#editor").kendoEditor({
tools: [
{
name: "fontName",
items:
[{text:"Garamond", value: "Garamond, serif"},
{text:"Calibri", value:"calibri, sans-serif"}]
}
]
});
这个代码示例演示了一个自定义的fontName
工具,限制为两个特定的选项。这两个字体在我们之前看到的默认fontName
工具中并未包含,但您也可以在这个自定义列表中包含默认字体。以下是使用此自定义工具配置的 HTML 编辑器的输出:
您会注意到列表中的前两个选项并不是我在源代码中定义的选项——继承的字体和Verdana。这是因为 HTML 编辑器正在从外部的包含 HTML 标记中启用字体,并将其称为继承的字体。然后它通过名称标记这个相同的字体,以便帮助用户进行字体选择,所以继承的字体和Verdana实际上都指的是从整个页面的外部 HTML 标记中继承的同一字体。
这种自定义工具配置应该适用于任何以下拉列表形式出现的自定义工具,例如字体名称、字体大小和格式块工具。
按钮工具
您可能不需要覆盖许多这些控件,因为创建自己的工具可能更有效。不过,如果您想看看如何实现,这里有一个从 Kendo UI 网站上摘取的代码示例,展示了如何用自定义代码替换viewHtml
工具的功能:
<script type="text/x-kendo-template" id="viewHtml-template">
<div>
<textarea style="width: 400px; height: 300px;"></textarea>
<div class="viewHtml-actions">
<button class="k-button viewHtml-update">Update</button>
<button class="k-button viewHtml-cancel">Cancel</button>
</div>
</div>
</script>
<script>
$("#editor").kendoEditor({
tools:
[{
name: "viewHtml",
tooltip: "View HTML",
exec: function(e) {
var editor = $(this).data("kendoEditor");
var dialog = $($("#viewHtml-template").html())
.find("textarea").val(editor.value()).end()
.find(".viewHtml-update")
.click(function() {
editor.value(dialog.element
.find("textarea").val());
dialog.close();
})
.end()
.find(".viewHtml-cancel")
.click(function() {
dialog.close();
})
.end()
.kendoWindow({
modal: true,
title: "View HTML",
deactivate: function() {
dialog.destroy();
}
}).data("kendoWindow");
dialog.center().open();
}
}]
})
</script>
这是页面上的代码显示:
此源代码包括一个模板和 kendoEditor
配置。您可以看到,此代码基本上是打开一个对话框,用 HTML 编辑器控件的内容填充它,连接对话框内按钮的事件,然后将其显示给用户。它至少提供了一个示例,说明如何覆盖内置工具之一。请注意,工具执行的逻辑位于一个名为 exec
的属性中;这对于所有自定义按钮工具也是常见的。tooltip
属性是鼠标悬停在工具栏上的按钮上时显示的文本。
自定义模板工具
如果您想创建一个具有选项下拉列表的自定义工具,自定义模板工具是最佳选择。它允许您使用 Kendo UI 模板来标记工具在工具栏上的显示方式,并且您可以单独连接其功能,以便您的工具可以执行它需要的任何操作:
<textarea id="editor"></textarea>
<button name="showKendoVal" id="showKendoVal" type="button">Show Kendo Value</button><br />
<button name="showHtmlVal" id="showHtmlVal" type="button">Show HTML Value</button>
<script type="text/x-kendo-template" id="editorColor-template">
<label for="customTool">Editor BG:</label>
<select name="customTool" id="customTool"><option value=''>None</option><option value="blue">Blue</option><option value="green">Green</option></select>
</script>
<script type="text/javascript">
$(document).ready(function () {
$("#editor").kendoEditor({
tools: [
{
name: "editorBackground",
template: $("#editorColor-template").html()
}
]
});
$("#showHtmlVal").click(function () {
alert($("#editor").val());
});
var editor = $("#editor").data("kendoEditor");
$("#showKendoVal").click(function () {
alert(editor.value());
});
$("#customTool").change(function (e) {
$("#editor").data("kendoEditor").body.style.backgroundColor =
$("#customTool").val();
});
});
</script>
您可以看到 Kendo 模板中声明的 label
和 select
元素。select
元素的行定义为 jQuery 代码,但自定义下拉列表工具是通过 tools
属性添加到 HTML 编辑器的。
这是带有此自定义工具的页面的输出:
这就是您创建作为下拉列表行为的自定义工具的方法。如您所见,行为完全由您决定,因此您可以创建您网站用例所需的任何工具。
自定义内联工具
如果您想在工具栏上创建自己的按钮工具,内联工具是正确的选择。它允许您定义工具名称和当从工具栏中选择该工具时要执行的代码。
$("#editor").kendoEditor({
tools: [
{
name: "addHr",
tooltip: "Insert Horizontal Rule",
exec: function (e) {
var editor = $(this).data("kendoEditor");
editor.exec("insertHtml", { value: "<hr/>" });
}
}
]
});
此代码显示了一个名为 addHr
的自定义工具,当点击时将在 HTML 编辑器控件中添加一个 hr
元素。您还可以看到在 kendoEditor
上的 exec
函数的使用,您可以在其中指示 HTML 编辑器的一个内置函数/工具,然后提供一个对象,该对象提供其参数。
这是此代码的输出:
使用 HTML 编辑器 API
Kendo HTML 编辑器小部件提供了一组庞大的 API 配置选项,这些选项允许您根据您网页的具体需求和情况对小部件进行微调。它还公开了一组方法和事件,您可以使用这些方法和事件在页面运行时以编程方式启用并响应用户界面小部件公开的功能。这些选项综合起来,就是您如何扩展编辑器小部件超出其开箱即用的能力。
配置选项
我们已经在上面的材料中介绍了一些内容,但以下是 HTML 编辑器控件可用的配置选项。始终请检查 Kendo UI Web 文档在 docs.kendoui.com/api/web/editor
,以获取这些选项的更详细配置设置列表,以及获取 API 的最新更改或新增内容。
$("#editor").kendoEditor({
encoded: true, // whether or not the editor should emit encoded html tags
messages: { // define custom labels for the built-in tools and dialogs
bold: "Bold",
…
},
stylesheets: {…}, // see above, custom stylesheets to load for editor
tools: {…}, // see above, custom and built-in tools to display in the editor
imageBrowser: { // the imageBrowser tool can accept a custom configuration
transport: { // the endpoints to use for image operations
read: "imagebrowser/read",
destroy: "imagebrowser/destroy",
create: "imagebrowser/createDirectory",
uploadUrl: "imagebrowser/upload",
thumbnailUrl: "imagebrowser/thumbnail" // path for thumbnails of images
imageUrl: "/content/images/{0}", // "{0}" is placeholder for virtual
// path and image name
},
path: "/myInitialPath/", // Initial path of images to display
fileTypes: ".png,.gif,.jpg,.jpeg", // Allowed image file extensions
schema: {…}, // a schema can be defined to interpret data returned from
// a remote endpoint when parsing data to display images
messages: {…} // custom messages for imageBrowser controls and dialogs
}
});
事件
就像在复杂网站中的任何 HTML 元素或 JavaScript 对象一样,当用户在页面内执行某些操作时,网页会触发事件。通过使用自己的 JavaScript 代码挂钩到这些事件,你可以实时响应页面的变化和数据,并根据用户执行的操作组织页面的功能。HTML 编辑器控件会根据用户操作触发以下事件:
-
change
: 当编辑器窗口内的数据发生变化时,此事件会触发。 -
execute
: 当一个工具被执行时,此事件会触发。它会在每次工具栏按钮被点击且该按钮背后的代码被执行时触发。 -
keydown
: 当用户在编辑器窗口内按下键时,keydown 事件会触发。通过挂钩到这个事件,你可以对用户正在输入的文本做出响应。 -
keyup
: 当用户在编辑器窗口内按下并释放键时,keydown 事件会触发。通过挂钩到这个事件,你可以对用户正在输入的文本做出响应。 -
paste
: 当文本被粘贴到编辑器窗口区域时,paste 事件会触发。 -
select
: 当用户在编辑器窗口内选择文本时,select 事件会触发。
摘要
HTML 编辑器为你提供了大量的功能,而所需的编码量却很少。在大多数情况下,默认控件将满足你在普通网站上对 HTML 编辑的所有需求。但是,如果你发现自己需要高度定制的工具,这个 HTML 编辑器支持丰富的 API、详细的配置选项以及易于访问的事件,用于捕获和响应用户操作。这是一个不适合每个网站的控件,但当你需要这样的工具时,在这样一个有用且易用的包中找到它将极大地提高生产力。
在下一章中,我们将介绍两个非常重要的 Kendo 控件——菜单和 ListView。这些控件允许你使用在所有前几章中看到过的相同的 Kendo 方法,在你的页面中创建响应式和功能丰富的级联页面菜单以及组织良好的数据结构。基于你已有的知识,使用这些新控件将会很容易,你很快就会开始运行。
第六章:菜单和 ListView
Kendo UI 菜单小部件旨在为您提供一种简单的方法来实现交互式 JavaScript 菜单,该菜单根据用户的命令打开和关闭,并在网页上提供丰富的视觉显示。这些类型的菜单也可以通过其他技巧实现,例如 CSS,但 Kendo UI 小部件为您提供了一个更可配置的框架和访问简化的 JavaScript API。
Kendo UI ListView 小部件是一个用于以图形方式可视化数据元素集合的控制项,特别是如果数据包含图像或特殊样式。像所有 Kendo UI 选项一样,配置是一致的、合理的,并允许您创建外观出色的内容,并提供用于编辑和选择的显示选项。
这些控件是您创建现代网页工具集的良好补充。
学习菜单小部件基础
菜单小部件创建了一个出色的下拉菜单,其中包含飞出部分以显示菜单内容。它功能丰富,对于大多数实现来说,代码量非常少。作为介绍,这里是一个从静态无序列表 HTML 创建的基本菜单的代码示例:
<!DOCTYPE html>
<html>
<head>
<title>Kendo UI Menu</title>
<script src="img/jquery.js"></script>
<script src="img/kendo.all.js"></script>
<link href="/Content/kendo/kendo.common.css" rel="stylesheet" />
<link href="/Content/kendo/kendo.default.css" rel="stylesheet" />
</head>
<body>
<div id="menuDemo">
<ul id="menu">
<li>
Music
<ul>
<li>
Blues / Folk
<ul>
<li>Contemporary Blues</li>
<li>Contemporary Folk</li>
<li>Traditional American</li>
<li>World Folk</li>
</ul>
</li>
<li>
Christian / Gospel
<ul>
<li>Christian Rock / Hip Hop</li>
<li>Contemporary Christian</li>
<li>Traditional Gospel</li>
</ul>
</li>
...
</ul>
</li>
<li>
Videos
<ul>
<li>Movies</li>
<li>TV</li>
<li>Trailers</li>
</ul>
</li>
<li>
Events
</li>
<li disabled="disabled">
News
</li>
</ul>
</div>
<script>
$(document).ready(function () {
$("#menu").kendoMenu();
});
</script>
</body>
</html>
这是一个显示不同音乐风格、视频以及其他一些选项的菜单,仅用于演示代码的外观。无序列表中的顶级<li>
元素在输出中均显示为实际的菜单标题,在本例中它们是音乐、视频、活动和新闻。
注意
注意,这些顶级元素每个都包含自己的名称,并且可以可选地包含一个嵌套的无序列表(<ul>
),它将成为在页面上选择顶级项时出现的选项。
在向下移动链的过程中,嵌套列表中的每个<li>
元素也可以包含它自己的<ul>
,以创建进一步的嵌套菜单选项。这会产生级联效果,当您将鼠标移动到不同的选项时,菜单选项可以继续展开。此外,请注意,最终的顶级<li>
项“新闻”带有禁用属性,这意味着它仍然会在输出中显示,但不能被选择。
这是页面首次加载时的输出:
当鼠标悬停在菜单中的某些元素上时,这就是菜单小部件的外观。自己试一试,看看菜单对这些事件反应有多快、多流畅;这非常令人印象深刻。
与 Kendo UI 框架中的大多数小部件一样,菜单小部件不必从静态 HTML 运行,它可以由本地或远程数据的DataSource
对象提供动力。以下是使用本地DataSource
对象而不是静态 HTML 的代码示例:
<!DOCTYPE html>
<html>
<head>
<title>Kendo UI Menu</title>
<script src="img/jquery.js"></script>
<script src="img/kendo.all.js"></script>
<link href="/Content/kendo/kendo.common.css" rel="stylesheet" />
<link href="/Content/kendo/kendo.default.css" rel="stylesheet" />
</head>
<body>
<div id="menuDemo">
</div>
<script type="text/javascript">
var menuData = [
{
text: "Music",
items: [
{
text: "Blues/Folk",
items: [
{ text: "Contemporary Blues" },
{ text: "Contemporary Folk" },
{ text: "Traditional American" },
{ text: "World Folk" }
]
},
{
text: "Christian / Gospel",
items: [
{ text: "Christian Rock / Hip Hop" },
{ text: "Contemporary Christian" },
{ text: "Traditional Gospel" }
]
},
...
]
},
{
text: "Videos",
items: [
{ text: "Movies" },
{ text: "TV" },
{ text: "Trailers" }
]
},
{
text: "Events"
},
{
text: "News",
enabled: false
}
];
</script>
<script type="text/javascript">
$(document).ready(function () {
$("#menuDemo").kendoMenu(
{ dataSource: menuData });
});
</script>
</body>
</html>
注意,DataSource
对象可以配置您在前面章节中看到的所有选项,并且可以轻松地配置一个用于远程数据的传输属性。
输出与第一次使用的静态 HTML 相同:
与大多数 Kendo UI 小部件一样,无论数据来自页面标记还是 JavaScript 数据源,页面上的交互内容都是相同的。为了适应使用 MVC 扩展方法,我们可以在cshtml
文件中创建一个 MVC 视图,其源代码如下:
@using Kendo.Mvc.UI;
@{
ViewBag.Title = "Mvc Menu";
}
<h2>Mvc Menu</h2>
@(Html.Kendo().Menu()
.Name("menuDemo")
.Items(items =>
{
items.Add().Text("Music").Items(sub =>
{
sub.Add().Text("Blues / Folk").Items(subsub =>
{
subsub.Add().Text("Contemporary Blues");
subsub.Add().Text("Contemporary Folk");
subsub.Add().Text("Traditional American");
subsub.Add().Text("World Folk");
});
sub.Add().Text("Christian / Gospel").Items(subsub =>
{
subsub.Add().Text("Christian Rock / Hip Hop");
subsub.Add().Text("Contemporary Christian");
subsub.Add().Text("Traditional Gospel");
});
...
});
items.Add().Text("Videos").Items(sub => {
sub.Add().Text("Movies");
sub.Add().Text("TV");
sub.Add().Text("Trailers");
});
items.Add().Text("Events");
items.Add().Text("News").Enabled(false);
})
)
注意,在这个代码示例中,我声明了数据是静态的。它也可以很容易地从 C#代码中的不同源收集,或者甚至将其作为 JavaScript 的一部分,并通过 HTTP 从远程源检索。
从这个屏幕截图可以看出,输出与另外两个代码示例相同:
这说明了创建 Kendo UI 菜单小部件的三种独特方法及其之间的区别。
带有图像的菜单项
到目前为止,菜单项仅包括文本。然而,菜单小部件还可以包含一个imageUrl
属性或一个spriteCssClass
属性,以显示与文本一起的图像。图像或精灵将作为图标出现在菜单项文本的左侧。
这里是一个使用imageUrl
属性来显示Videos
菜单项图标的示例:
...
{
text: "Videos",
imageUrl: "images/reel.png",
items: [
{ text: "Movies" },
{ text: "TV" },
{ text: "Trailers" }
]
},
...
通过添加此属性,输出现在在菜单中显示了图像:
这就是代码示例在 MVC 中的样子:
items.Add().Text("Videos").ImageUrl("/static/images/reel.png").Items(sub => {
sub.Add().Text("Movies");
sub.Add().Text("TV");
sub.Add().Text("Trailers");
});
注意添加到输出中的ImageUrl
扩展方法。
要使用精灵图,您首先需要设置应显示图标的菜单项的背景图像,然后使用spriteCssClass
属性指定一个 CSS 类,该类将指定每个特定图标的像素偏移。任何指定了spriteCssClass
属性的菜单项都将自动装饰上k-sprite
CSS 类,以确保正确连接。以下是一个可能的示例:
<style>
#menuDemo .k-sprite {
background-image: url("images/sprites.png");
}
.someIcon {
background-position: 0 0;
}
.someOtherIcon {
background-position: 0 -32px;
}
</style>
...
<script>
...
{
text: "Videos",
spriteCssClass: "someIcon",
items: [
{ text: "Movies" },
{ text: "TV" },
{ text: "Trailers" }
]
},
...
这个示例的 CSS 部分显示了为所有k-sprite
类装饰的元素分配background-image
属性,并指定了两个精灵像素background-position
样式。脚本部分显示了正在使用的spriteCssClass
属性,它将为该菜单项分配精灵图像的相应部分作为图标。
带有 URL 的菜单项
到目前为止,我展示的所有示例都是当选择时不会执行任何操作的菜单项。您需要做的只是将url
属性添加到菜单项中,以便在点击时导航。因此,对于您想要将用户导航到不同页面的任何菜单项,请包括一个url
属性,如这里所示,它将这样做:
...
{
text: "Videos",
spriteCssClass: "someIcon",
url: "http://www.kendoui.com",
items: [
{ text: "Movies" },
{ text: "TV" },
{ text: "Trailers" }
]
},
...
注意,在这个屏幕截图中的网络浏览器显示了Videos菜单项现在导航到的 URL。
菜单 API 配置选项
如您现在所期望的,Kendo UI 菜单小部件可以通过一组完整的 API 属性和方法进行配置。这些选项是可以配置的属性,以便菜单小部件能够满足您的网页和风格需求。这些配置是在创建菜单小部件的代码点中指定的。以下部分将向您展示您可以使用哪些选项。
动画属性
Kendo UI 菜单的动画动作可以配置为样式、速度和方向。当您配置菜单的打开动作时,Kendo 会自动为close
动作分配相反的行为。如果您想独立于open
动作配置close
动作,那么您应该分别配置它们,如下所示:
...
$("menu").kendoMenu({
animation: {
close: { // animation to use when closing a menu
effects: "slideIn", // 'slideIn' / 'fadeIn' / 'expand'
duration: 10
},
open: { // animation to use when opening a menu
effects: "slideIn:Down", // You can assign a direction too
duration: 10
}
}
});
...
// or you can disable animation entirely
$("menu").kendoMenu({
animation: false
});
方向属性
direction
属性决定了当用户悬停在菜单上时,菜单将打开的方向。这里可用的选项有top
、bottom
、left
和right
。
$("menu").kendoMenu({
direction: "bottom"
});
...
// or you can specify how each level of submenus open separately
$("menu").kendoMenu({
direction: "bottom right" // "bottom" for menu, "right" for sub menus
});
更多选项
在配置菜单行为方面,还有一些额外的选项可供选择。您可以使用closeOnClick
、openOnClick
和hoverDelay
属性来配置菜单如何根据鼠标移动和点击行为进行操作。您可以使用orientation
属性来配置整个菜单是水平还是垂直排列,并且可以通过popupCollision
属性来指导 Kendo UI 框架如何使菜单适应页面。所有这些配置都可以在这里找到:
$("menu").kendoMenu({
closeOnClick: true, // close menus when item is selected
hoverDelay: 100, // delay before menus open/close
openOnClick: false, // root submenus open with item is selected
orientation: "vertical", // root menu orientation:
popupCollision: "fit" // how to adjust menu to screen boundaries
// Use "fit flip" for vertical menus.
// Set to false to disable boundary detection completely.
});
配置菜单方法
Kendo UI 菜单小部件的一些方法需要您获取现有菜单项对象的引用(而不仅仅是 HTML 元素)作为附加或插入一些额外菜单项的参考点。在这种情况下,您可以通过对 Kendo 菜单的引用来访问菜单项对象,如下所示:
var menu= $("#menuDemo").kendoMenu().data("kendoMenu");
在此代码中,您可以从实例化它的同一行代码中获取 Kendo 菜单对象的引用。这样,您可以在页面的其他部分和 JavaScript 逻辑中引用此对象。您还可以在任何代码点通过在包含它的 HTML 元素上调用.data(…)
来获取 Kendo 菜单对象的引用,但一次性完成是更好的选择。
一旦您有了这个引用,您就可以通过element
属性访问 Kendo 菜单内部的子项:
menu.element.children("li").eq(3);
在此代码示例中,我们正在访问这个特定菜单对象的子代中的第四个li
元素。这里的返回值将是一个 JavaScript 对象,可以用作append
、insertAfter
和insertBefore
方法的参考点。
append()、insertAfter()和 insertBefore()方法
append
方法接受两个参数:要附加为子项的新菜单项的 JSON 表示,以及将作为新附加项父项的菜单项的引用:
var menu = $("menu").data("kendoMenu");
var referenceItem = menu.element.children("li").eq(1);
menu.append(
[{
text: "new menu item",
url: "http://www.music.com",
items: [...]
}],
referenceItem
);
此代码将此菜单项作为子项附加到页面上的第二个菜单项。insertAfter
和 insertBefore
方法的工作方式完全相同,只是它们在相同的菜单级别插入新的菜单项,分别是在参考项之后或之前。
注意
所有这些方法都返回菜单对象以支持方法链。
close()、enable()、open() 和 remove() 方法
这些 Kendo UI 菜单的方法不需要 JavaScript 对象引用;它们直接在页面菜单中的 HTML 元素上操作。因此,您可以使用 jQuery 选择器类型语法来选择要操作的项目(项),并使用熟悉的语法。
enable
方法接受两个参数:HTML 元素(元素)的选择器和表示项目应启用(true)或禁用(false)的 true
或 false
值:
var menu = $("menu").data("kendoMenu");
menu.enable("#secondItem", false);
此特定的代码示例将禁用具有 HTML id
值为 secondItem
的元素。
这里其他的方法,即 close
、open
和 remove
,只接受一个参数,即 HTML 元素(元素)的选择器。请注意,框架不会为您分配元素的 ID 值或类名,您必须自己将这些值分配给您的元素,以便选择它们:
var menu = $("menu").data("kendoMenu");
menu.close(".green");
menu.open("#item3");
menu.remove("#lastItem");
注意
所有这些方法都返回菜单对象以支持方法链。
菜单事件
Kendo UI 菜单触发三个事件:close
、open
和 select
。每个事件都提供了一个包含关闭、打开或选择的 HTML <li>
元素的 item
属性的事件参数,如下所示:
<script>
$(document).ready(function () {
function onSelected(e) {
var menu = $("#menu").data("kendoMenu");
menu.enable(".green", false);
alert("disabling green menu");
}
$("#menu").kendoMenu({ select: onSelected });
});
</script>
以下代码示例展示了连接到处理选择事件的某个方法,该事件将禁用所有具有类名 green
的菜单项。由于此代码没有考虑选择了哪个特定元素,因此无论选择了哪个元素,它都会触发相同的代码。以下是一个不同的示例:
<script type="text/javascript">
$(document).ready(function () {
function onSelected(e){
alert(e.item.innerHTML);
};
var menu= $("#menuDemo").kendoMenu(
{ dataSource: menuData, select: onSelected }).data("kendoMenu");
});
</script>
此代码检查所选的特定元素,并将它的 innerHTML
属性弹回用户。
Kendo UI ListView
Kendo UI ListView 小部件旨在在网页上以比标准 HTML 列表更丰富的功能集展示数据集合。ListView 小部件通过 Kendo DataSource
对象检索其数据,通过一个或多个 Kendo 模板块展示其数据,并允许用户通过在页面上选择和编辑数据与数据交互。
ListView 基础
基本上,ListView 小部件通过使用模板和 DataSource
对象来显示数据集合:
<!DOCTYPE html>
<html >
<head>
<title>ListView</title>
<script src="img/jquery.js"></script>
<script src="img/kendo.all.js"></script>
<link href="/Content/kendo/kendo.common.css" rel="stylesheet" />
<link href="/Content/kendo/kendo.default.css" rel="stylesheet" />
<style type="text/css">
.animal {
width:250px;
height:200px;
position:relative;
float:left;
}
.animal-label {
font-size:large;
}
.animal-image {
max-height:100px;
max-width: 150px;
margin: 5px;
}
#listView {
width:750px;
height:100%;
}
</style>
</head>
<body>
<div id="listView"></div>
<script type="text/x-kendo-tmpl" id="template">
<div class="animal">
<img src="img/#= imageName #" alt="#= animalName #
image" class="animal-image" />
<div class="animal-label">#= animalName #</div>
</div>
</script>
<script type="text/javascript">
var animals = [
{ animalName: "African Elephant",
imageName: "african-elephant.jpg" },
{ animalName: "African Lion", imageName: "african-lion.jpg" },
{ animalName: "Alpaca", imageName: "alpacas.jpg" },
{ animalName: "Badger", imageName: "badger.jpg" },
{ animalName: "Black Bear", imageName: "bear-black.jpg" },
{ animalName: "Bison", imageName: "bison.jpg" },
{ animalName: "Jack-Rabbit",
imageName: "black-tailed-jackrabbit.jpg" },
{ animalName: "Caribou", imageName: "caribou.jpg" },
{ animalName: "Giraffe", imageName: "giraffe.jpg" },
{ animalName: "Hummingbird", imageName: "humming-bird.jpg" },
{ animalName: "Jaguar", imageName: "jaguar.jpg" },
{ animalName: "Lemur", imageName: "lemur.jpg" },
{ animalName: "Red Fox", imageName: "red-fox.jpg" },
{ animalName: "Striped Skunk", imageName: "striped-skunk.jpg" }
];
$(document).ready(function () {
$("#listView").kendoListView({
dataSource: animals,
template: kendo.template($("#template").html())
});
});
</script>
</body>
</html>
以下代码示例从上到下显示了将出现在 ListView 小部件内部的元素的一些样式。这些样式声明对于在网页上正确布局 ListView 小部件内部的图像非常重要:
<style type="text/css">
.animal {
width:250px;
height:200px;
position:relative;
float:left;
}
.animal-label {
font-size:large;
}
.animal-image {
max-height:100px;
max-width: 150px;
margin: 5px;
}
#listView {
width:750px;
height:100%;
}
</style>
然后我们创建一个 div
元素,它将包含 ListView 小部件和 Kendo UI 模板,该模板结构化单个 ListView 元素。这个模板决定了 ListView 中的每个项目如何在网页内渲染。对 ListView 项的任何更改都必须在这里进行:
<div id="listView"></div>
<script type="text/x-kendo-tmpl" id="template">
<div class="animal">
<img src="img/#= ${imageName #}" alt="#= ${animalName #}
image" class="animal-image" />
<div class="animal-label">#= ${animalName #}</div>
</div>
</script>
然后我们有包含一些数据和 ListView 实例化的 JavaScript 对象字面量,其中设置了 dataSource
和 template
属性:
<script type="text/javascript">
var animals = [
{ animalName: "African Elephant",
imageName: "african-elephant.jpg" },
{ animalName: "African Lion", imageName: "african-lion.jpg" },
{ animalName: "Alpaca", imageName: "alpacas.jpg" },
{ animalName: "Badger", imageName: "badger.jpg" },
{ animalName: "Black Bear", imageName: "bear-black.jpg" },
{ animalName: "Bison", imageName: "bison.jpg" },
{ animalName: "Jack-Rabbit",
imageName: "black-tailed-jackrabbit.jpg" },
{ animalName: "Caribou", imageName: "caribou.jpg" },
{ animalName: "Giraffe", imageName: "giraffe.jpg" },
{ animalName: "Hummingbird", imageName: "humming-bird.jpg" },
{ animalName: "Jaguar", imageName: "jaguar.jpg" },
{ animalName: "Lemur", imageName: "lemur.jpg" },
{ animalName: "Red Fox", imageName: "red-fox.jpg" },
{ animalName: "Striped Skunk", imageName: "striped-skunk.jpg" }
];
$(document).ready(function () {
$("#listView").kendoListView({
dataSource: animals,
template: kendo.template($("#template").html())
});
});
</script>
像往常一样,请记住,DataSource
对象可以完全配置以指向远程数据源,可以使用模式进行结构化,或者可以使用您在生产场景中可能想要利用的任何其他选项。
您可以看到 DataSource
对象中的每个元素是如何使用模板渲染的,并且按照预期在页面上进行了样式化和展示。
使用 ListView 选择元素
ListView 小部件提供的功能远不止显示数据,首先让我们看看它是如何允许“选择”元素的。在这个代码示例中,我向 ListView 实例化逻辑中添加了一些更多属性和事件处理程序来演示这一点:
$(document).ready(function () {
$("#listView").kendoListView({
dataSource: animals,
template: kendo.template($("#template").html()),
selectable: "multiple",
change: notifyUser
});
function notifyUser(e) {
var selected = $.map(this.select(), function (item) {
return animals[$(item).index()].animalName;
});
alert(selected.join(", "));
}
});
</script>
selectable
属性已设置为 multiple
以允许多选项目(您可以通过在键盘上按住 Ctrl 键并使用鼠标点击来在页面上选择多个项目)。我们还添加了一个 change
事件的事件处理程序,以便我们可以看到一个显示已选择元素的警告框。
在 notifyUser
事件处理函数中,我想解释一下正在发生的事情,因为乍一看可能有点令人困惑。变量 selected
被赋予了一个包含所有已选择元素 animalName
属性值的数组。它是通过在 this.select()
的结果上使用 $.map
来做到这一点的。什么是 this.select()
?好吧,当 Kendo 从小部件触发事件时,它会设置该事件处理程序的范围,使得 this
指向触发事件的 Kendo 小部件。所以,在这种情况下,this
是对 ListView 的引用。这意味着在这个事件处理程序中调用 this.select()
将返回 ListView 中所有已选择元素的集合。$.map
的第二个参数函数然后通过使用 animals
数组的索引从这些元素中获取 animalName
属性。这段代码的结果是一个包含所有已选择元素的 animalName
值的字符串数组。然后使用 [array].join()
将其显示给用户。
这里是选择了一些项目并显示从事件处理程序中出现的警告框的输出:
注意动物名称是如何全部显示在页面上弹出的 alert 框中的。这很好,因为这意味着您可以准确地跟踪用户在 ListView 中所做的选择,并按需对这些操作做出响应。
使用 ListView 编辑元素
ListView 小部件还提供了一种良好的语法,允许编辑 DataSource
对象内的数据。您需要创建一个单独的模板来显示允许用户进行编辑的内容,然后确保您分配了一些 Kendo 特定的类名,以便它能够正确显示和理解命令。以下是新模板的代码。将其放置在最后一个示例中创建的模板下方。
<script type="text/x-kendo-tmpl" id="edit-template">
<div class="animal">
<img src="img/#= imageName #" alt="#= animalName # image"
class="animal-image" />
<div class="animal-label">
<input type="text" data-bind="value:animalName" name="animalName"
required="required" /></div>
<div>
<a class="k-button k-button-icontext k-update-button"
href="\\#"><span class="k-icon k-update"></span>Save</a>
<a class="k-button k-button-icontext k-cancel-button"
href="\\#"><span class="k-icon k-cancel"></span>Cancel</a>
</div>
</div>
</script>
注意
您注意到模板中两个按钮的 href
属性中的不寻常字符了吗?双反斜杠字符 \\#
防止哈希标记被渲染为 Kendo 模板的一部分。如果这个哈希标记没有被这些反斜杠转义,模板将根本无法渲染。
接下来,我们在创建我们的 ListView 小部件的 JavaScript 块中添加了一些更多配置。具体来说,我们现在有一个 editTemplate
属性,它指向我们刚刚创建的模板:
<script type="text/javascript">
var animals = [
{ animalName: "African Elephant",
imageName: "african-elephant.jpg" },
...
];
$(document).ready(function () {
$("#listView").kendoListView({
dataSource: animals,
template: kendo.template($("#template").html()),
editTemplate: kendo.template($("#edit-template").html())
});
});
</script>
</body>
</html>
下面是一个截图,其中 Caribou 的名称已被编辑为 Reindeer:
ListView API 和配置
我们已经在先前的示例中涵盖了 ListView 的几个方面;以下是文档中剩余的配置属性:
$("#listView").kendoListView({
autoBind: true, // if false, you must call read() manually
dataSource: ..., // demonstrated above
editTemplate: ..., // demonstrated above
navigatable: false, // whether or not keyboard navigation is enabled
selectable: false, // true/false or "single"/"multiple" are valid options
template: ..., // demonstrated above
altTemplate: ... // template used for alternating styles if desired
});
ListView 方法
ListView 小部件有几种可用方法。大多数方法都是设计用来操作 ListView 中的项目,以便您可以通过代码来控制行为。像任何小部件一样,在调用这些方法之前,您需要获得 listView JavaScript 对象的引用,如下所示:
var listView = $("#listView").data("kendoListView");
...
listView.add(...)
通过 .data(...)
方法获取引用,然后您可以调用 ListView 特定的方法。以下是无需参数的方法的简要概述:
-
add
:将空项目插入到 ListView 中并准备它进行编辑 -
cancel
:取消当前编辑项中的更改 -
clearSelection
:清除 ListView 的选中项并触发change
事件 -
refresh
:重新加载数据并重新打印 ListView -
save
:保存编辑后的 ListView 项目。如果验证成功,它将调用数据源的sync
方法。
有几种其他方法确实接受参数。
编辑方法
此方法编辑指定的 ListView 项目并触发 edit
事件。此方法接受一个参数,即需要编辑的 ListView 项目。以下是一个示例:
var listView = $("#listView").data("kendoListView");
...
listView.edit(listView.element.children().first());
删除方法
此方法删除指定的 ListView 项目并触发 remove
事件。它还会触发数据源的 sync
方法。
var listView = $("#listView").data("kendoListView");
...
listView.remove(listView.element.children().first());
选择方法
此方法选择指定的 ListView 项目。如果没有提供任何参数调用此方法,它将返回 ListView 中所有选中项目的集合。这正是我们在选择项目的代码示例中所做的。以下是一个使用参数调用此方法的代码示例:
var listView = $("#listView").data("kendoListView");
...
listView.select(listView.element.children().first());
ListView 事件
ListView 小部件公开了几个事件,用于挂钩其生命周期和行为。我们已经在我们的示例中看到了一些。这些事件都可以在 ListView 实例化期间分配给处理程序,正如我们在本章前面所保存的。以下是一个列表:
-
change
: 当 ListView 选择项发生变化时触发 -
dataBound
: 当 ListView 从DataSource
对象接收数据并即将渲染时触发 -
dataBinding
: 当数据即将在页面上渲染时触发 -
edit
: 当 ListView 进入编辑模式时触发 -
remove
: 在 ListView 项目被移除之前触发
摘要
菜单和 ListView 小部件是结构化网页上数据的优秀工具。菜单小部件使得创建用于导航的交互式 JavaScript 菜单以及显示带有图形的数据变得简单。当您想在网页上以标准方式渲染数据元素集合时,ListView 小部件应该成为您的标准选项。它为您提供了连接功能的能力,否则这将需要大量的代码和调试。
在下一章中,我们将探讨 Kendo UI PanelBar 小部件。它的 API 与 Kendo UI Menu 小部件非常相似,正如您将看到的,它是一种在网页中渲染手风琴控件的有效方式。与 Kendo UI Menu 小部件类似,它的主要职责是以节省屏幕空间的方式组织层次化内容,同时仍然为用户提供一个合理的结构来理解。
第七章:实现 PanelBar 和 TabStrip
PanelBar 和 TabStrip 小部件是用于组织数据的特殊 Kendo UI 控件,使得网页能够包含大量内容,但一次只显示其中的一部分内容。这些内容部分被 PanelBar 小部件分割成面板,或者被 TabStrip 小部件分割成标签页。在两种情况下,效果都非常相似,并且是保持网页不过于杂乱的一种非常有用的方式。本章将解释使用 HTML 和 ASP.NET MVC 实现 PanelBar 和 TabStrip 控件的基础知识,然后说明以下功能:
-
将图片添加到 PanelBar 和 TabStrip 项目中
-
将 URL 添加到 PanelBar 和 TabStrip 项目中
-
使用 PanelBar 和 TabStrip 加载 AJAX 内容
-
控制 PanelBar 和 TabStrip 动画效果
PanelBar 基础知识
PanelBar 小部件是 Kendo UI 在网页上实现交互式 JavaScript “折叠”的方式。这种类型的控件对于显示可能占用大量屏幕空间的数据列表非常有用,但将其压缩成对用户仍有意义的格式。作为介绍,这里是一个从静态无序列表 HTML 创建的基本 PanelBar 的代码示例。此 HTML 列表将被重新格式化为一个折叠控件,一次显示列表的一个区域。正如您将看到的,当运行代码示例时,这允许大量数据在视觉上压缩到更小的空间。它还允许用户选择他们感兴趣查看的列表区域,并隐藏其他部分的详细信息。这展示了 Kendo 小部件实现之间的一些共同点:
注意
注意,我在 Menu 控制中使用了与上一章相同的数据。
<!DOCTYPE html>
<html>
<head>
<title>Kendo UI PanelBar</title>
<script src="img/jquery.js"></script>
<script src="img/kendo.all.js"></script>
<link href="/Content/kendo/kendo.common.css" rel="stylesheet" />
<link href="/Content/kendo/kendo.default.css" rel="stylesheet" />
</head>
<body>
<div id="panelBarDemo">
<ul id="panelBar">
<li>
Music
<ul>
<li>
Blues / Folk
<ul>
<li>Contemporary Blues</li>
<li>Contemporary Folk</li>
<li>Traditional American</li>
<li>World Folk</li>
</ul>
</li>
<li>
Christian / Gospel
<ul>
<li>Christian Rock / Hip Hop</li>
<li>Contemporary Christian</li>
<li>Traditional Gospel</li>
</ul>
</li>
...
</ul>
</li>
<li>
Videos
<ul>
<li>Movies</li>
<li>TV</li>
<li>Trailers</li>
</ul>
</li>
<li>
Events
</li>
<li disabled="disabled">
News
</li>
</ul>
</div>
<script>
$(document).ready(function () {
$("#panelBar").kendoPanelBar();
});
</script>
</body>
</html>
此源代码创建了一个 PanelBar,其数据与上一章中 Menu 的数据相同。无序列表中的顶级 <li>
元素在输出中均显示为实际的折叠标题。在这个例子中,正如菜单示例中一样,它们是 音乐、视频、活动 和 新闻。请注意,这些顶级元素都包含自己的名称,并且可以可选地包含一个嵌套的无序列表 (<ul>
),当在页面上选择该顶级项目时,它将显示为选项。向下移动链,嵌套列表中的每个 <li>
元素也可以包含自己的 <ul>
列表,以创建进一步嵌套的选项菜单,这在不是所有折叠实现都能处理这种级别嵌套数据的情况下是非常令人印象深刻的。这创建了一个级联效果,其中菜单选项可以随着您将鼠标移动到不同的选项而继续展开。此外,请注意,最终的顶级 <li>
项目 新闻
被标记为 disabled
属性,这意味着它仍然会在输出中显示,但不能被选择。
下面是此代码的输出:
在此截图拍摄之前,点击了视频面板,以便您可以看到一些打开的数据,它通常以所有面板都关闭开始。
就像之前的菜单小部件一样,PanelBar 小部件不必从静态 HTML 运行,它可以由本地或远程数据的DataSource
对象提供动力。以下是使用数据源而不是静态 HTML 的代码修改示例:
<body>
<div id="panelBarDemo">
</div>
<style type="text/css">
#panelBarDemo img{
max-height: 30px;
max-width: 30px;
}
</style>
<script type="text/javascript">
var panelBarData = [
{
text: "Music",
items: [
{
text: "Blues/Folk",
items: [
{ text: "Contemporary Blues" },
{ text: "Contemporary Folk" },
{ text: "Traditional American" },
{ text: "World Folk" }
]
},
{
text: "Christian / Gospel",
items: [
{ text: "Christian Rock / Hip Hop" },
{ text: "Contemporary Christian" },
{ text: "Traditional Gospel" }
]
},
...
]
},
{
text: "Videos",
imageUrl: "/Images/reel.png",
items: [
{ text: "Movies" },
{ text: "TV" },
{ text: "Trailers" }
]
},
{
text: "Events"
},
{
text: "News",
enabled: false
}
];
</script>
<script type="text/javascript">
$(document).ready(function () {
$("#panelBarDemo").kendoPanelBar({ dataSource: panelBarData} );
});
</script>
</body>
</html>
备注
注意,DataSource
对象可以配置为所有您在早期章节中看到的选项,也可以通过传输属性配置远程数据。
在这个代码示例中,我们还实现了一个新功能,即视频标签页的imageUrl
属性。通过指定项目中的图像 URL,输出将显示屏幕上标签页标题旁边的此图像,您可以在下面的屏幕截图中看到:
要适应使用 MVC 扩展方法,您需要在cshtml
文件中创建一个 MVC 视图,并包含以下源代码:
@using Kendo.Mvc.UI;
@{
ViewBag.Title = "Mvc PanelBar";
}
<style type="text/css">
li img {
max-height: 25px;
max-width: 25px;
}
</style>
<h2>Mvc Menu</h2>
@(Html.Kendo().PanelBar()
.Name("panelBarDemo")
.Items(items =>
{
items.Add().Text("Music").Items(sub =>
{
sub.Add().Text("Blues / Folk").Items(subsub =>
{
subsub.Add().Text("Contemporary Blues");
subsub.Add().Text("Contemporary Folk");
subsub.Add().Text("Traditional American");
subsub.Add().Text("World Folk");
});
sub.Add().Text("Christian / Gospel").Items(subsub =>
{
subsub.Add().Text("Christian Rock / Hip Hop");
subsub.Add().Text("Contemporary Christian");
subsub.Add().Text("Traditional Gospel");
});
...
});
items.Add().Text("Videos").ImageUrl("/static/images/reel.png").Items(sub => {
sub.Add().Text("Movies");
sub.Add().Text("TV");
sub.Add().Text("Trailers");
});
items.Add().Text("Events");
items.Add().Text("News").Enabled(false);
})
)
备注,在这个代码示例中,我们已经声明了数据是静态的。它也可以通过 C#代码中的逻辑从不同的来源收集,或者甚至作为 JavaScript 的一部分留下,并通过 HTTP 从远程源检索。我们还可以看到,这里的图像是通过 ASP.NET MVC 语法而不是通过上一个示例中的 JavaScript 提供的。
从这个屏幕截图中,您可以看到输出与另外两个代码示例完全相同:
这说明了创建 Kendo UI PanelBar 小部件的三种独特方法,就像之前的菜单小部件一样,以及它们之间的区别。
将精灵图像添加到 PanelBar 项
我们已经看到了一些示例,说明了 PanelBar 小部件如何包含imageUrl
属性来显示与部分标题并排的图像。它还可以通过指定spriteCssClass
属性来使用更高级的图像选项。在两种情况下,图像或精灵都将作为菜单项文本左侧的图标出现。
正如我们之前部分看到的,以下是一个使用imageUrl
属性显示视频
菜单项图标的示例:
...
{
text: "Videos",
imageUrl: "/images/reel.png",
items: [
{ text: "Movies" },
{ text: "TV" },
{ text: "Trailers" }
]
},
...
通过添加此属性,输出现在在菜单中显示图像:
这就是使用 MVC 语法时的代码示例:
items.Add().Text("Videos").ImageUrl("/images/reel.png").Items(sub => {
sub.Add().Text("Movies");
sub.Add().Text("TV");
sub.Add().Text("Trailers");
});
注意,添加到输出中的ImageUrl
扩展方法。
要使用精灵,您首先需要设置应显示图标的菜单项的背景图像,然后使用spriteCssClass
属性指定一个 CSS 类,该类将指定每个特定图标的像素偏移。每个指定了spriteCssClass
属性的菜单项将自动装饰上k-sprite
CSS 类,以确保正确连接。以下是一个可能的示例:
<style>
#panelBarDemo .k-sprite {
background-image: url("images/sprites.png");
}
.someIcon {
background-position: 0 0;
}
.someOtherIcon {
background-position: 0 -32px;
}
</style>
...
<script>
...
{
text: "Videos",
spriteCssClass: "someIcon",
items: [
{ text: "Movies" },
{ text: "TV" },
{ text: "Trailers" }
]
},
...
此示例的 CSS 部分显示了为所有k-sprite
类装饰的元素分配background-image
属性,并指定了两个精灵像素background-position
样式。脚本部分显示了正在使用的spriteCssClass
属性,它将分配精灵图像的相应部分作为该菜单项的图标。
向 PanelBar 项添加 URL
到目前为止,我们看到的所有示例都是当选择时不会执行任何操作的 PanelBar 项。我们唯一需要做的就是向 PanelBar 项添加url
属性,以便在点击时导航。因此,对于任何我们希望将用户导航到不同页面的 PanelBar 项,包括一个url
属性,它就会这样做:
...
{
text: "Videos",
spriteCssClass: "someIcon",
url: "http://www.microsoft.com",
items: [
{ text: "Movies" },
{ text: "TV" },
{ text: "Trailers" }
]
},
...
使用 PanelBar 加载 AJAX 内容
与将所有内容嵌入一个页面不同,可以使用 PanelBar 小部件通过 AJAX 动态地从其他 URL 加载内容。这将减少页面的整体大小,因为一次只会加载 PanelBar 的一个部分。它还可以允许您从您的站点中的其他位置加载内容,这些位置可能独立于包含您的 PanelBar 的站点而变化,这可以减少重复文本或标记。要启用此功能,请使用 PanelBar 的contentUrls
属性来指示哪些站点包含应放置在手风琴内部的标记:
$("#panelId").kendoPanelBar({
...
contentUrls: [
"content1.html",
"content2.html" ]
});
其次,我们必须在 HTML 标记中创建占位符,以指示 AJAX 内容加载后会出现的位置。这只需要以下代码的结构,其中包含包含空<div>
元素的<li>
元素,这些元素将在适当的时间接收 AJAX 内容:
<ul id="panelBarDemo">
<li>
Remote content
<div></div>
</li>
<li>
More content
<div></div>
</li>
</ul>
使用这种标记和 JavaScript 代码的组合,PanelBar 将加载第一个标签页的content1
,第二个标签页的content2
,依此类推。保持这些页面上的内容非常简单是个好主意,这样它就可以适应 PanelBar 区域而不会变形。
控制 PanelBar 动画效果
可以通过在 JavaScript 中配置 PanelBar 对象时使用动画属性来控制 PanelBar 的动画功能。可以将animation
属性设置为false
以完全禁用所有动画效果,或者可以像以下代码示例那样进行配置以实现特定行为:
$("#panelId").kendoPanelBar({
...
expandMode: "single", // "multiple" for multiple open tabs at once
animation: {
collapse: {
duration: 1000, // milliseconds for animation effect
effects: "fadeOut" //"fadeout" is the only option for collapse
},
expand: {
duration: 500,
effects: "expandVertical fadeIn" // choose either or both of these
}
});
可用的唯一折叠动作动画效果是fadeOut
。对于expand
动作,可以选择expandVertical
,这是展开 PanelBar 的正常动作,以及fadeIn
,它在展开时改变不透明度。
介绍 TabStrip 小部件
TabStrip 小部件与 PanelBar 小部件非常相似。实际上,它们执行的功能几乎相同,只是 PanelBar 小部件将内容组织成垂直堆叠的面板,而 TabStrip 小部件将内容组织成水平堆叠的面板。它们如此相似,以至于我们将使用几乎相同的代码来演示这两个小部件。你已经在前面几节中看到了 PanelBar 小部件。现在我们将查看 TabStrip 小部件,并了解它在网页中的功能。
TabStrip 基础
TabStrip 小部件创建了一系列标签,用于一次只显示特定内容的一个部分。标签内的内容可以是几乎所有东西,从简单的文本和标记到足够填充整个网页的 <div>
部分都可以。你肯定见过网页顶部有标签的网页,用于将不同类型的材料组织到单个网页上。Kendo TabStrip 小部件是在自己的页面上创建这种效果的一种方法。首先,将以下代码复制到一个新的 HTML 页面中,并在网页浏览器中运行它:
<!DOCTYPE html>
<html>
<head>
<title>Kendo UI TabStrip</title>
<script src="img/jquery.js"></script>
<script src="img/kendo.all.js"></script>
<link href="/Content/kendo/kendo.common.css" rel="stylesheet" />
<link href="/Content/kendo/kendo.default.css" rel="stylesheet" />
</head>
<body>
<div id="panelBar">
<ul>
<li>
Music
</li>
<li>
Videos
</li>
<li>
Events
</li>
<li disabled="disabled">
News
</li>
</ul>
<div>Next concert in May of 2013!</div>
<div>Next music video in July of 2013!</div>
<div>Memorabilia signing on April 15th</div>
<div></div>
</div>
<script>
$(document).ready(function () {
$("#panelBar").kendoTabStrip();
});
</script>
</body>
</html>
对于此小部件,标记必须遵循特定的模式。TabStrip 本身必须在包含无序列表 (<li>
) 和紧随无序列表之后的一组 <div>
元素的 <div>
元素上声明。这在上面的代码示例中都很明显。无序列表包含所有标签标题。<div>
元素集合包含在每个标签中出现的所有内容,其顺序与在标记中出现的顺序相同。这就是这个特定示例在网页浏览器中运行时的样子:
使用数据源与 TabStrip 结合
与 PanelBar 类似,TabStrip 可以配置为使用数据源,而不是在网页上现有的 HTML 标记之上创建。要将上一节中的代码示例适应这种模式,用以下代码替换页面主体:
<body>
<div id="panelBar">
</div>
<script>
$(document).ready(function () {
$("#panelBar").kendoTabStrip({
dataTextField: 'text',
dataContentField: 'content',
dataSource: [
{
text: 'Music',
content: 'Next concert in May of 2013!'
},
{
text: 'Videos',
content: 'Next music video in July of 2013!'
},
{
text: 'Events',
content: 'Memorabilia signing on April 15th'
},
{
text: 'News',
content: ''
}
]
});
});
</script>
</body>
此代码的输出与之前完全相同,只是由于没有属性可以定义使用数据源禁用的元素,因此新闻标签没有被禁用:
将图片添加到 TabStrip 小部件
到目前为止,所有的 TabStrip 标签都只包含文本。然而,TabStrip 小部件(就像 PanelBar 小部件一样),也可以包含一个 imageUrl
属性来在标签的标题旁边显示图片。它还可以通过指定 spriteCssClass
属性来使用更高级的图片选项。在任一情况下,图片或精灵都将作为图标出现在标签标题文本的左侧。以下是一个使用 imageUrl
属性来显示 Videos
菜单项图标的示例:
...
{
text: "Videos",
imageUrl: "/images/reel.png",
content: "Next music video in July of 2013!"
}
...
通过添加此属性,输出现在在菜单中显示了图片:
当使用 MVC 语法时,相同的代码示例看起来是这样的:
@using Kendo.Mvc.UI;
@{
ViewBag.Title = "Mvc TabStrip";
}
<style type="text/css">
li img {
max-height: 25px;
max-width: 25px;
}
</style>
<h2>Mvc TabStrip</h2>
@(Html.Kendo().TabStrip()
.Name("tabStripDemo")
.Items(items =>
{
items.Add().Text("Music")
.Content("Next concert in May of 2013!");
items.Add().Text("Videos")
.Content("Next music video in July of 2013!")
.ImageUrl("/images/reel.png");
items.Add().Text("Events")
.Content("Memorabilia signing on April 15th");
items.Add().Text("News").Enabled(false);
})
)
你应该能够注意到与我们之前用于 PanelBar 小部件的代码有很多相似之处。要使用与 TabStrip 一起的精灵,你可以遵循我们之前讨论的 PanelBar 的相同程序。
向 TabStrip 标签页添加 URL
要将 TabStrip 标签页用作指向另一页面的超链接,你可以配置该标签页的 url
属性,并承担此角色。通过这样做,我们不再使用标签页在页面上显示任何内容,它只是在点击时直接导航到另一个网页。
...
{
text: 'News',
content: '',
url: 'http://www.kendoui.com'
}
...
通过这种方式修改代码后,新闻
标签页将变成一个超链接,而不是实际显示内容的标签页。
使用 TabStrip 加载 AJAX 内容
要将 AJAX 内容加载到标签页中,我们需要在配置中指定每个标签页内容的 URL。这与 TabStrip 中的其他选项遵循相同的模式,因此现在你应该非常熟悉这种格式:
<script>
$(document).ready(function () {
$("#panelBar").kendoTabStrip({
dataTextField: 'text',
dataContentField: 'content',
dataImageUrlField: 'dataImageUrl',
dataUrlField: 'url',
dataContentUrlField: 'contentUrl',
dataSource: [
{
text: 'Remote Content',
contentUrl: 'content1.html'
},
{
text: 'More Content',
contentUrl: 'content2.html'
}
]
});
});
</script>
当我们在浏览器中运行网页时,它将呈现如下,随着我们点击标签页标题,远程内容会动态加载:
控制 TabStrip 小部件的动画效果
TabStrip 小部件的动画效果与 PanelBar 小部件完全相同。它们通过在 JavaScript 中配置 TabStrip 对象时通过 animation
属性来控制。可以将 animation
属性设置为 false
以完全禁用所有动画效果,或者可以像以下代码示例那样配置以实现特定行为:
$("#tabSripId").kendoTabStrip({
...
animation: {
collapse: {
duration: 1000, // milliseconds for animation effect
effects: "fadeOut" //"fadeout" is the only option for collapse
},
expand: {
duration: 500,
effects: "expand:vertical fadeIn" // choose either or both of these
}
});
可用的折叠动作的唯一动画效果是 fadeOut
。对于 expand
动作,你可以选择 expand:vertical
,这是展开 TabStrip 的正常动作,以及 fadeIn
,它在展开时改变透明度。
摘要
PanelBar 小部件是一个高度可配置的 JavaScript 折叠小部件,为你提供了相当大的“物有所值”。对于需要压缩到更小屏幕空间中的分类数据元素列表,PanelBar 小部件是网页的完美选择。TabStrip 小部件是一个简单的 JavaScript 标签框架,允许你使用标签组织页面内容,甚至在点击标签时动态将远程内容加载到页面上。这两个出色的组件都应该为你的网站添加有用的功能。
在下一章中,你将了解 Kendo UI 滑块小部件及其如何以图形化的方式收集用户输入。滑块小部件将 HTML 输入显示为可视化的条形,用户可以拖动滑块到所需选项,而不是在表单字段中输入数字。
第八章. 滑块基本知识
Kendo UI 框架包括一些特殊的滑块小部件,这些小部件在网页上显示滑块条,用户可以通过拖动手柄来增加或减少滑块以选择一个值。这些滑块通常有刻度和标签,指示可用的最高和最低数字以及它们之间的范围。这些小部件是帮助用户在固定刻度上选择数字的出色视觉工具,而不是仅仅输入一个可能或可能不合适的值。例如,在评分系统中,或者在只允许一组特定数字的任何输入控件中,这可能很有用。正如您将看到的,Kendo UI 允许进行良好的配置,因此您可以自定义 UI 的外观和功能以满足您的需求。
介绍滑块和范围滑块
我们首先应该介绍的是 Kendo UI 提供的两种不同类型的滑块小部件。有标准的 Kendo UI 滑块小部件,还有一个 Kendo UI 范围滑块小部件。Kendo UI 范围滑块小部件是为更高级的场景设计的,在这种情况下,你的页面需要在一个页面元素中捕获一个范围(一个底部和一个顶部的数字)而不是仅仅一个值。
理解这些滑块小部件是用于向输入 HTML 元素提供数字的特殊视觉辅助工具是很重要的。滑块小部件的最终输出是用户选择的数字,并且这个数字被设置为输入 HTML 元素的值。这是很重要的,因为输入元素可以随后被放入 HTML 表单中,并在表单提交时由另一端的 Web 服务器使用。
沿着这个思路,当在页面上创建 Kendo UI 滑块小部件时,请务必遵循以下模式:
<!— value is optional, but will set the initial value of the slider if present -->
<input id="sliderId" value="2" />
...
<script>
$(function(){
$("#sliderId").kendoSlider({...});
});
</script>
kendoSlider
方法需要绑定到一个实际的输入 HTML 元素上。那么 Kendo UI 范围滑块小部件又是如何呢?它使用两个数字,但输入控件只包含一个值。它是如何维护这两个独立值的呢?答案是,它使用两个输入元素在容器div
标签内部:
<div id="rangeSliderId">
<input />
<input />
</div>
...
<script>
$(function(){
$("#rangeSliderId").kendoRangeSlider({...});
});
</script>
这样,Kendo UI 范围滑块小部件就在一个div
元素上创建,并且将它的范围值构建到该容器div
内部的两个输入元素中,以便正确地在页面上渲染。
使用滑块和范围滑块与 MVC 扩展方法
以下代码示例展示了使用 ASP.NET MVC 扩展方法实例化滑块小部件的基本方法。必须调用Name
方法,以便所有 Kendo 小部件都能正常工作。
@(Html.Kendo().Slider().Name("horizontalSlider"))
...
@(Html.Kendo().RangeSlider().Name("horizontalRangeSlider"))
实现基本功能
作为介绍,我创建了一个示例页面,展示了各种配置下的滑块和范围滑块。在以下几节中讨论功能和选项时,我们将使用相同的代码示例。在这个示例中,我们使用 CSS 绝对定位固定了元素的位置。这并不一定是网页设计的最佳实践,但它可以用来单独显示这些控件。在这个第一个代码块中,我们创建了包含滑块小部件所需的 HTML 标记。每个滑块都是在包含输入元素的 div
元素上创建的。这将在以下代码示例之后进行解释:
<!DOCTYPE html>
...
<body>
<!-- Two slider widgets -->
<div id="sliders">
<h2 style="position:absolute;top:5px;left:40px">Slider Widgets</h2>
<!-- vertical slider widget -->
<div style="position:absolute;top:65px;left:100px;">
<input id="verticalSlider" value="2" /></div>
<!-- horizontal slider widget -->
<div style="position:absolute;top:285px;left:15px;">
<input id="horizontalSlider" value="7" /></div>
</div>
<!-- Two rangeslider widgets -->
<div id="rangeSliders">
<h2 style="position:absolute;top:5px;left:300px">
RangeSlider Widgets</h2>
<!-- vertical rangeslider widget -->
<div style="position:absolute;top:65px;left:388px"
id="verticalRangeSlider">
<!-- these inputs are required for containing the two
Values in the range -->
<input /><input />
</div>
<!-- horizontal rangeslider widget -->
<div id="horizontalRangeSlider"
style="position:absolute;top:285px;left:300px;">
<!-- these inputs are required for containing the two
Values in the range -->
<input /><input />
</div>
</div>
您将看到我们在页面上创建了四个独立的滑块小部件,其中两个是普通滑块小部件,另外两个是范围滑块小部件。下面的 JavaScript 代码部分是将 HTML 标记转换为网页上的 Kendo 小部件。您还可以看到这些示例中的一些配置选项,我们将在接下来的几段中详细讨论。
<script>
$(document).ready(function () {
// create the vertical slider widget
$("#verticalSlider").kendoSlider({
min: -10,
max: 20,
orientation: "vertical",
smallStep: 2,
largeStep: 10,
tickPlacement: "both"
});
// create the horizontal slider widget
$("#horizontalSlider").kendoSlider({
min: 0,
max: 20,
smallStep: 1,
largeStep: 5
});
// create the vertical rangeslider widget
$("#verticalRangeSlider").kendoRangeSlider({
min: 0,
max: 20,
orientation: "vertical",
selectionStart: 2,
selectionEnd: 6,
smallStep: 1
});
// create the horizontal rangeslider widget
$("#horizontalRangeSlider").kendoRangeSlider({
min: 0,
max: 30,
selectionStart: 5,
selectionEnd: 15,
smallStep: 1,
largeStep: 5,
tickPlacement: "none"
});
});
</script>
</body>
</html>
这里是执行前面代码块的结果:
我们组织了页面上的内容,以便您可以看到不同的滑块小部件及其输出。左侧的两个滑块,一个垂直和一个水平,都是普通滑块小部件。右侧的两个滑块,一个垂直和一个水平,都是范围滑块小部件。我还调整了它们各自的属性,以便在演示中显示独特的选项。我们将在本章的其余部分中介绍这些选项。
使用 MVC 扩展方法的基本实现
以下代码示例说明了如何使用 ASP.NET MVC 扩展方法实例化这些相同的滑块。我只包括了实际的滑块小部件,而没有包含完整的 HTML 页面。
<div id="sliders">
<h2 id="slidersLabel">Slider Widgets</h2>
@(Html.Kendo().Slider().Name("verticalSlider")
.HtmlAttributes(new { id = "verticalSlider" })
.Min(-10)
.Max(20)
.Orientation(SliderOrientation.Vertical)
.Value(5)
.SmallStep(2)
.LargeStep(10)
.TickPlacement(SliderTickPlacement.None)
.Tooltip(tt =>
tt.Format("{0}")))
@(Html.Kendo().Slider().Name("horizontalSlider")
.HtmlAttributes(new { id = "horizontalSlider" })
.Min(0)
.Max(20)
.Orientation(SliderOrientation.Horizontal)
.Value(7)
.SmallStep(1)
.LargeStep(5)
.TickPlacement(SliderTickPlacement.Both))
</div>
<div id="rangeSliders">
<h2 id="rangeSlidersLabel">RangeSlider Widgets</h2>
@(Html.Kendo().RangeSlider().Name("verticalRangeSlider")
.HtmlAttributes(new { id = "verticalRangeSlider" })
.Min(0)
.Max(20)
.Orientation(SliderOrientation.Vertical)
.Values(new double[] { 2, 6 })
.SmallStep(1))
@(Html.Kendo().RangeSlider().Name("horizontalRangeSlider")
.HtmlAttributes(new { id = "horizontalRangeSlider" })
.Min(0)
.Max(30)
.Orientation(SliderOrientation.Horizontal)
.Values(new double[] { 5, 15 })
.SmallStep(1)
.LargeStep(5)
.TickPlacement(SliderTickPlacement.Both))
</div>
正如上面正常的 JavaScript 和 HTML 示例一样,这些 MVC 扩展生成的输出是相同的。所有四个滑块都带有相同的选项和配置,并且具有相同的行为。
使用工具提示和弹出文本
滑块小部件向用户提供了几个视觉提示,以指示它们的值和控制功能。有工具提示或悬停效果,指示滑块末尾的按钮将执行的操作。这些工具提示始终存在,不需要任何额外的配置或代码,尽管可以使用 API 进行自定义。以下截图显示了出现在增加按钮上的工具提示文本:
以下截图显示了出现在减少按钮上的工具提示文本:
如果存在,还有工具提示标签指示刻度值,以及指示如何通过鼠标拖动与滑块控件交互。以下截图显示了代表数字18的刻度上的工具提示文本:
以下截图显示了拖动手柄上的工具提示文本:
最后,当用户拖动范围滑块小部件的控制时,页面将显示一个标签,指示当前选定的范围。以下截图显示了所选范围内的工具提示文本,在这种情况下,显示手柄位于4和15:
学习键盘控制
还要注意,当滑块小部件在页面上获得焦点时,可以使用键盘箭头按钮和Page Up和Page Down按钮来操纵滑块控件。按下向上或向下的箭头按钮将增加或减少滑块的值,该值包含在smallStep
属性中。按下Page Up或Page Down将增加或减少滑块的值,该值包含在largeStep
属性中。
这些属性,smallStep
和largeStep
,可以在 JavaScript 中实例化滑块小部件时设置,正如我们在之前的示例代码中所看到的:
$("#verticalSlider").kendoSlider({
min: -10,
max: 20,
orientation: "vertical",
smallStep: 2,
largeStep: 10,
tickPlacement: "both"
});
数字不必是偶数,可以是任何对您的应用程序有意义的整数增量。
自定义滑块小部件的用户界面
滑块小部件的许多属性都可以用来自定义用户在网页上如何与之交互。显示在工具提示和刻度标记标签中的文本可以自定义,以显示更符合您页面需求的文本。您还可以自定义滑块的朝向及其默认值。
工具提示自定义
滑块小部件的tooltip
属性可以通过自定义格式或自定义模板进行自定义,如果不需要,也可以完全禁用。例如,假设您的滑块小部件旨在让用户选择度数(例如在温度计上)。您可以自定义工具提示的格式以反映这种独特的格式。您还会看到,当更改工具提示的格式时,数据标签的格式也会自动更改以匹配它:
$("#verticalSlider").kendoSlider({
min: -10,
max: 20,
orientation: "vertical",
smallStep: 2,
largeStep: 10,
tickPlacement: "both",
tooltip: {
format: "{0}"
}
});
默认格式是"{0}"
,因此在此之后添加度数符号,它将正确地显示在页面上:
注意标签和工具提示都更改以匹配新的格式。还要注意,我使用未 HTML 编码的度数符号添加了格式,Kendo UI 系统为我处理了适当的编码。
配置tooltip
属性的完整选项在此处显示:
// options for a kendoSlider
tooltip: {
enabled: true, // enable tooltips or not
format: "{0}", // format string for tooltips
template:{
value: "..." // template value for tooltips
}
}
}
...
// options for a kendoRangeSlider
tooltip: {
enabled: true, // enabled or not
format: "{0}", // format string for tooltips
template:{
selectionStart: "...", // template value for start range
selectionEnd: "..." // template value for end range
}
}
}
你不应该同时使用格式和模板,因为这两个属性都是为了自定义提示框的显示而设计的。模板,如你在前面的章节中看到的,需要遵循正常的 Kendo 模板语法,并且可以用来为你的滑块控件创建高度定制的提示框。
使用 MVC 扩展方法自定义提示框选项
这就是使用 ASP.NET MVC 扩展方法配置的提示框的外观。
...
.Tooltip(tt =>
tt.Enabled(true)
.Format("{0}")
.Tempalte("template would go here")) @* misspelled in the Kendo code *@
记住,就像在 JavaScript 中一样,你不会同时设置格式和模板。另外,请注意,Kendo 库拼写了一个单词,它将 "tempalte" 错误地拼写为 "template"。务必在此处检查你的代码,以防 Telerik 已经修复了拼写错误。
自定义默认值
滑块小部件可以被配置为以特定的默认值开始。对于一个普通的 Kendo 滑块小部件,这以输入 HTML 元素的 value
属性或在此处所示的 Kendo 滑块小部件的 JavaScript 初始化形式出现:
<input id="sliderId" value="4" />
... // or
$("#sliderId").kendoSlider({
value: 4,
...
}
这两种方法中的任何一种都将滑块小部件的初始值或默认值设置为数字 4
。
对于 Kendo 范围滑块,你需要设置范围的两个数字,因此你需要使用不同的属性 selectionStart
和 selectionEnd
或设置 HTML 中两个输入的值属性:
<div id="rangeSliderId">
<input value="2" />
<input value="8" />
</div>
... // or
$("#rangeSliderId").kendoRangeSlider({
selectionStart: 2,
selectionEnd: 8
...
}
这两种方法都将选择范围的开始设置为 2
,并将选择范围的结束设置为 8
。
自定义刻度放置
滑块小部件上的刻度和数据标签也可以通过选择四种支持的显示选项之一来自定义:topLeft
、bottomRight
、both
和 none
。这些是通过名为 tickPlacement
的配置属性设置的。
$("#sliderId").kendoSlider({
tickPlacement: "topLeft"
...
});
在左上角放置刻度
topLeft
刻度放置选项将在垂直滑块的左侧或水平滑块的上侧放置刻度。
$("#sliderId").kendoSlider({
tickPlacement: "topLeft"
...
});
这里是输出:
在右下角放置刻度
bottomRight
刻度放置选项将在垂直滑块的右侧或水平滑块的底部放置刻度:
$("#sliderId").kendoSlider({
tickPlacement: "bottomRight"
...
});
在两侧放置刻度
both
刻度放置选项将在滑块的两侧放置刻度:
$("#sliderId").kendoSlider({
tickPlacement: "both"
...
});
完全移除刻度
none
刻度放置选项将从滑块中移除所有刻度:
$("#sliderId").kendoSlider({
tickPlacement: "none"
...
});
自定义滑块方向
你已经看到了滑块小部件的两个方向——水平和垂直,但这里简要看看启用这两个选项所需的代码:
$(function(){
orientation: "vertical" // "horizontal" or "vertical"
...
}
注意
如果你没有设置方向,则默认方向将是水平。
学习 API 方法
与滑动组件交互时,你必须像往常一样通过 data()
方法引用 JavaScript 对象:
// Kendo Slider Widget
var slider = $("#sliderId").data("kendoSlider");
// Kendo RangeSlider Widget
var rangeSlider = $("#rangeSliderId").data("kendoRangeSlider");
启用和禁用方法
滑动组件支持通过 enable()
和 disable()
方法启用和禁用网页中的控件。假设你通过 JavaScript 正确引用了对象,这两个滑动组件和范围滑动组件的语法是相同的。
// get a reference to the slider
var slider = $("sliderId").data("kendoSlider");
// disable a slider
slider.disable();
// enable a slider
slider.enable();
禁用的滑动组件在网页上显示为部分透明或灰色。在以下屏幕截图中,左侧的滑动条是禁用的,右侧的滑动条是启用的:
使用值
滑动组件的值可以通过 JavaScript API 设置和检索。由于它们在内部使用不同数量的值,因此滑动组件和范围滑动组件的语法不同。
使用 Kendo 滑动组件的值
设置和检索 Kendo 滑动组件的值很简单,因为它只包含一个值,如下所示:
// get a reference to the slider
var slider = $("#sliderId").data("kendoSlider");
// set the value of the slider to 7
slider.value(7);
// get the value of the slider
var sliderValue = slider.value(); // returns a number
使用 Kendo 范围滑动组件的值
当设置或检索范围滑动组件的值时,你必须使用 JavaScript 数组进行通信,以便可以同时持有滑动对象中的两个值。
// get a reference to the slider
var rangeSlider = $("#rangeSliderId").data("kendoRangeSlider");
// set the values for the range slider to 2 and 8
rangeSlider.value([2,8]);
// get the values from the range slider
var sliderValues = rangeSlider.value(); // returns an object array
事件钩子
就像其他 Kendo UI 组件一样,事件处理器可以在对象实例化时绑定,或者稍后通过 JavaScript bind()
方法调用。以下示例将仅展示实例化代码。
使用变化事件
当用户通过点击箭头、使用鼠标移动滑动条或使用键盘控件更改滑动条的值时,滑动组件将触发 change
事件。
Kendo 滑动组件的变化事件
Kendo 滑动组件的 change
事件可以像以下那样绑定和使用:
$("#sliderId").kendoSlider({
change: changeHandler,
...
});
...
function changeHandler (e){
alert(e.value); // e.value contains the new value of the slider
}
e.value
属性将包含滑动组件的新值,这样你就可以在 JavaScript 代码中正确地响应事件。
Kendo 范围滑动组件的变化事件
Kendo 范围滑动组件的 change
事件可以像以下代码片段所示那样绑定。它与滑动组件的 change
事件不同,因为它将数组传递给事件处理器而不是单个值。
$("#rangeSliderId").kendoRangeSlider({
change: changeHandler,
...
});
...
fuction changeHandler (e){
alert(e.value.toString()); // e.value is an array of the new range values
}
滑动事件
slide
事件在语法上与 change
事件相同,但它仅在用户使用鼠标移动滑动条时触发,它不会对键盘事件或按钮点击触发。前面的 change
事件示例也适用于 slide
事件。
$("#sliderId").kendoSlider({
slide: changeHandler,
...
});
使用 MVC 扩展方法处理变化和滑动事件
这就是通过使用 ASP.NET MVC 扩展方法来连接事件处理器的方式。请注意,输出与之前概述的相同;这只是为了执行以下代码所需的语法;有关更多信息,请参阅前面的部分。
.Events(events => events
.Slide("slideHandler")
.Change("changeHandler"))
摘要
Kendo UI 滑块和 Kendo UI 范围滑块小部件是收集网页中输入元素的数字的非常实用的工具。当收集必须落在指定范围内的数字时,这些小部件比向用户返回关于数字无效的错误消息要友好得多。我建议在适当的地方使用它们,以使您的网站对用户来说更加有趣。
在下一章中,您将了解 Splitter 和 TreeView 小部件,这些小部件允许您将可调整大小的动态内容加载到您的页面中,并在树形显示中组织层次内容。这些小部件将帮助您构建强大的页面,可以动态处理和加载内容,并以有组织的模式显示内容。
第九章:实现分隔符和树视图小部件
在本章中,你将了解来自 Kendo UI Web 框架的两个不同小部件,即分隔符小部件和树视图小部件。分隔符小部件是一个用于在网页内部组织内容的工具。它创建网页内的块状区域,可以包含常规页面元素,甚至还可以包含额外的分隔符小部件控件以进一步细分内容区域。树视图小部件是一个用于显示以层次结构组织的数据的工具,例如在树中。这种方式组织的数据的一个很好的例子是硬盘上的文件夹结构。文件夹可以包含文件或额外的文件夹。当绘制时,这会创建一个嵌套结构,如树,非常适合树视图小部件。
分隔符小部件
Kendo UI 分隔符小部件是创建动态页面布局的强大工具。它在一个网页内生成可调整大小、可滚动、可折叠和嵌套的边框区域。这些区域建立在 div
元素之上,并扩展了这些底层 div
元素的令人印象深刻的函数。当你看到本节中如何使用此小部件时,我相信你可以想象出许多使用它的方法。
学习分隔符小部件
Kendo UI 分隔符小部件旨在将 div
HTML 元素扩展为灵活的内容区域,这些区域可以分割网页上的元素,因此得名“分隔符”。这些内容区域变为可调整大小的块,使用户可以选择页面的哪些部分应该占据更多的可见屏幕。每个这些块都可以配置特定的行为和选项,例如滚动条和通过单次点击折叠页面元素的能力。
这里有一些可以与 Kendo UI 分隔符小部件一起使用的 HTML 标记的示例。请注意 div
元素的组织和嵌套;当你看到实例化 Kendo 对象的 JavaScript 代码时,这将成为重要的一点:
<div id="outerSections" style="height: 600px">
<div id="outerTopSection" style="height: 200px">
<div id="topSubSections" class="k-pane" style="height: 200px">
<div style="height: 200px" class="k-pane"></div>
<div style="height: 200px" class="k-pane"></div>
</div>
</div>
<div id="outerMidSection" style="height: 200px" class="k-pane">
<div class="k-pane"></div>
</div>
<div id="outerBottomSection" style="height: 200px" class="k-pane">
<div id="bottomSubSections" class="k-pane" style="height: 200px">
<div style="height: 200px" class="k-pane"></div>
<div style="height: 200px" class="k-pane"></div>
<div style="height: 200px" class="k-pane"></div>
</div>
</div>
</div>
最外层的 div
,其 id
值为 outerSections
,在其标签之间包含三个 div
元素。你还可以看到,这些位于 outerSections
div
之下的每个 div
元素都包含自己的子 div
元素。这些子元素将成为更大 outerSections
区域内的 Kendo UI 分隔符小部件部分。其中两个子 div
元素,topSubSections
和 bottomSubSections
,还包含一个更进一步的嵌套层次结构,它将成为分别在 outerTopSection
和 outerBottomSection
区域内的嵌套 Kendo UI 分隔符小部件部分。
在此 JavaScript 代码块中,你可以看到创建了三个独立的 kendoSplitter
小部件。第一个 Splitter 小部件按垂直顺序组织;它是最外层区域,并将包含以下两个 Splitter 小部件对象。第二个和第三个 Splitter 小部件区域按水平组织,并嵌套在其他 Splitter 小部件对象中,正如你将在以下屏幕截图中所看到的:
<script type="text/javascript">
$(function () {
$("#outerSections").kendoSplitter({
orientation: "vertical",
panes: [
{ collapsible: false, size: "200px", scrollable: false },
{ collapsible: false, size: "200px", scrollable: false },
{ collapsible: false, size: "200px", scrollable: false }
]
});
$("#topSubSections").kendoSplitter({
orientation: "horizontal",
panes: [
{ collapsible: true, scrollable: false },
{ collapsible: true, scrollable: false }
]
});
$("#bottomSubSections").kendoSplitter({
orientation: "horizontal",
panes: [
{ collapsible: true, scrollable: false },
{ collapsible: true, scrollable: false },
{ collapsible: true, scrollable: false }
]
});
});
</script>
你可以看到三个垂直堆叠在页面上的 Splitter 小部件区域。最上面的区域包含其中两个水平堆叠的区域。最下面的区域包含三个水平堆叠的区域。这些都与你刚才看到的 HTML 和 JavaScript 代码相匹配。
加载内容
你刚才看到的 Splitter 小部件区域的内容都是空的,只是为了演示。然而,这并不是必要的。内容区域可以包含所有 div
元素通常包含的正常 HTML 内容。例如,你可以在以下代码片段中填充一些区域,如下所示:
<div id="topSubSections" class="k-pane" style="height: 200px">
<div style="height:200px" class="k-pane">
Lorem ipsum dolor sit amet, consectetur adipisicing elit...
</div>
<div style="height:200px" class="k-pane">
Lorem ipsum dolor sit amet, consectetur adipisicing elit...
</div>
</div>
此文本现在将出现在 Splitter 小部件框内,并根据需要调整大小或折叠:
使用 AJAX 加载内容
通过 AJAX 调用来填充这些 Splitter 小部件区域内容的一种更可配置的方法是加载它。要启用此功能,只需使用定义 Splitter 小部件内容区域的 JavaScript 对象字面量的 contentUrl
属性,并通过 AJAX 指定要加载的页面。Kendo UI 框架将为您处理其余部分。
$("#bottomSubSections").kendoSplitter({
orientation: "horizontal",
panes: [
{ collapsible: true, scrollable: false },
{ collapsible: true, scrollable: false },
{ collapsible: true, scrollable: false,
contentUrl: "LoremIpsum.html" }
]
});
钩入 Splitter 事件
Kendo UI Splitter 小部件配备了一系列丰富的行为。这些行为中的大多数,无论是通过用户操作还是通过方法调用执行,都会触发一个事件。像 JavaScript 中的任何事件一样,你可以将这些事件附加到自己的事件处理器函数,并使用自己的自定义代码对这些动作做出响应。本节将展示 Kendo UI Splitter 小部件上可用的不同事件,并演示如何将其钩入。
折叠(collapse)事件
当用户通过点击两个窗格之间的折叠图标来折叠 Kendo UI Splitter 小部件的某个部分时,将触发 collapse
事件。此图标显示为一个指向 collapse
动作将移动的方向的小三角形。以下是将 collapse
事件与事件处理器连接的代码:
// Binding during Splitter Widget creation
$("#splitterElement").kendoSplitter({
...
collapse: collapseEventHandler
...
});
// Dynamic binding and unbinding
var splitter = $("#splitterElement").data("kendoSplitter");
splitter.bind("collapse", collapseEventHandler);
spliter.unbind("collapse", collapseEventHandler);
contentLoad 事件
当内容被加载到 Kendo UI Splitter 小部件的窗格中时,将触发 contentLoad
事件。此事件的正常用途是在 AJAX 内容从远程源完成加载时做出反应。以下是将 contentLoad
事件与事件处理器连接的代码:
// Binding during Splitter Widget creation
$("#splitterElement").kendoSplitter({
...
contentLoad: contentLoadEventHandler
...
});
// Dynamic binding and unbinding
var splitter = $("#splitterElement").data("kendoSplitter");
splitter.bind("contentLoad", contentLoadEventHandler);
spliter.unbind("contentLoad", contentLoadEventHandler);
展开(expand)事件
当用户点击展开图标将 Kendo UI Splitter 小部件的面板展开时,将触发 expand
事件。当面板折叠后,此图标将显示为一个指向面板展开方向的三角形,如下所示:
以下是将 expand
事件与事件处理程序连接的代码:
// Binding during Splitter Widget creation
$("#splitterElement").kendoSplitter({
...
expand: expandEventHandler
...
});
// Dynamic binding and unbinding
var splitter = $("#splitterElement").data("kendoSplitter");
splitter.bind("expand", expandEventHandler);
spliter.unbind("expand", expandEventHandler);
layoutChange
事件
当 Kendo UI Splitter 小部件的布局发生变化时,将触发 layoutChange
事件。此事件比 expand
、collapse
和 resize
更通用,因此它通常与这些事件一起出现,因为所有这些事件也都表示布局已更改。以下是将 layoutChange
事件与事件处理程序连接的代码:
// Binding during Splitter Widget creation
$("#splitterElement").kendoSplitter({
...
layoutChange: layoutChangeEventHandler
...
});
// Dynamic binding and unbinding
var splitter = $("#splitterElement").data("kendoSplitter");
splitter.bind("layoutChange", layoutChangeEventHandler);
spliter.unbind("layoutChange", layoutChangeEventHandler);
resize
事件
当用户拖动两个 Kendo UI Splitter 小部件面板之间的手柄以调整它们的大小时,将触发 resize
事件。此事件在 collapse
和 expand
期间也会被触发。以下是将 resize
事件与事件处理程序连接的代码:
// Binding during Splitter Widget creation
$("#splitterElement").kendoSplitter({
...
resize: resizeEventHandler
...
});
// Dynamic binding and unbinding
var splitter = $("#splitterElement").data("kendoSplitter");
splitter.bind("resize", resizeEventHandler);
spliter.unbind("resize", resizeEventHandler);
调用 Splitter API 方法
Kendo UI Splitter 小部件配备了一系列方法,使其具有丰富的行为。大多数这些方法在触发时都会引发一个事件。像 JavaScript 中的任何事件一样,您可以将自己的事件处理程序函数附加到这些事件上,并使用自己的自定义代码响应用户的操作。本节将展示 Kendo UI Splitter 小部件上可用的不同方法。
获取 Splitter 对象的引用
在处理所有 Kendo UI 小部件上的方法时,首先要记住的是,在可以使用这些方法之前,您必须获取 JavaScript 对象的引用。为此,您必须使用 JavaScript 方法 .data()
。以下是一个示例:
var splitter = $("#splitterElement").data("kendoSplitter");
注意 jQuery 如何用于选择 Kendo UI Splitter 小部件创建的 Document Object Model (DOM) 元素,然后使用参数文本 kendoSplitter
调用 .data()
函数,以指示我们试图获取的对象类型。现在,已经检索到 Kendo UI Splitter 小部件实例,可以直接从 splitter
变量调用方法。
splitter.collapse("#outerPane");
使用 ajaxRequest
方法
ajaxRequest
方法用于将 AJAX 内容加载到特定的 Kendo UI Splitter 小部件面板中。此方法接受三个参数。第一个参数是一个字符串,用于选择应将 AJAX 内容加载到其中的特定面板。它使用 jQuery 语法来选择元素,因此要选择具有 id
值为 pane1
的元素,您将使用 #pane1
来选择它。第二个参数是包含要加载到面板中的内容的远程端点的 URL。第三个参数是可选的,如果远程端点需要参数以发送数据并返回数据,则用于向远程端点发送数据。以下是一个展示此方法如何工作的代码示例:
// Get a reference to the Kendo UI Splitter Widget
var splitter = $("#splitterElement").data("kendoSplitter");
// Call the ajaxRequest method
splitter.ajaxRequest("#pane1", "someContent.html");
注意
注意,此方法将导致 contentLoad
事件被触发。
使用折叠方法
collapse
方法用于折叠特定 Kendo UI Splitter 小部件面板。此方法接受一个参数。该参数是一个字符串,用于选择应该被折叠的特定面板。它使用 jQuery 语法来选择元素,因此要选择具有id
值为pane2
的元素,您将使用#pane2
来选择它。以下是一个方法操作的代码示例:
// Get a reference to the Kendo UI Splitter Widget
var splitter = $("#splitterElement").data("kendoSplitter");
// Call the collapse method
splitter.collapse("#pane2");
注意
注意,此方法将导致layoutChange
和resize
事件被触发,但由于用户没有使用鼠标发起操作,因此不会触发collapse
事件。
使用展开方法
expand
方法用于展开特定 Kendo UI Splitter 小部件面板。此方法接受一个参数。该参数是一个字符串,用于选择应该被展开的特定面板。它使用 jQuery 语法来选择元素,因此要选择具有id
值为pane2
的元素,您将使用#pane2
来选择它。以下是一个方法操作的代码示例:
// Get a reference to the Kendo UI Splitter Widget
var splitter = $("#splitterElement").data("kendoSplitter");
// Call the expand method
splitter.expand("#pane2");
注意
注意,此方法将导致layoutChange
和resize
事件被触发,但由于用户没有使用鼠标发起操作,因此不会触发expand
事件。
使用最大和最小方法
max
和min
方法用于设置特定 Kendo UI Splitter 小部件面板的最大或最小大小。这些方法接受两个参数。第一个参数是一个字符串,用于选择将被配置的特定面板。它使用 jQuery 语法来选择元素,因此要选择具有id
值为pane3
的元素,您将使用#pane3
来选择它。第二个参数是一个表示新最大或最小大小的字符串值。此值表示为像素数或百分比。以下是一个方法操作的代码示例:
// Get a reference to the Kendo UI Splitter Widget
var splitter = $("#splitterElement").data("kendoSplitter");
// Call the max method
splitter.max("#pane3", "300px");
// Call the min method
splitter.min("#pane3", "25%");
注意
注意,此方法不会触发任何事件。
使用大小方法
size
方法用于设置特定 Kendo UI Splitter 小部件面板的大小。此方法接受两个参数。第一个参数是一个字符串,用于选择将被配置的特定面板。它使用 jQuery 语法来选择元素,因此要选择具有id
值为pane4
的元素,您将使用#pane4
来选择它。第二个参数是一个表示新大小的字符串值。此值表示为像素或百分比。它必须在最大和最小大小值范围内。以下是一个方法操作的代码示例:
// Get a reference to the Kendo UI Splitter Widget
var splitter = $("#splitterElement").data("kendoSplitter");
// Call the size method
splitter.size("#pane4", "300px");
注意
注意,此方法将导致layoutChange
和resize
事件被触发。
使用切换方法
toggle
方法用于在特定 Kendo UI Splitter 小部件的面板之间切换折叠和展开状态。如果面板当前是展开的,则 toggle
方法将折叠它。如果面板当前是折叠的,则 toggle
方法将展开它。此方法接受两个参数。第一个参数是一个字符串,用于选择将被切换的特定面板。它使用 jQuery 语法来选择元素,因此要选择一个 id
值为 pane5
的元素,你会使用 #pane5
来选择它。第二个参数是一个可选的布尔值(true
或 false
),它指示面板应设置为的特定状态,而不考虑其当前状态。true
的值将面板设置为展开状态。false
的值将面板设置为折叠状态。以下是一个方法操作的代码示例:
// Get a reference to the Kendo UI Splitter Widget
var splitter = $("#splitterElement").data("kendoSplitter");
// Call the toggle method
splitter.toggle("#pane5");
// Force the pane to expand
splitter.toggle("#pane5", true);
// Force the pane to collapse
splitter.toggle("#pane5", false);
注意
注意,这种方法将导致 layoutChange
和 resize
事件被触发,但它不会触发 collapse
或 expand
事件。
TreeView
Kendo UI TreeView 小部件在你需要显示组织成层次结构的数据时非常有用。硬盘上的文件和商业组织结构是这种组织方式数据的良好例子。数据有一个顶级元素(例如根文件夹或首席执行官),然后在该顶级元素下有多个单个元素(例如文件或员工)和组(例如文件夹或部门)。每个组可以进一步分组,使得最终的图表可以想象为一棵树,有一个根和许多分支(元素组),这些分支多次分割,最终以叶子(单个元素)结束。正如你可以想象的那样,这种类型的数据并不总是很容易在网页上可视化和布局。幸运的是,Kendo UI TreeView 小部件作为显示这种数据的简单方式,提供了丰富的交互和配置选项。
学习 TreeView
Kendo UI TreeView 小部件旨在与嵌套在 HTML 无序列表中的数据一起工作。这些对于 TreeView 的工作来说是一个自然的匹配,因为它们可以像 Kendo UI 想要显示和组织的那样进行层次嵌套。与组织数据的其他 Kendo UI 小部件类似,TreeView 小部件可以创建在已经渲染到网页上的 HTML 之上,或者当通过数据源对象提供数据时,它可以自己构建 HTML。以下是一个在预渲染的 HTML 上实例化 Kendo UI TreeView 小部件的简单示例:
<div class="demo-section">
<ul id="treeview">
<li data-expanded="true">
Organization Chart
<ul>
<li data-expanded="true">
Administration
<ul>
<li>Office Manager</li>
<li>Resource Manager</li>
<li>Administrative Assistant</li>
</ul>
</li>
<li data-expanded="true">
Consulting
<ul>
<li data-expanded="true">
Software Development
<ul>
<li>Desktop Applications</li>
<li>Web Applications</li>
</ul>
</li>
<li>Business Intelligence</li>
</ul>
</li>
<li>Special Projects</li>
<li>Portals and Collaboration</li>
</ul>
</li>
</ul>
</div>
<script>
$(document).ready(function () {
$("#treeview").kendoTreeView();
});
</script>
此页面显示按部门和职位功能分类的组织结构图。正如你在下面的屏幕截图中所看到的,Kendo UI TreeView 小部件很好地展示了这一点。HTML 能够在没有 Kendo UI 框架的帮助下渲染层次数据,但普通的 HTML 不提供可折叠的部分或其他你将在本节中继续阅读时看到的特殊行为。
绑定到数据源
正如您刚才看到的,Kendo UI TreeView 小部件旨在在现有 HTML 标记之上工作,或者它可以绑定到 JavaScript 数据源。与其他旨在显示和组织数据的 Kendo UI 小部件类似,此数据最好包含在支持 Kendo 框架内许多固有功能的 Kendo DataSource
对象中。要以前述方式显示您之前看到的页面,可以使用以下代码:
<script>
$(document).ready(function () {
var orgChart = [{
text: 'Organization Chart', expanded: true, items: [
{ text: 'Administration', expanded: true, items: [
{ text: 'Office Manager' },
{ text: 'Resource Manager' },
{ text: 'Administrative Assistant' }
]
},
{ text: 'Consulting', expanded: true, items: [
{
text: 'Software Development', expanded: true, items: [
{ text: 'Desktop Applications' },
{text: 'Web Applications'}
]
},
{text: 'Business Intelligence'}
]
},
{ text: 'Special Projects' },
{ text: 'Portals and Collaboration' }
]
}];
$("#treeview").kendoTreeView({
dataSource: orgChart
});
});
</script>
注意到每个元素都可以通过 items
属性包含自己的子元素列表,例如 软件开发
组包含两个子元素:桌面应用程序
和 Web 应用程序
。这些子元素也可以包含自己的子元素列表,依此类推。这就是数据树的形成方式,也是 Kendo UI TreeView 小部件如何将数据处理成网页上的图形树的方式。与任何 Kendo DataSource
连接一样,数据可以绑定到远程源,而无需在页面上硬编码。
使用拖放功能
由于 Kendo UI TreeView 小部件通过 Kendo 框架启用了特殊功能,因此它能够执行比标准 HTML 无序列表更多的操作。其中一项特殊功能是 dragAndDrop
。当此功能在 Kendo UI TreeView 小部件上启用时,用户可以点击 TreeView 中的某个元素,并将其拖动到 TreeView 上的任何其他位置。不仅如此,如果同一页面上有多个启用了拖放功能的 TreeView 小部件,用户还可以将元素从一个 TreeView 小部件拖动到另一个!要启用此功能,您只需将 Kendo UI TreeView 小部件的 dragAndDrop
属性设置为 true
。
$(document).ready(function() {
$("#treeview").kendoTreeView({
dataSource: files,
dragAndDrop: true
});
});
当此功能被启用时,TreeView 小部件的元素会在鼠标悬停时显示暗色背景,以帮助指导用户它们是可交互的。当拖动 TreeView 中的元素时,旁边会出现一个图标,以帮助指示鼠标按钮释放时将发生什么操作。+ 符号表示将项目添加到层次结构部分,如下面的截图所示:
然而,如果鼠标悬停在将项目留在列表中的位置,图标将变为类似短项目列表的图片。同时,列表中会出现一条小线,以指示项目将被放置的位置,如下所示:
配置动画效果
你可能已经注意到,Kendo UI TreeView 小部件在树布局的每个部分旁边放置了小三角形图标,其中包含其他项目下的项目。如果你用鼠标点击这些三角形图标之一,该部分将折叠成隐藏状态或展开成可见状态。当这种隐藏和可见之间的转换发生时,Kendo UI 框架会使用一些效果来动画化它,使其视觉上吸引人。这些效果可以根据你自己的个人偏好进行配置:
$("#treeview").kendoTreeView({
...
animation: {
expand: { // configure the expand animation
duration: 200, // milliseconds of animation
hide: false, // ?
show: true, // ?
effects: "expandVertical fadeIn" // one or both of these
},
collapse: { // configure the collapse animation
duration: 200, // milliseconds of animation
hide: false, // ?
show: true, // ?
effects: "fadeOut" // "fadeOut" is the only option here
}
}
...
});
显示图片
Kendo UI TreeView 小部件旨在为你的内容提供吸引人的布局。为此,Kendo UI 框架内置了对在 TreeView 小部件内部显示小图片的支持,这些图片位于你显示的项目旁边。这可以通过两种方式之一完成。第一种方式是为你想要显示的每个图片使用单独的图像文件。第二种方式是使用包含多个图像的 CSS 图标精灵图像,这些图像通过一定数量的像素偏移。
要在 Kendo UI TreeView 小部件中使用单个图像文件,你可以使用 TreeView 项目的 imageUrl
属性。以下是如何在代码中显示它的示例:
var orgChart = [{
text: 'Organization Chart', expanded: true, items: [
{
text: 'Administration', expanded: true,
imageUrl: '/Images/icon-organizational-chart.gif',
items: [
{ text: 'Office Manager' },
{ text: 'Resource Manager' },
{ text: 'Administrative Assistant' }
]
},
{
text: 'Consulting', expanded: true,
imageUrl: '/Images/icon-organizational-chart.gif',
items: [
{
text: 'Software Development', expanded: true, items: [
{ text: 'Desktop Applications' },
{text: 'Web Applications'}
]
},
{text: 'Business Intelligence'}
]
},
{
text: 'Special Projects',
imageUrl: '/Images/icon-organizational-chart.gif',
},
{
text: 'Portals and Collaboration',
imageUrl: '/Images/icon-organizational-chart.gif',
}
]
}];
使用这样的图片渲染图形与 TreeView 小部件的左侧直接对齐,与每个带有 imageUrl
属性的 TreeView 项目的文本一起,如以下截图所示:
使用 TreeView 小部件中的图片的另一种方法是引用 CSS 图标精灵图像文件。通过使用精灵图像,你可以减少网页调用服务器以获取单独图像文件的次数,这可以提高你网站的性能。如果你有一个包含你的图像的精灵图像,你可以在代码中如下引用它:
<style type="text/css">
.org{
background-image: url('/Images/icon-organizational-chart.gif');
max-height: 25px;
max-width: 25px;
}
</style>
<script>
$(document).ready(function () {
var orgChart = [{
text: 'Organization Chart', expanded: true, items: [
{
text: 'Administration', expanded: true,
spriteCssClass: 'org',
items: [
{ text: 'Office Manager' },
{ text: 'Resource Manager' },
{ text: 'Administrative Assistant' }
]
},
...
使用这样的精灵渲染图形与 TreeView 小部件的左侧直接对齐,与每个带有 imageUrl
属性的 TreeView 项目的文本一起,类似于之前图像的渲染方式。
使用模板
Kendo UI TreeView 小部件高度可配置。除了能够添加图片和精灵,正如你在上一节中看到的,它还可以通过使用 Kendo 模板进行自定义。这些模板可以用来创建任何你想要的显示的可定制显示。例如,考虑以下代码示例,它用于创建一个特殊的 TreeView 显示,其中每个项目旁边都有图标,可以点击以从 TreeView 显示中删除项目:
<script id="treeview-template" type="text/kendo-ui-template">
#: item.text #
# if (!item.items) { #
<a class='delete-link' href='\#'>[x]</a>
# } #
</script>
<script>
$("#treeview").kendoTreeView({
template: kendo.template($("#treeview-template").html()),
...
});
// Delete button behavior
$(document).on("click", ".delete-link", function(e) {
e.preventDefault();
var treeview = $("#treeview").data("kendoTreeView");
treeview.remove($(this).closest(".k-item"));
});
</script>
首先,注意代码示例顶部的模板块。模板指定了要显示项目文本。然后,只有当项目下没有集合时,才会显示可以点击以从 TreeView 小部件中删除项目的锚点链接。其次,注意模板是通过template
属性在 TreeView 设置代码中设置的。最后,注意锚点链接的行为是通过事件处理器连接的。从 TreeView 中删除项目的函数依赖于 TreeView API,并且必须使用 JavaScript 连接。以下是这种方式在网页上的截图:
连接到 TreeView 事件
在其操作过程中,Kendo UI TreeView 小部件会触发几种不同类型的事件。这些事件为您,即开发者,提供了在 TreeView 运行时执行自己的代码的机会。其中一些动作与用户的直接参与有关,例如当用户点击某物时。还有一些动作更为间接,当 TreeView 小部件改变其状态时触发,例如当它加载内容时。由于与 TreeView 小部件相关的事件有很多,我们将在此处简要描述每个事件:
-
collapse
:当用户点击一个箭头图标导致 TreeView 小部件的某个部分折叠时,会触发collapse
事件。 -
dataBound
:在处理数据源更改事件之后,会触发dataBound
事件,例如当向数据源添加或删除项目,或者当数据源最初被填充时。 -
drag
:当项目从 TreeView 小部件中拖动或在其内部拖动时,会触发drag
事件。drag
事件向事件处理器提供了关于其位置的许多非常具体的细节,这些细节可以在您的自定义代码中使用。 -
dragEnd
:当拖动操作结束时,项目被释放并重新插入到一个新的位置到 TreeView 小部件中时,会触发dragEnd
事件。 -
dragStart
:当用户开始从 TreeView 小部件拖动一个项目时,会触发dragStart
事件。 -
drop
:在拖动操作后,项目被放下时,会触发drop
事件。drop
事件向事件处理器提供了关于其位置的许多非常具体的细节,这些细节可以在您的自定义代码中使用。 -
expand
:当用户点击一个箭头图标导致 TreeView 小部件的某个部分展开时,会触发expand
事件。 -
select
:当用户通过鼠标点击节点来选择节点时,会触发select
事件。 -
navigate
:当焦点从页面上的一个 TreeView 节点转移到其他元素时,会触发navigate
事件。
调用 TreeView API 方法
Kendo UI TreeView 小部件配备了丰富的功能方法,这些方法使其行为更加丰富。这些方法允许您以 TreeView 小部件支持的所有方式手动操作该小部件。通过使用这些 API 方法,您可以按照应用程序的需求配置和激活 TreeView 小部件。就像刚刚讨论的事件部分一样,TreeView 小部件支持许多方法。我将在这里列出所有这些方法,并附上简要说明:
-
append
:append
方法将一个元素追加到现有 TreeView 小部件部分的末尾。 -
collapse
:collapse
方法折叠展开的 TreeView 小部件部分。 -
dataItem
:dataItem
方法检索绑定到 TreeView 小部件元素的模型数据项。 -
enable
:enable
方法启用或禁用 TreeView 小部件元素。 -
expand
:expand
方法展开折叠的 TreeView 小部件部分。 -
findByText
:findByText
方法通过其文本值查找 TreeView 元素。 -
findByUID
:findByUID
方法通过其UID
值查找 TreeView 元素。 -
insertAfter
:insertAfter
方法在 TreeView 小部件中指定的元素之后插入一个新元素。 -
insertBefore
:insertBefore
方法在 TreeView 小部件中指定的元素之前插入一个新元素。 -
parent
:parent
方法检索 TreeView 小部件中元素的父元素。 -
remove
:remove
方法从 TreeView 小部件中删除一个元素。 -
select
:select
方法将 TreeView 小部件中的元素标记为选中。 -
setDataSource
:setDataSource
方法设置 TreeView 小部件的数据源。 -
text
:text
方法可以获取或设置 TreeView 小部件中元素的文本值。 -
toggle
:toggle
方法折叠展开的 TreeView 部分或展开折叠的 TreeView 部分。
摘要
在开发网页的过程中,Kendo UI Splitter 和 Kendo UI TreeView 小部件提供了许多功能。Splitter 小部件是一个组织可折叠、可展开和可调整大小的内容部分的出色工具。这种类型的功能通常并不那么容易实现。TreeView 小部件提供了一个功能丰富的分层无序列表版本,具有一些非常实用的图形功能、可折叠的树部分以及大量方法和事件。这两个小部件都应该为您的网站增添很多价值。
在下一章中,您将了解 Kendo UI Web 框架中的两个最终小部件:Window 和 Upload 小部件。Window 小部件允许您创建和管理具有专用内容的模态弹出页面。Upload 小部件为传统的 HTML 上传元素提供了一组更丰富的功能,为您的网站用户提供了一个出色的文件上传体验。
第十章。上传和窗口小部件
现代网络应用已经发展到文件上传和对话框已经从简单的、不吸引人的 HTML 元素发展成交互式和可定制的控件。然而,这种强大的功能并非免费提供;它需要编写良好的 JavaScript 和 CSS 样式。Kendo UI Web 框架提供了预构建的控件,让您几乎无需努力就能获得这种功能。本章将探讨这些控件并说明它们的使用。
上传文件
文件上传在网页中一直是一个笨拙的元素。上传多个文件的经验更糟糕,通常需要多个 HTML 上传元素,这迫使用户为每个文件点击一个单独的按钮。Kendo UI 框架提供了一个专门的 Upload 小部件,它帮助用户和开发者在这个过程中。用户不再需要为每个文件点击按钮,他们只需将所需数量的文件拖放到网页上,文件就会自动上传,并在后台异步上传。同样,开发者也可以编程以同时接收多个文件,并通过 JavaScript 接收文件上传,而不会使网页变慢和失去响应。
学习 Upload 小部件
由于 Upload 小部件旨在将一个或多个文件的 内容上传到服务器,因此即使是最基本的此小部件实现也需要一个可以接受文件上传的服务器。您可以通过使用您的 ASP.NET MVC 项目来实现这一点。为了接收文件上传,您需要创建一个接受IEnumerable<HttpPostedFileBase>
作为输入参数的动作方法。以下是如何服务器从 Kendo UI Upload 小部件接收文件的方式:
// Action method to receive uploaded files
[HttpPost] // This attribute guarantees that only
// Form POST requests can call this action method
public ActionResult Submit(IEnumerable<HttpPostedFileBase> files)
{
if (files != null)
{
// ...
// Process the files and save them
// ...
}
return View();
}
在此服务器代码到位以接收上传的文件后,您现在可以构建一个页面,该页面将托管 Kendo UI Upload 小部件,用户将从中选择要上传的文件。以下代码示例显示了一个已配置为 Kendo UI Upload 小部件使用的 HTML 表单。请注意,该表单有两个必需的输入元素:一个文件输入和一个提交输入。这些是您在任何上传文件的表单中都应该期望的正常输入元素,但在此情况下,还有一个script
元素,它在文件上传元素上创建了一个特殊的 Kendo UI Upload 小部件。
这里是 index 视图的 HTML:
<form method="post" action="submit" style="width:45%">
<div>
<input name="files" id="files" type="file" /> // HTML file upload
<p>
<input type="submit" value="Submit" class="k-button" /> // Submit button
</p>
</div>
</form>
<script>
$(document).ready(function() {
$("#files").kendoUpload(); // Create the Kendo Upload Widget
});
</script>
以下是如何在真实网页上显示此标记。请注意,文件输入元素显示为按钮,而不是您在默认 HTML 中看到的正常样式。
在所有这些准备就绪后,您可以点击选择按钮来选择要上传到服务器的文件。一旦您选择了该文件并点击确定,服务器将接收该文件,并执行您在服务器端代码中设置的任何处理指令。
上述截图显示了将在用户的计算机上出现的文件选择对话框,以便用户可以选择要上传的文件。
通过在接收上传文件的 action
方法代码中添加断点,您可以看到 ASP.NET MVC 如何使用 Visual Studio 2012 解释已提交的数据。以下是一个已上传文件及其显示上传文件信息的对象的截图。在这种情况下,我上传了一个名为 Reflection.linq
的小文本文件。您可以看到,Web 服务器已成功接收文件,并且能够按您所需的方式处理它。此截图显示了处于调试模式的 Visual Studio,它允许我们查看对象内部状态。此外,在此截图中,我们可以看到 IEnumerable<HttoPostedFileBase>
中的第一个对象是一个具有 FileName
属性值为 Reflection.linq
的文件:
启用异步上传
尽管我们刚才看到的上传体验已经比传统的 HTML 上传元素更优越,但体验可以变得更好。JavaScript 现在能够异步发送文件上传,或在后台发送,这意味着用户不需要提交导致页面重新加载的表单。换句话说,这个过程可以运行得更快、更顺畅,并且需要更少的参与。要启用此功能,您只需将 async
配置属性添加到 Kendo Upload 小部件实例化块中。以下代码示例显示了如何操作:
<form method="post" action="submit" style="width:45%">
<div>
<input name="files" id="files" type="file" />
<p>
<input type="submit" value="Submit" class="k-button" />
</p>
</div>
</form>
<script>
$(document).ready(function() {
$("#files").kendoUpload(
{
async: { // async configuration
saveUrl: "save", // the url to save a file is '/save'
removeUrl: "remove", // the url to remove a file is '/remove'
autoUpload: true // automatically upload files once selected
}
}
);
});
</script>
此功能还需要对服务器进行一些更改。尽管大多数代码与早期示例相同,但此动作方法返回 ContentResult
而不是 ActionResult
,因为此动作方法不会将新的网页发送回浏览器。相反,它发送回一个字符串结果,通知网页中的 JavaScript 文件上传(们)已成功完成。如果文件上传(们)出现错误,服务器将发送一个错误代码,例如代码 500
内部服务器错误。
public ContentResult Save(IEnumerable<HttpPostedFileBase> files)
{
// The Name of the Upload component is "files"
if (files != null)
{
foreach (var file in files)
{
// ...
// Process the files and save them...
// ...
}
// Return an empty string to signify success
return Content("");
}
同时上传多个文件
默认情况下,Kendo UI 上传小部件允许同时上传多个文件,但您可以在以下代码示例中明确指定此设置:
<script>
$(document).ready(function() {
$("#files").kendoUpload(
{
multiple: true
}
);
});
</script>
要上传多个文件,请在上传窗口中点击文件时按住 Ctrl 键。查看以下截图,以显示一次性选中的多个文件。当您点击 OK 按钮,所有文件将一起上传到服务器,并作为一个单一事务进行处理。不再需要多个按钮和对话框!
删除已上传的文件
当使用 Kendo UI 上传小部件上传文件时,你会在页面的文件上传区域看到文件名列表。如果你使用的是标准上传行为,而不是async
配置,页面上列出的文件尚未上传到服务器。相反,它们的文件名已被存储,以备你点击页面的提交按钮时附加到 HTML 上。以下截图显示了已标记为上传的文件列表;它们尚未发送到服务器:
由于这些文件尚未上传,你可以点击任何这些文件旁边的移除按钮来从列表中移除它们,而不会产生任何副作用。然而,如果你使用的是异步文件上传功能,文件将立即上传到服务器,并且无法在完全上传之前移除它们。正如你在下一个截图中所见,这个文件已经异步加载到服务器,并且已经被服务器代码保存到某个地方:
仍然有方法可以移除文件,但这需要在服务器上添加一些额外的代码来实现。具体来说,为了移除异步自动上传的文件,需要另一个控制器动作方法。这个动作方法接收一个包含一个或多个文件名的列表,并将它们从服务器上删除,因为这些文件已经上传并保存。当页面上点击移除按钮时,Kendo UI 上传小部件会自动调用此方法。
public ContentResult Remove(string[] fileNames)
{
// The parameter of the Remove action must be called "fileNames"
if (fileNames != null)
{
foreach (var fullName in fileNames)
{
// ...
// delete the files
// ...
}
}
// Return an empty string to signify success
return Content("");
}
跟踪上传进度
当文件正在异步上传时,你可以通过文件名下方的进度条和一个旋转的点状圈来查看上传进度,这表明操作仍在进行中。以下截图显示了正在进行的文件上传:
取消正在进行的更新
当文件正在异步上传时,进度条旁边会出现一个按钮,用于取消上传。如果你点击此按钮,它将尝试取消正在进行的异步上传。你应该注意,取消异步上传并不总是成功的。大多数文件上传都非常快,你很可能无法及时取消。此外,即使你能够及时点击取消按钮,后台线程在响应取消之前,这个过程仍会持续一段时间。这只是为了说明,取消文件上传可能有效,但也可能无效,并且很难预测结果。
使用文件拖放
如果您正在使用异步文件上传功能,还有一个您可以利用的特殊功能。由于异步文件上传通过 JavaScript 立即处理文件,因此网页可以启用一些特殊行为,例如使用鼠标将文件拖放到页面上。此功能默认启用,因此您无需进一步配置即可利用它。您只需从您的计算机中拖动一个文件并将其拖放到 Kendo UI Upload 小部件所在的屏幕上。当您将文件拖动到页面上时,您将看到页面通过显示一些文本来响应用户,指示用户将文件放在何处。当文件放下时,上传立即开始。
Kendo UI Window 小部件
JavaScript 长期以来一直支持可以发送消息到网页用户的弹出窗口。这些消息可以是用户可以看到的简单文本,可以是请求权限的确认框,有时甚至可以提示用户输入一些信息。当然,这些弹出消息有两个大问题。首先,它们不够吸引人,看起来像系统消息而不是网站的一部分。其次,它们在过去被过度使用和滥用,以至于许多用户完全禁用了它们,或者养成避免使用它们的习惯,因为它们最多是令人烦恼的,最坏的情况是潜在的安全风险。
现代网络程序员已经找到了这个问题的解决方案。已经创建了可以创建不同类型弹出消息的 JavaScript 框架。他们没有使用 JavaScript 过去使用的实际系统提示,而是找到了一种方法来显示悬停的 HTML div
元素,这些元素根本不是弹出消息,而是可以按需隐藏或显示的页面真实部分。Kendo UI Window 小部件是构建这些漂亮的悬停页面元素的工具。
由于这项技术的核心概念是隐藏和显示特定的 HTML div
元素,因此此小部件的基本用法就是直接在 div
标签上创建一个 Kendo UI Window 小部件。这将使其在准备显示之前隐藏,一旦准备显示,它将以悬停元素的形式动画化显示在页面的其余部分上方。以下代码示例提供了一个基本示例:
<div id="window">
<p>Windows Azure is a cloud computing platform
and infrastructure, created by Microsoft, for building,
deploying and managing applications and services through
a global network of Microsoft-managed datacenters.
It provides both platform as a service (PaaS) and
infrastructure as a service (IaaS) services and supports
many different programming languages, tools and frameworks,
including both Microsoft-specific and third-party software
and systems. Windows Azure is Microsoft's competing product
to Amazon's AWS cloud computing platform, Google App Engine,
and other systems.</p>
</div>
<button id="windowButton">See Details</button>
<script>
$(document).ready(function() {
$("#window").kendoWindow({
width: "600px",
title: "About Windows Azure",
close: onClose
});
var onClose = function(){
$("#windowButton").show();
};
$("#windowButton").on("click", function(){
$("#window").data("kendoWindow").open();
$("#windowButton").hide();
});
});
</script>
您可以看到 Kendo UI Window 小部件是如何在具有 id
值为 window
的 HTML 元素上创建的。ID 为 windowButton
的按钮被连接到打开 Window 小部件,事件处理程序在 Window 小部件打开时隐藏此按钮,并在 Window 小部件关闭时再次显示它。
您的 div
中的标记将是窗口小部件出现时的标记。这意味着您的所有样式和布局都将以与页面其余部分相同的方式正确显示;没有断开连接。以下是代码在页面上呈现的样子。请注意,Kendo UI 窗口小部件的内容尚未显示,必须首先通过事件激活;在这种情况下,该事件是点击显示窗口按钮:
这是激活时的 Kendo UI 窗口小部件的外观:
自定义窗口操作
Kendo UI 窗口小部件为其创建的所有窗口添加了一些默认功能。窗口右上角有一个按钮,用作关闭按钮,有一个标题栏,用于向用户清楚地说明窗口内容的目的,如果用户用鼠标点击其中一个边缘并拖动它,窗口可调整大小。窗口小部件右上角出现的按钮可以针对您的网页和特定需求进行自定义。
如您所见,默认情况下唯一出现的按钮是关闭按钮。然而,还有三个其他按钮可以非常容易地添加:刷新
、最小化
和最大化
。这些按钮已经附加了默认功能。刷新
按钮将在内容从远程源加载到窗口小部件内部时刷新窗口小部件中的内容。最小化
按钮将窗口小部件的大小缩小到仅标题栏。最大化
按钮将窗口小部件放大,使其占据整个网页浏览器的屏幕大小。点击最小化
或最大化
按钮后,将出现一个新按钮,专门用于将窗口小部件恢复到其原始位置和大小。以下是您需要在窗口小部件中启用这些操作的代码:
<script>
$(document).ready(function() {
$("#window").kendoWindow({
width: "600px",
title: "About Windows Azure",
actions: ["Minimize", "Maximize", "Close"],
close: onClose
});
var onClose = function(){
$("#windowButton").show();
};
$("#windowButton").on("click", function(){
$("#window").data("kendoWindow").open();
$("#windowButton").hide();
});
});
</script>
启用这些操作后,窗口小部件将呈现如下:
这是一个最小化的窗口小部件,请注意,最小化
按钮已更改为将窗口恢复到原始大小和形状的按钮:
下一个屏幕截图显示了最大化的窗口小部件。请注意,最大化
按钮已更改为将窗口恢复到原始大小和形状的按钮:
使用 AJAX 加载内容
到目前为止,你所看到的所有示例都在窗口小部件中显示了本地内容,或者是在网页中已经嵌入的内容。这在有限的场景中才有用。当窗口小部件可以从外部源加载内容时,例如在您的整个站点中的其他网页,窗口小部件就更加灵活了。为了实现这一点,您需要配置窗口小部件的内容源。您可以在以下代码示例中看到一个示例:
<script>
$(document).ready(function() {
$("#window").kendoWindow({
width: "600px",
title: "Rams's Ten Principles of Good Design",
content: "OtherPage.html",
close: onClose
});
var onClose = function(){
$("#windowButton").show();
};
$("#windowButton").on("click", function(){
$("#window").data("kendoWindow").open();
$("#windowButton").hide();
});
});
</script>
启用此功能后,窗口小部件将立即在激活时加载并显示此外部内容。这还有一个额外的优点,即加载的内容只有在必要时才会下载,因此页面将加载得更快。以下是一个以这种方式加载外部内容的窗口小部件示例:
使用动画效果
当窗口小部件在页面上被激活时,它会以一些令人愉快的效果动画显示在屏幕上。默认情况下,它将使用缩放效果,使窗口小部件看起来像是从一个非常小的对象缩放到全尺寸。其他可用的效果是切换效果、展开效果,以及选择窗口小部件动画是否应该以半透明开始。以下代码示例显示了默认配置的动画效果:
注意
注意,这里没有包含特殊的动画配置。要运行默认的动画,唯一的方法是在设置中省略动画配置元素。
<script>
$(document).ready(function() {
$("#window").kendoWindow({
width: "600px",
title: "About Alvar Aalto"
}
close: onClose
});
var onClose = function(){
$("#windowButton").show();
};
$("#windowButton").on("click", function(){
$("#window").data("kendoWindow").open();
$("#windowButton").hide();
});
});
</script>
要启用切换动画,修改代码使其看起来像以下代码示例。切换动画实际上是缺少特殊的动画,因此窗口小部件会立即出现或消失,而不是通过图形过渡。
<script>
$(document).ready(function() {
$("#window").kendoWindow({
width: "600px",
title: "About Alvar Aalto",
animation: {
open: {
effects: ""
},
close: {
effects: ""
}
}
close: onClose
});
var onClose = function(){
$("#windowButton").show();
};
$("#windowButton").on("click", function(){
$("#window").data("kendoWindow").open();
$("#windowButton").hide();
});
});
</script>
要启用展开动画,修改代码使其看起来像以下代码示例。reverse
配置属性用于反转close
效果的动画。
<script>
$(document).ready(function() {
$("#window").kendoWindow({
width: "600px",
title: "About Alvar Aalto",
animation: {
open: {
effects: "expand:vertical"
},
close: {
effects: "expand:vertical",
reverse: true
}
}
close: onClose
});
var onClose = function(){
$("#windowButton").show();
};
$("#windowButton").on("click", function(){
$("#window").data("kendoWindow").open();
$("#windowButton").hide();
});
});
</script>
透明度效果可以与这些动画效果中的任何一个一起使用,并且可以单独启用或禁用。以下代码示例显示了如何启用或禁用动画。与上一个示例的唯一区别是effects
属性值末尾的额外字符串值fadeIn
。
<script>
$(document).ready(function() {
$("#window").kendoWindow({
width: "600px",
title: "About Alvar Aalto",
animation: {
open: {
effects: "expand:vertical fadeIn"
},
close: {
effects: "expand:vertical fadeIn",
reverse: true
}
}
close: onClose
});
var onClose = function(){
$("#windowButton").show();
};
$("#windowButton").on("click", function(){
$("#window").data("kendoWindow").open();
$("#windowButton").hide();
});
});
</script>
使用窗口小部件事件
Kendo UI 窗口小部件提供了一组事件,这些事件在响应各种用户事件时被触发。由于这些事件有很多,我将在这里列出它们,并对每个事件进行简要描述:
-
Activate
:当窗口小部件打开后动画完成时,此事件被触发 -
Close
:当窗口小部件关闭时,此事件被触发 -
Deactivate
:当窗口小部件关闭后动画完成时,此事件被触发 -
Dragend
:当用户使用鼠标完成拖动窗口小部件时,此事件被触发 -
Dragstart
:当用户开始使用鼠标拖动窗口小部件时,此事件被触发 -
错误
: 当一个窗口小部件在通过 AJAX 加载远程内容时遇到错误时,此事件被触发。 -
打开
: 当窗口小部件打开时,此事件被触发。 -
刷新
: 当窗口小部件中的远程内容从远程源刷新时,此事件被触发。 -
调整大小
: 当用户使用鼠标调整窗口小部件大小时,此事件被触发。
使用窗口小部件 API 方法
API 方法允许我们在 JavaScript 代码中按需在窗口小部件上执行功能。以下是对调用 API 方法时我们有哪些选项的简要描述:
-
居中
: 调用此方法将窗口小部件移动到屏幕中央。 -
关闭
: 调用此方法关闭窗口小部件。 -
内容
: 调用此方法要么在没有参数的情况下获取窗口小部件的当前内容,要么在提供新内容作为参数时设置窗口小部件的内容。 -
最大化
: 调用此方法最大化窗口小部件。 -
最小化
: 调用此方法最小化窗口小部件。 -
打开
: 调用此方法将关闭的窗口小部件打开。 -
刷新
: 调用此方法通过 AJAX 从其远程源刷新窗口小部件的内容。此方法仅适用于具有 AJAX 内容属性的窗口小部件对象。 -
恢复
: 调用此方法将窗口小部件从最小化状态恢复到正常大小和位置。 -
设置选项
: 调用此方法设置窗口小部件的配置选项。 -
标题
: 调用此方法要么获取或设置窗口小部件的标题。 -
置前
: 调用此方法将窗口小部件带到页面上的其他元素的前面。 -
切换最大化
: 调用此方法要么最大化当前未最大化的窗口小部件,要么将已最大化的窗口小部件返回到其原始大小和位置。
摘要
在本章中,我们学习了如何使用窗口和上传小部件。这些小部件赋予你创建可扩展和交互式网页的能力,你的用户会欣赏这些。最重要的是,这些小部件为非常常见的网络开发问题提供了现成的解决方案,这样你就可以专注于你的代码而不是解决重复性问题。
在这本书中,我们看到了可用于开发强大网页的完整系列的 Kendo UI Web 工具。正如你在每一章中看到的那样,这些小部件非常易于使用,并提供了一系列配置选项,可以根据你的具体需求和情况进行定制。不仅如此,Telerik 还有一个活跃的开发者社区,可以通过网络论坛和博客以及必要时提供付费支持来协助实施细节。我希望你喜欢学习关于 Kendo UI Web 框架中可用的强大工具的知识。这些工具将降低交付丰富网页所需的总时间和精力投入,这是我们大多数人都会高兴的事情。
第十一章. Web API 示例
我们在前几章中探讨的许多小部件在与更高级的服务器端代码搭配使用时最为有用。例如,许多 Web 应用程序使用数据库并处理文件。虽然前几章展示了使用这些小部件所需的客户端代码,如 HTML 和 JavaScript,但它们并没有关注许多实际应用所使用的 ASP.NET 服务器端 C# 代码。为了展示如何在这些场景中使用 Kendo UI 框架,本章将展示一些使用 Kendo UI 框架与 ASP.NET Web API 和 Entity Framework 一起使用的专业示例。
注意
如果你对 ASP.NET Web API 框架不熟悉,可以访问 www.asp.net/web-api 了解一些优秀的示例、视频和教程。
熟悉 ASP.NET Web API
ASP.NET MVC 框架的最新版本 MVC 4 包含了名为 Web API 控制器 的新功能模板。这些控制器是专门的 HTTP 通信端点,允许创建 RESTful API 服务。RESTful API 服务是一种 HTTP 网络服务,允许客户端使用标准 HTTP 动词(Get
、Post
、Put
、Delete
和 Patch
)与服务器进行通信,以执行操作。
注意
传统上,ASP.NET 具有创建作为 SOAP 端点(而非 REST 端点)的 Web 服务的功能。SOAP Web 服务使用 XML 架构,在序列化和反序列化强类型对象方面非常出色,并且在生产系统中得到了广泛的应用。与 RESTful 服务相比,SOAP 服务非常冗长且脆弱,因为任何新功能的实现都需要更改架构。此外,JavaScript 的爆炸性增长使得 RESTful 服务对开发者更具吸引力,因为它们可以通过 HTML script
块和常见的 JavaScript 代码轻松访问。
RESTful Web 服务在互联网上变得越来越普遍。许多流行的基于 Web 的服务公开 RESTful API 以实现与移动应用、基于 Web 的仪表板和其他软件项目的集成。这种广泛的应用主要归因于 JavaScript 对象表示法(JSON)在序列化和反序列化对象方面的同样广泛的应用。JSON 使得任何 Web 客户端都能轻松解释来自任何 Web 服务器的数据,而无需专门的或专有的许可证或算法。
RESTful 网络请求非常简单,如果你不知道的话,你每天都在使用它们。每次你在网络浏览器中输入一个 URL,你就是在向该 URL 地址的服务器发出一个 HTTP GET 请求。同样,大多数包含表单的网页使用 HTTP POST 动词将数据发送回网络服务器以保存。这也许会让你回想起我们之前章节中的某些代码示例。你还记得在控制器的一些操作方法上看到过[HttpGet]
和[HttpPost]
属性吗?这些属性向 ASP.NET 指示,只有特定类型的 HTTP 动词(GET 或 POST)对该操作方法有效。当然,这确实有安全影响,但它实际上更有用,可以根据客户端随请求发送的 HTTP 动词来确定服务器应使用哪种方法。换句话说,一个控制器可以有五个不同的操作方法,每个方法有不同的 HTTP 动词属性,如下所示:
[HttpGet]
public ActionResult Get(int objectId = 0)
{
...
}
[HttpPost]
public ActionResult Post(Object postedObject)
{
...
}
[HttpPut]
public ActionResult Put(Object objectToPut)
{
...
}
[HttpPatch]
public ActionResult Patch(Object objectToPatch)
{
...
}
[HttpDelete]
public ActionResult Delete(int objectId)
{
...
}
前述代码的问题在于它为页面的每个不同功能创建了单独的路由。如果这个页面可以通过路由http://mysite.com/movies
访问,我们可以使用http://mysite.com/movies/get/25
来查看特定电影的数据,但为了添加新电影或删除电影,我们必须使用完全不同的路由,例如http://mysite.com/movies/put
。这可能对于一个用户交互不多的网站来说不是什么大问题,但对于试图从远程代码中创建访问 API 的程序的开发者来说,这是一个大问题。
ASP.NET MVC Web API 通过创建专门用于创建 RESTful 服务的特殊控制器来解决此问题。在一个标准的 MVC 控制器中,每个操作方法创建一个新的路由(或 URL),最终在视图中生成一些网页内容。然而,在一个 Web API 控制器中,每个操作方法为相同的路由(或 URL)指定一个单一的 HTTP 动词。换句话说,Web API 控制器只为单个 HTTP 端点提供服务;它只针对单个路由操作。对于 API 开发者来说,这是完美的。例如,单个 HTTP 端点http://mysite.com/api/movies
可以适当地响应所有 HTTP 动词,而无需为每个操作使用不同的 URL。
在 API 控制器内部,每个 HTTP 动词都有一到多个操作方法来处理该特定类型的请求。控制器到路由的默认值是控制器的名称。因此,名为MoviesController.cs
的控制器默认路由为http://mysite.com/api/movies
。这就是路由的终点;现在,请求此端点之间的唯一区别在于请求包含的 HTTP 动词以及作为参数传递的哪些参数。以下是由 ASP.NET Web API 模板为 API 控制器生成的默认代码:
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post([FromBody]string value)
{
}
// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
注意到操作方法的名称是 HTTP 动词的名称。这不是偶然的,操作方法名称必须与 HTTP 动词名称匹配或以 HTTP 动词名称开头。因此,一个操作方法可以被称为Get
,或者它可以被称为GetMovie
。请注意,在这个控制器中,有两个不同的Get
操作方法版本。就像在标准控制器中一样,只要每个方法的签名是唯一的,相同的操作方法可以多次列出。在这种情况下,它允许我们有一个不需要任何参数的标准Get
方法,以及一个更专业的Get
方法,该方法返回特定记录的信息。
注意
您可以访问www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api
以了解 Web API 路由规则和命名约定的良好概述。
您还会注意到,这些操作方法上没有 HTTP 动词属性。对于 API 控制器,这些属性不是必需的。然而,代码示例中有一个新的属性。您可以在Post
和Put
操作方法的参数前看到它:[FromBody]
。这个特殊属性用于帮助模型绑定器在 HTTP 请求体中定位参数。它并不总是必要的,例如,当您绑定一个模型绑定器可以清楚地看到由具有特定名称的特定属性组成的复杂对象时。然而,对于像本代码示例中的简单字符串值,它需要知道您打算将 HTTP 请求体绑定到那个输入参数。还有一个属性([FromUri]
)用来指示参数来自 URL。大多数情况下,这些参数将是不必要的,但它们可用于帮助解决模型绑定器无法自行解决的问题。如果您不熟悉它,那么进行一些研究是值得的。Web API 用于模型绑定的基本规则如下:
-
简单类型来自 URL(URI)
-
复杂类型来自请求体
简单类型包括所有.NET Framework 的原始类型,以及DateTime
、Decimal
、Guid
、String
和TimeSpan
。对于每个操作方法,最多只能有一个参数可以读取请求体。如果您尝试用[FromBody]
标记多个参数,您可能会遇到运行时错误或空值。
注意
您可以访问blogs.msdn.com/b/jmstall/archive/2012/04/16/how-webapi-does-parameter-binding.aspx
以获取有关 Web API 参数绑定的更多信息。
关于 API 控制器,还有一个重要的概念需要理解,那就是它们不会像标准控制器那样返回视图。API 控制器不是为浏览器显示生成 HTML 标记,而是生成原始数据,这些数据旨在供专门的客户端代码,如 JavaScript,消费。这种数据格式是您不必担心的事情。注意,在前面的代码示例中,动作方法只是简单地返回字符串值,而没有使用我们在一些前面的章节中看到过的Json()
方法。我们不需要告诉 API 控制器如何格式化其数据,因为它将在通信过程中与客户端自动协商正确的格式。最常用的格式是 JSON,但某些客户端可能更喜欢 XML 或其他 ASP.NET 框架知道如何序列化的数据类型。
注意
您可能想知道这种自动协商是如何工作的。以下是答案:它主要基于 API 调用期间客户端的Accept
头。您甚至可以创建自己的内容类型来扩展 API 框架以适应定制场景。更多信息请参阅此页面:www.asp.net/web-api/overview/formats-and-model-binding/content-negotiation
。
由于 API 控制器不是设计用来渲染带有标记的网页,因此您需要创建与您习惯相同的常规控制器来处理您的网页。为了与 API 控制器交互,使用 JavaScript,尤其是 jQuery,通过特定的 HTTP 动词访问 API 端点以完成页面设计的任何任务是非常常见的。
熟悉 Entity Framework Code First
大多数应用程序使用数据库来存储信息。然而,大多数数据库存储信息的方式并不完全符合服务器端面向对象编程。这是一个非常普遍的问题,并催生了对象关系映射(ORM)系统领域。其中许多存在,但微软为.NET 框架创建了一个特定的系统,称为Entity Framework(EF)。它基本上是一个框架,旨在更容易编写将信息存储在数据库中的代码,同时仍然像面向对象系统一样运行。如果您已经下载了本章的示例内容,请现在打开Chapter 11
解决方案以继续。否则,创建一个新的 ASP.NET MVC 4 项目,并在被询问时选择Web API模板。
Entity Framework 的细节众多,这里没有足够的空间来探索它们。我们将通过一个基本的示例来展示如何利用 Entity Framework Code First 模型,以便我们可以在本章的示例中展示它。为了使用 Entity Framework,您必须首先通过 NuGet 将它安装到您的 Visual Studio 项目中。您可以通过在 Visual Studio 的解决方案资源管理器中右键单击项目并选择 管理 NuGet 包… 来这样做,如图所示:
在下一屏,您应该确保您正在查看 在线 目录。在搜索框中输入文本 Entity Framework
,当它在结果窗口中出现时选择 安装。一旦安装,它将显示一个绿色的勾选标记,表示它已准备好使用:
这将安装所有必要的 Entity Framework 组件到您的 Visual Studio 解决方案中。我们将使用 Entity Framework 的一个名为 Code First 的功能。这个功能允许我们在数据库甚至存在之前首先创建类,或实体。从这个模型中获得的最大好处是,它保证了数据库的设计和数据存储将符合我们的面向对象架构。
注意
如果您还没有这样做,现在下载本章的示例内容是个好时机。所有这些示例和文件都已经存在那里,所以您可以跟随带有工作代码的示例。
为了说明起见,我们将在 Visual Studio 项目的 Models
文件夹中创建我们的实体类。在 Models
文件夹中创建一个名为 Movie.cs
的类,如下所示:
public class Movie
{
public int Id { get; set; }
public string Name { get; set; }
public int ReleaseYear { get; set; }
public int Rating { get; set; }
public int Rank { get; set; }
}
Entity Framework 将从这个属性推断出 Id
属性应该在数据库内部成为主键。现在我们已经有了我们的模型,我们需要告诉 Entity Framework 我们想要创建一个包含它的数据库。在 Models
文件夹中创建另一个类,并将其命名为 MoviesContext.cs
,如下所示:
...
using System.Data.Entity;
...
public class MoviesContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
}
这段代码通知 Entity Framework 我们想要一个包含 Movie
实体 DbSet
的 DbContext
上下文。让我们继续添加一些电影到我们的数据库中,这样我们就可以在我们的示例中使用它们。为了开始,我们需要一个页面,我们可以输入电影数据,并且让网络服务器将数据保存到数据库中。
创建一个带有以下选项选择的 MoviesController
控制器;它将自动生成用于管理我们刚刚创建的 Movie
实体的基本操作方法和视图。
注意
如果您找不到 Movie
实体或 MoviesContext
类,请尝试构建您的项目并再次尝试。
现在转到Movies/Index
页面并创建一些电影。第一次运行项目时,它可能非常慢。原因是 Entity Framework 正在后台根据你之前提供的模型和上下文动态创建你的数据库。在你看到网页的时候,数据库就已经启动并运行了。你可以在下面的屏幕截图中看到我是如何创建几个的。至少创建十个,以便在章节后面的示例中有一些数据。
尽管还有更多关于 Entity Framework 的知识需要学习,但这个简短的例子已经带你从单个类到完全工作的数据库。我们将在这个章节的其余示例中使用这个电影数据库。如果你对 Entity Framework 不熟悉并且想了解更多,我建议检查我们刚刚用 Visual Studio 创建的MoviesController.cs
类,看看它是如何创建默认操作的;然后你可以访问www.msdn.com获取该主题的官方文档。
熟悉 OData
ASP.NET Web API 框架通过称为OData的语法支持数据查询。OData 是一种与 HTTP URL 兼容的查询语言,因此它可以出现在 URL 查询字符串中。它为用于返回数据列表的 API 操作方法提供了两个非常强大的好处。首先,它自动将 OData 查询语言转换为 API 操作方法内部实际的数据查询。这非常强大,直到你真正看到它可能很难相信。基本上,它是一个免费的搜索引擎。其次,OData 功能允许查询在服务器上执行。这意味着服务器可以查询数据源以找到匹配的特定元素,然后将结果返回给客户端。客户端不需要查询整个数据集然后自行过滤。这是一个巨大的性能提升,同时也简化了客户端和服务器端的代码。
你可以通过四种方式为你的 API 控制器启用 OData 查询功能。每个都比前一个提供了更细粒度的控制。
-
通过
WebApiConfig.cs
全局启用查询支持 -
将
[Queryable]
属性添加到特定的 API 操作方法 -
从
ODataController
继承而不是ApiController
-
从
EntitySetController
继承而不是ODataController
第一个选项将全局启用任何具有IQueryable
返回类型的ApiController
操作方法的查询支持。要启用此功能,打开App_Start
文件夹中的WebApiConfig.cs
文件,取消注释带有config.EnableQuerySupport()
的代码行:
// Uncomment the following line of code to enable query support
for actions with an IQueryable or IQueryable<T> return type.
// To avoid processing unexpected or malicious queries, use the
validation settings on QueryableAttribute to validate
incoming queries.
// For more information, visit
http://go.microsoft.com/fwlink/?LinkId=279712.
config.EnableQuerySupport();
第二种方法将启用带有 [Queryable]
属性装饰的特定操作方法的查询支持。与前面的选项相比,它提供了更多的配置选择,因为 [Queryable]
属性有许多属性可以配置以微调其行为。带有此属性装饰的操作方法看起来如下:
// GET api/values
[Queryable]
public IQueryable<string> Get()
{
return new string[] { "value1", "value2" }.AsQueryable();
}
第三种方法涉及从 ODataController
继承您的控制器类而不是 ApiController
。这将启用 Web API 提供的完整 OData 支持,并且还需要进行一些额外的配置,以便 OData 引擎理解它所公开的实体的 实体数据模型(EDM)。
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Movie>("Movies");
Microsoft.Data.Edm.IEdmModel model = modelBuilder.GetEdmModel();
config.Routes.MapODataRoute("ODataRoute", "OData", model);
上述代码需要在 Web 应用程序启动时运行,因此它应该放置在 Global.asax
或 App_Start
类之一中,例如 WebApiConfig.cs
。它读取与 Entity Framework 相同类型的实体模型,并将其加载到 OData 路由中,以便 Web API 理解模型各部分之间的关系,主键是什么,等等。这使更高级的场景,如属性导航成为可能。有关此信息,您可以访问 www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/getting-started-with-odata-in-web-api/create-a-read-only-odata-endpoint
了解介绍。
第四种方法与前面的方法类似,但它自动启用了 ODataController
类必须手动执行的更多 OData 功能。它仍然需要与上一个选项中的 ODataModelBuilder
类。上面列出的 URL 也涵盖了此主题的信息。
在本章的示例中,我们将使用 [Queryable]
属性来为特定的操作方法启用查询支持。我鼓励您自己更深入地探索这项技术,它是一个强大且可扩展的框架,可以为您的代码提供巨大的生产力提升。要了解更多关于 OData 的信息,您可以访问 www.odata.org。
使用 DataSourceRequest 与 Kendo Grid
正如我们在第一章中看到的,Kendo Grid 小部件旨在允许丰富的功能,如分页、过滤和排序。我们之前看到,这可以通过客户端的 JavaScript 和 Kendo DataSource
对象来实现。然而,当与服务器端功能连接时,Grid 小部件的功能变得更加强大,以帮助驱动其功能。
Kendo UI Framework for ASP.NET MVC 包含一个特殊对象,用于帮助在标准 MVC 控制器中实现此功能。它不需要 Web API 或 OData,尽管如果您想手动配置 Kendo DataSource
,则可以使用它们。在本例中,我们将学习如何使用 DataSourceRequest
对象以及它是如何帮助驱动 Kendo Grid 小部件的功能的。
首先,向之前创建的MoviesController
类中添加一个新的操作方法。
public ActionResult MoviesGrid([DataSourceRequest]DataSourceRequest request)
{
return Json(
db.Movies.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
您应立即注意到操作方法签名的特殊属性[DataSourceRequest]
。此属性来自Kendo.Mvc.Extensions
命名空间,因此您需要在控制器顶部的using
语句中包含它。此属性对于 Kendo UI 框架正确理解网格小部件和服务器端操作方法之间的通信是必要的。同样重要的是,[DataSourceRequest]
属性装饰了一个DataSourceRequest
对象,并且从此操作方法返回的值通过名为ToDataSourceResult(request)
的扩展方法传递。这些特殊方法驱动 Kendo 的数据绑定、排序、分页和过滤功能。
在此代码就绪后,向KendoController
添加一个名为Grid
的新操作方法,这将是用于视图的操作方法。
public ActionResult Grid()
{
return View();
}
为此方法创建一个视图,并在其中放置以下 Razor 代码:
@using Kendo.Mvc.UI;
@{
ViewBag.Title = "Grid";
}
@(Html.Kendo().Grid<Chapter11.Models.Movie>().Name("moviesGrid")
.Columns(columns =>
{
columns.Bound(p => p.Name);
columns.Bound(p => p.ReleaseYear);
columns.Bound(p => p.Rating);
columns.Bound(p => p.Rank);
}
)
.Pageable()
.Sortable()
.Filterable()
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(5)
.Read(read => read.Action("MoviesGrid", "Movies"))
))
如您之前所见,此Html
辅助方法来自 Kendo UI 框架,在视图页面上生成一个网格小部件。我们已配置了列并启用了网格的pageable
、sortable
和filterable
功能。对于此示例来说,重要的是我们已经将DataSource
对象设置为指向我们之前设置的Movies
控制器的MoviesGrid
操作,该操作具有特殊的 Kendo 属性和对象。当我们运行我们的项目并导航到这个新视图时,我们得到一个如下所示的 Kendo 网格小部件,它具有工作分页按钮、过滤按钮和可排序的列标题:
与第一章不同,与数据交互:数据源、模板、TabStrip 和网格,然而,这个网格小部件要求服务器计算排序顺序、页码和过滤后的结果。它是通过向服务器发送特殊的数据指令来完成的,这些指令由特殊的 Kendo 属性和对象解释。要查看这些数据指令,可以在网站运行时按F12键打开 Internet Explorer 开发者工具。在出现的工具栏中,点击网络标签,然后点击开始捕获。点击这些按钮后,点击网格功能之一,如页面箭头或列标题之一。你将在开发者工具栏中看到一些活动,这意味着网格正在通过 JavaScript AJAX 调用与服务器通信。双击列表中显示地址/Movies/MoviesGrid的第一项,如图所示:
双击此项目将打开 HTTP 请求的详细描述。点击请求体标签以查看网格发送到服务器的信息:
你可以看到,Grid 请求了页码2
,每页大小为5
条记录。这是 Kendo Grid 如何通过 HTTP 请求体与服务器通信的方式。
使用 Web API 驱动 ListView
与 Grid 小部件类似,ListView 小部件能够利用[DataSourceRequest]
属性来帮助驱动其操作的特殊功能。在这种情况下,我们不仅将从服务器查询数据,还将使用 Web API 进行编辑。
在KendoController
类中为我们的 ListView 示例创建一个动作方法,如下所示:
private MoviesContext db = new MoviesContext();
public ActionResult ListView()
{
return View(db.Movies);
}
然后为这个动作方法添加一个视图,并在其中添加以下 HTML 标记:
@using Kendo.Mvc.UI;
@model IEnumerable<Chapter11.Models.Movie>
@{
ViewBag.Title = "ListView";
}
<script type="text/x-kendo-tmpl" id="template">
<div class="movie-view">
<dl>
<dt>Name</dt>
<dd>${Name}</dd>
<dt>Rating</dt>
<dd>${Rating}</dd>
<dt>Rank</dt>
<dd>${Rank}</dd>
</dl>
</div>
<div>
<a class="k-button k-button-icontext k-edit-button"
href="\\#"><span class="k-icon k-edit"></span>Edit</a>
<a class="k-button k-button-icontext k-delete-button"
href="\\#"><span class="k-icon k-delete"></span>Delete</a>
</div>
</script>
<h2>ListView</h2>
在数据检索后,这个基本的 HTML 和 Kendo 模板将被用来构建页面。你可以看到模板只是简单地显示Movie
对象的每个元素,然后提供编辑和删除按钮。接下来,在视图底部添加以下 MVC Razor 代码来连接一切:
@(Html.Kendo().ListView(Model)
.Name("moviesListView")
.TagName("div")
.ClientTemplateId("template")
.Editable()
.DataSource(dataSource => {
dataSource
.Read(read => read.Action("MoviesGrid", "Movies"))
.Update(update => update.Type(HttpVerbs.Post)
.Url("/api/MovieApi"))
.PageSize(5)
.Model(config => config.Id("Id"));
})
.Pageable())
在这里,我们创建了一个 Kendo ListView,指定了在页面上渲染时要使用的模板 ID,将其标记为可编辑,并指定了数据源。在数据源内部,我们指明了要检索以显示数据的位置(Read
方法)以及发送更新数据的位置(Update
方法)。
接下来,我们需要为Movie
对象创建一个编辑模板,以便这个 ListView 可以编辑我们的Movie
对象。在Views/Shared
文件夹下创建一个名为EditorTemplates
的新文件夹。然后,在EditorTemplates
文件夹中添加一个视图,并将其命名为Movie.cshtml
。
打开Movie.cshtml
视图文件,并在其中添加以下代码:
@model Chapter11.Models.Movie
<div class="movie-view">
<dl>
<dt>Name</dt>
<dd>@Html.EditorFor(model => model.Name)</dd>
<dt>Rating</dt>
<dd>@Html.EditorFor(model => model.Rating)</dd>
<dt>Rank</dt>
<dd>@Html.EditorFor(model => model.Rank)</dd>
</dl>
<div>
<a class="k-button k-button-icontext k-update-button"
href="\\#"><span class="k-icon k-update"></span>Save</a>
<a class="k-button k-button-icontext k-cancel-button"
href="\\#"><span class="k-icon k-cancel"></span>Cancel</a>
</div>
</div>
当在Movie
项上点击编辑按钮时,ListView 小部件将使用此视图。以下是在默认情况下(查看电影)的页面外观。你可以看到电影项的不同元素以及用于编辑或删除它的按钮:
当你点击编辑按钮时,这就是电影项的渲染方式。看看字段是如何现在按照我们在EditorTemplate
文件夹中为Movie
数据类型指定的方式渲染的。
由于我们已经将其连接到 Web API,如果我们设置 Visual Studio 中 API 方法被调用时的断点,我们可以观察到发送到服务器进行处理的更改。你可以看到我在以下屏幕截图中所做的是:
以这种方式设置 Visual Studio 后,程序将在更新时停止,你可以检查数据以观察正在发生的事情。对于生产应用程序,你希望使用 Entity Framework 来编辑movie
对象并将更改保存到数据库中。
摘要
在本章中,我们看到了如何使用 Web API 来处理一些更现实的场景,这些场景涉及到管理数据的两个 Kendo 组件。我们还快速探讨了 ASP.NET Web API 的基础知识,以及 Entity Framework 和 OData。这些工具结合使用,可以是一个非常强大的组合,几乎可以创建您需要的任何自定义解决方案。
我们刚才看到的示例,都使用了 Telerik 提供的一个特殊属性,以帮助进行模型绑定和服务器端分页和筛选。当这些特殊助手可用时,使用它们是非常方便的。我鼓励您继续自行探索这些技术,看看您如何在自己的网页上创建自己的自定义解决方案。