(转)[翻译]ASP.NET MVC 3 开发的20个秘诀(十八)[20 Recipes for Programming MVC 3]:自动完成搜索
2012-01-07 17:16
681 查看
原文地址:
/article/5297705.html
议题
当你在搜索某个具体事情的时候,可能输入会比较复杂(或需要很长时间),正当用户在试图输入正确的内容时,搜索并显示可能是用户输入的内容,让用户查找输入和搜索变的更加容易。
解决方案
使用JQuery自动完成插件,修改图书列表页面上的搜索功能,使用户在输入搜索时,立即显示搜索结果。
讨论
自动完成插件默认不包含在MVC项目的JQuery基本包中,所以,要做的第一件事是访问http://jquery.com去下载插件。这个插件包含两个必需文件,一个Javascript文件和一个CSS文件。将新下载的文件放置到“Scripts”文件夹中。将CSS文件放置到“Content”文件夹中。
这个秘诀也会介绍关于视图渲染部分的内容。为了提高访问性能,在全局共享视图中添加Ajax和不唐突Ajax文件以及名为“main”的CSS文件,以避免每次加载不同视图时都就要加载这些文件。并在共享视图里面添加RenderSection()方法。这将允许每个视图根据具体情况在<Head>标签中添加特需的Javascript或CSS文件。
修改Views/Shared/_Layout.cshtml,添加新方法RenderSection():
只有主要的CSS文件以及jQuery的核心文件在共享文件中加载,因为CSS是每一页都需要的,而jQuery会在绝大多数的页面中被使用。但是,我们新引用的Ajax的jQuery并不是每页都必须要求的。
现在我们使用自动完成插件有两种方法:
将数据发送到Javascript中进行搜索;
在用户输入时通过Ajax获取结果。
以我使用的感觉来说,我发现解决方案1的自动完成方法要快很多,因为它并不需要要每次都从数据库中请求数据。然而这个解决方案限制于数据量的多少,当搜索内容过于庞大时,用户页面加载以及调用Javascript方法时都会导致加载用户计算机运行变慢或等待时间过长。经过一些错误跟踪实验,我大致可以确定这个神奇的数字大约是40000条数据。如果结果数量超过这个值就需要使用2号解决方案,否则,始终坚持方案1,因为搜索时瞬间的体验,尽量不要有轻微的延迟。
在这个例子中,将要搜索的书籍没有超过40000上限,所以我们会选择使用方案1。现在必须对BooksController进行修改,创建一个存储书名列表的ViewBag变量。自动完成时需要有一个Javascript的数组,将这些书籍名称使用“|”字符进行分割。然后在视图中,这个字符串将会被Javascript的Split()方法转换为数组对象。修改了这个功能后,当用户完全的输入了想搜索的结果,将会返回一本书的匹配结果,用户点击该结果将会自动重定向到这本书的详情页面。
最后,修改Books/Index视图,添加jQuery自动完成的功能。首先,是使用@section包含必要的JavaScript和CSS文件的引用。然后,将以前创建的搜索文本框的ID修改为“wordSearch”。最后,将自动完成的代码添加到自动完成搜索框的下面。这个JavaScript是有意放置在视图的底部的,根据返回结果数量的不同,这个JavaScript的“代码块(Blocking)”可能会给用户的计算机带来很多处理负载而不至于影响视图呈现。
为了实现第二种方案,Ajax搜索,通过URL传递搜索参数,而不是通过自动完成方法访问数组。该URL将包含一个查询字符串变量“q”。这个变量将包含用户输入的搜索值。这将用来执行搜索与书籍的信息进行匹配,并将返回的内容使用字符分隔符进行分隔。jQuery文档中有完整的例子,以及其他相关的例子(可能包含返回书籍的封面的缩略图等)。
/article/5297705.html
议题
当你在搜索某个具体事情的时候,可能输入会比较复杂(或需要很长时间),正当用户在试图输入正确的内容时,搜索并显示可能是用户输入的内容,让用户查找输入和搜索变的更加容易。
解决方案
使用JQuery自动完成插件,修改图书列表页面上的搜索功能,使用户在输入搜索时,立即显示搜索结果。
讨论
自动完成插件默认不包含在MVC项目的JQuery基本包中,所以,要做的第一件事是访问http://jquery.com去下载插件。这个插件包含两个必需文件,一个Javascript文件和一个CSS文件。将新下载的文件放置到“Scripts”文件夹中。将CSS文件放置到“Content”文件夹中。
这个秘诀也会介绍关于视图渲染部分的内容。为了提高访问性能,在全局共享视图中添加Ajax和不唐突Ajax文件以及名为“main”的CSS文件,以避免每次加载不同视图时都就要加载这些文件。并在共享视图里面添加RenderSection()方法。这将允许每个视图根据具体情况在<Head>标签中添加特需的Javascript或CSS文件。
修改Views/Shared/_Layout.cshtml,添加新方法RenderSection():
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script> @RenderSection("JavaScriptAndCSS", required: false) </head> <body> <div class="page"> <div id="header"> <div id="title"> <h1>My MVC Application</h1> </div> <div id="logindisplay"> @Html.Partial("_LogOnPartial") [ @Html.ActionLink("English", "ChangeLanguage", "Home", new { language = "en" }, null) ] [ @Html.ActionLink("Français", "ChangeLanguage", "Home", new { language = "fr" }, null) ] </div> <div id="menucontainer"> <ul id="menu"> <li>@Html.ActionLink("Home", "Index", "Home")</li> <li>@Html.ActionLink("About", "About", "Home")</li> </ul> </div> </div> <div id="main"> @RenderBody() </div> <div id="footer"> </div> </div> </body> </html>复制代码
只有主要的CSS文件以及jQuery的核心文件在共享文件中加载,因为CSS是每一页都需要的,而jQuery会在绝大多数的页面中被使用。但是,我们新引用的Ajax的jQuery并不是每页都必须要求的。
现在我们使用自动完成插件有两种方法:
将数据发送到Javascript中进行搜索;
在用户输入时通过Ajax获取结果。
以我使用的感觉来说,我发现解决方案1的自动完成方法要快很多,因为它并不需要要每次都从数据库中请求数据。然而这个解决方案限制于数据量的多少,当搜索内容过于庞大时,用户页面加载以及调用Javascript方法时都会导致加载用户计算机运行变慢或等待时间过长。经过一些错误跟踪实验,我大致可以确定这个神奇的数字大约是40000条数据。如果结果数量超过这个值就需要使用2号解决方案,否则,始终坚持方案1,因为搜索时瞬间的体验,尽量不要有轻微的延迟。
在这个例子中,将要搜索的书籍没有超过40000上限,所以我们会选择使用方案1。现在必须对BooksController进行修改,创建一个存储书名列表的ViewBag变量。自动完成时需要有一个Javascript的数组,将这些书籍名称使用“|”字符进行分割。然后在视图中,这个字符串将会被Javascript的Split()方法转换为数组对象。修改了这个功能后,当用户完全的输入了想搜索的结果,将会返回一本书的匹配结果,用户点击该结果将会自动重定向到这本书的详情页面。
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.Linq; using System.Linq.Dynamic; using System.Web; using System.Web.Mvc; using MvcApplication4.Models; using MvcApplication4.Utils; using PagedList; namespace MvcApplication4.Controllers { public class BooksController : Controller { private BookDBContext db = new BookDBContext(); // // GET: /Books/ public ActionResult Index(string sortOrder, string filter, string Keyword, int page = 1) { #region ViewBag Resources ... #endregion #region ViewBag Sort Params ... #endregion var books = from b in db.Books select b; #region Keyword Search if (!String.IsNullOrEmpty(Keyword)) { books = books.Where(b => b.Title.ToUpper(). Contains(Keyword.ToUpper()) || b.Author.ToUpper().Contains( Keyword.ToUpper())); // Should we redirect because of only one result? if (books.Count() == 1) { Book book = books.First(); return RedirectToAction("Details", new { id = book.ID }); } } ViewBag.CurrentKeyword = String.IsNullOrEmpty(Keyword) ? "" : Keyword; #endregion #region Filter switch ... #endregion books = books.OrderBy(sortOrder); int maxRecords = 1; int currentPage = page - 1; // Get all book titles ViewBag.BookTitles = FormatBooksForAutocomplete(); return View(books.ToPagedList(currentPage, maxRecords)); } private string FormatBooksForAutocomplete() { string bookTitles = String.Empty; var books = from b in db.Books select b; foreach (Book book in books) { if (bookTitles.Length > 0) { bookTitles += "|"; } bookTitles += book.Title; } return bookTitles; } ... } }复制代码
最后,修改Books/Index视图,添加jQuery自动完成的功能。首先,是使用@section包含必要的JavaScript和CSS文件的引用。然后,将以前创建的搜索文本框的ID修改为“wordSearch”。最后,将自动完成的代码添加到自动完成搜索框的下面。这个JavaScript是有意放置在视图的底部的,根据返回结果数量的不同,这个JavaScript的“代码块(Blocking)”可能会给用户的计算机带来很多处理负载而不至于影响视图呈现。
@model PagedList.IPagedList<MvcApplication4.Models.Book> @if (IsAjax) { Layout = null; } @section JavascriptAndCSS { <link rel="stylesheet" href=" @Url.Content("~/Content/jquery.autocomplete.css")" type="text/css" /> <script src="@Url.Content( "~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script> <script type="text/javascript" src="@Url.Content( "~/Scripts/jquery.autocomplete.js")"></script> } ... @using (Html.BeginForm()) { @:Search: @Html.TextBox("Keyword", (string)ViewBag.CurrentKeyword, new { id = "KeywordSearch" }) <input type="submit" value="Search" /> } ... <script type="text/javascript"> $(document).ready(function () { var data = "@ViewBag.BookTitles".split("|"); $("#KeywordSearch").autocomplete(data); }); </script>复制代码
为了实现第二种方案,Ajax搜索,通过URL传递搜索参数,而不是通过自动完成方法访问数组。该URL将包含一个查询字符串变量“q”。这个变量将包含用户输入的搜索值。这将用来执行搜索与书籍的信息进行匹配,并将返回的内容使用字符分隔符进行分隔。jQuery文档中有完整的例子,以及其他相关的例子(可能包含返回书籍的封面的缩略图等)。
相关文章推荐
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十八)[20 Recipes for Programming MVC 3]:自动完成搜索
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十)[20 Recipes for Programming MVC 3]:通过关键字进行列表搜索
- [翻译]ASP.NET MVC 3 开发的20个秘诀(二)[20 Recipes for Programming MVC 3]:自动生成控制器和视图
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十二)[20 Recipes for Programming MVC 3]:缩放图片尺寸创建缩略图
- [翻译]ASP.NET MVC 3 开发的20个秘诀(二十)[20 Recipes for Programming MVC 3]:缓存结果数据加速页面载入
- [翻译]ASP.NET MVC 3 开发的20个秘诀(一)[20 Recipes for Programming MVC 3]:通过密码验证限制访问视图
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十一)[20 Recipes for Programming MVC 3]:通过表单上传文件
- [翻译]ASP.NET MVC 3 开发的20个秘诀(四)[20 Recipes for Programming MVC 3]:实现多语言支持
- [翻译]ASP.NET MVC 3 开发的20个秘诀(五)[20 Recipes for Programming MVC 3]:发送欢迎邮件
- [翻译]ASP.NET MVC 3 开发的20个秘诀(八)[20 Recipes for Programming MVC 3]:对列表进行分页
- [翻译]ASP.NET MVC 3 开发的20个秘诀(二十)[20 Recipes for Programming MVC 3]:缓存结果数据加速页面载入
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十三)[20 Recipes for Programming MVC 3]:实现Ajax增强用户体验
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十六)[20 Recipes for Programming MVC 3]:站点移动化
- [翻译]ASP.NET MVC 3 开发的20个秘诀(九)[20 Recipes for Programming MVC 3]:对列表进行筛选
- [翻译]ASP.NET MVC 3 开发的20个秘诀(三)[20 Recipes for Programming MVC 3]:验证用户输入
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十九)[20 Recipes for Programming MVC 3]:路由用户至特定的Controller或Action
- [翻译]ASP.NET MVC 3 开发的20个秘诀(六)[20 Recipes for Programming MVC 3]:找回忘记的密码
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十四)[20 Recipes for Programming MVC 3]:使用Ajax提交Form
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十七)[20 Recipes for Programming MVC 3]:卷帘式分页加载
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十五)[20 Recipes for Programming MVC 3]:启用图片验证码(CAPTCHA)