使用JQuery自动完成插件Auto Complete详解


Posted in jQuery onJune 18, 2019

问题

当你查找一些特殊的东西,当你输入准确的词时,找到它可能是困难的(或者很耗时)。在输入的时候展示出结果(自动完成),使查找变得更简单。

解决方案

使用JQuery自动完成插件,更新现有图书列表页面上的搜索,当用户键入的时候立即显示结果。

讨论

自动完成插件是不会象jQuery基本库一样自动包含在MVC项目中的,所以需要做的第一件事就是的是下载插件
访问http://jquery.com/。两个主要的文件是必需的:JavaScript文件和CSS文件。把新下载的javascript文件放到你MVC应用程序的script 文件夹下。CSS文件可以直接添加到您的content目录。

这个配方也将介绍在view中使用 rendering sections。在shared文件夹下layout中自动添加了2个javascript文件和1个css文件。这些是Ajax和不唐突的Ajax和网站主css文件。每次加载的内容越多,页面视图加载越慢。与其在每个页面都去包含可能不必要的javascript和css 文件,不如在layout中添加一个新的RenderSection()。这允许特别的view在<head>标签去加载特别的javascript或css,但不是每页都添加他们。

下边是一个更新后的Views/Shared/_Layout.cshtml,他使用了一个新的RenderSection()。

<!DOCTYPE html>
<html>
<head>
<title>_Mobile</title>
<link href="@Url.Content(" rel="external nofollow" rel="external nofollow" ~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.6.2.min.js")" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
if (window.innerWidth <= 480) {
$("link[rel=stylesheet]").attr({ href: "@Url.Content("~/Content/jquery.mobile-1.0b1.min.css")" });
}
});
</script>
@RenderSection("JavaScriptAndCSS", required: false)
</head>
<body>
<div class="page" data-role="page">
<div id="header" data-role="header">
<div id="title">
<h1>My MVC Application</h1>
</div>
<div id="logindisplay" class="ui-bar">
@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" class="ui-bar">
<ul id="menu">
<li>@Html.ActionLink("Home", "Index", "Home", null, new Dictionary<string, object> {{ "data-role", "button" }})</li>
<li>@Html.ActionLink("About", "About", "Home", null, new Dictionary<string, object> { { "data-role", "button" }})</li>
</ul>
</div>
</div>
<div id="main" data-role="content">
@RenderBody()
</div>
<div id="footer" data-role="footer">
</div>
</div>
</body>
</html>

主要的CSS文件和核心的JQuery文件被留下来了,因为css在每个也都需要,并且绝大多数网页也需要JQuery。然而新的JQuery文件和不唐突的AJAX不是每个页面都需要的。

现在,有两种方式使用Autocomplete 插件:

1.在javascript中设置要搜索的数据。

2.当用户输入时通过ajax检索。

在我使用这个插件的经验看来,我发现使用解决方案1时自动完成更快。因为它并不需要每次从数据库中请求数据。然而,使用这种解决方案的限制:只有这么多字符,可传递到function中,大量的JavaScript可能会导致用户的计算机上页面加载缓慢。经过一些试验和错误,我已经确定神奇的数字是大约40,000个结果。如果结果数量超过此,最好使用选项2;否则,始终坚持,因为搜索选项1是瞬时,而不是有轻微的延迟。

在这个例子中,将搜索书籍,我们没有超过40000,所以将使用选项1。BooksController现在必须更新,以设置ViewBag为book title。自动完成功能需要支持一个JavaScript数组的支持,所以书将管道(|)分开。然后在view中,书将被转换到一个数组,使用JavaScript的split()函数。当用户完成键入他们的结果,他们应该有选择完全匹配标题,因此这个函数将被更新。如果只有1本书返回并且用户执行了搜索,它会自动重定向到本书详细介绍页面。

我们要在bookcontroller 中更新Index Action 并添加一个私有方法名为:FormatBooksForAutocomplete。

代码如下:

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 MvcApplication.Models;
using MvcApplication.Utils;
using PagedList;
namespace MvcApplication.Controllers
{ 
public class BooksController : Controller
{
private BookDBContext db = new BookDBContext();
//
// GET: /Books/
[OutputCache(Duration = Int32.MaxValue, SqlDependency = "MvcApplication.Models.BookDBContext:books", VaryByParam = "sortOrder;filter;page")]
public ActionResult Index(string sortOrder, string filter, string Keyword, int page = 1)
{
#region ViewBag Resources
ViewBag.Title = Resources.Resource1.BookIndexTitle;
ViewBag.CreateLink = Resources.Resource1.CreateLink;
ViewBag.TitleDisplay = Resources.Resource1.TitleDisplay;
ViewBag.IsbnDisplay = Resources.Resource1.IsbnDisplay;
ViewBag.SummaryDisplay = Resources.Resource1.SummaryDisplay;
ViewBag.AuthorDisplay = Resources.Resource1.AuthorDisplay;
ViewBag.ThumbnailDisplay = Resources.Resource1.ThumbnailDisplay;
ViewBag.PriceDisplay = Resources.Resource1.PriceDisplay;
ViewBag.PublishedDisplay = Resources.Resource1.PublishedDisplay;
ViewBag.EditLink = Resources.Resource1.EditLink;
ViewBag.DetailsLink = Resources.Resource1.DetailsLink;
ViewBag.DeleteLink = Resources.Resource1.DeleteLink;
#endregion
#region ViewBag Sort Params
ViewBag.TitleSortParam = (sortOrder == "Title") ? "Title desc" : "Title";
ViewBag.IsbnSortParam = (sortOrder == "Isbn") ? "Isbn desc" : "Isbn";
ViewBag.AuthorSortParam = (sortOrder == "Author") ? "Author desc" : "Author";
ViewBag.PriceSortParam = (sortOrder == "Price") ? "Price desc" : "Price";
ViewBag.PublishedSortParam = (String.IsNullOrEmpty(sortOrder)) ? "Published desc" : "";
// Default the sort order
if (String.IsNullOrEmpty(sortOrder))
{
sortOrder = "Published desc";
}
ViewBag.CurrentSortOrder = sortOrder;
#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
switch (filter)
{
case "NewReleases":
var startDate = DateTime.Today.AddDays(-14);
books = books.Where(b => b.Published <= DateTime.Today.Date 
&& b.Published >= startDate
);
break;
case "ComingSoon":
books = books.Where(b => b.Published > DateTime.Today.Date);
break;
default:
// No filter needed
break;
}
ViewBag.CurrentFilter = String.IsNullOrEmpty(filter) ? "" : filter;
#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;
}
//
// GET: /Books/Details/5
public ActionResult Details(int id = 0, string bookTitle = "")
{
Book book = db.Books.Find(id);
return View(book);
}
//
// GET: /Books/Create
public ActionResult Create()
{
return View();
} 
//
// POST: /Books/Create
[HttpPost]
public ActionResult Create(Book book, HttpPostedFileBase file)
{
if (ModelState.IsValid)
{
// Upload our file
book.Thumbnail = FileUpload.UploadFile(file);
db.Books.Add(book);
db.SaveChanges();
return RedirectToAction("Index"); 
}
return View(book);
}
//
// GET: /Books/Edit/5
public ActionResult Edit(int id)
{
Book book = db.Books.Find(id);
return View(book);
}
//
// POST: /Books/Edit/5
[HttpPost]
public ActionResult Edit(Book book, HttpPostedFileBase file)
{
if (ModelState.IsValid)
{
// Delete old file
FileUpload.DeleteFile(book.Thumbnail);
// Upload our file
book.Thumbnail = FileUpload.UploadFile(file);
db.Entry(book).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(book);
}
//
// GET: /Books/Delete/5
public ActionResult Delete(int id)
{
Book book = db.Books.Find(id);
return View(book);
}
//
// POST: /Books/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{ 
Book book = db.Books.Find(id);
// Delete old file
FileUpload.DeleteFile(book.Thumbnail);
db.Books.Remove(book);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}

最后book/index view需要更新去初始化jQuery的自动完成。要做的第一件事是使用@节标记,包括必要的JavaScript和CSS文件。接下来,以前创建的搜索文本框更新设置一个键的IDwordSearch。

最后,JavaScript代码添加在视图的底部去在搜索文本框上建立自动完成功能。此JavaScript是有意添加在view的底部,以确保完全呈现给用户,因为在用户的电脑上建立数据是一项工作,Javascript处理可能会“堵塞”页面加载。

(译者:先呈现数据再执行javascript,js不是像传统那样放在head标签里)

这取决于结果的数量。代码如下:

@model PagedList.IPagedList<MvcApplication.Models.Book>
@if (IsAjax)
{
Layout = null;
}
@section JavascriptAndCSS {
<link rel="stylesheet" href="@Url.Content(" rel="external nofollow" rel="external nofollow" ~/Content/jquery.autocomplete.css")" type="text/css" />
<script type="text/javascript" src="@Url.Content("~/Scripts/jquery.autocomplete.js")"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
}
<h2>@MvcApplication4.Resources.Resource1.BookIndexTitle</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<p>
Show:
@if (ViewBag.CurrentFilter != "")
{
@Ajax.ActionLink("All", "Index", new { sortOrder = ViewBag.CurrentSortOrder, Keyword = ViewBag.CurrentKeyword }, new AjaxOptions { UpdateTargetId = "main" })
}
else
{
@:All
}
  |  
@if (ViewBag.CurrentFilter != "NewReleases")
{
@Ajax.ActionLink("New Releases", "Index", new { filter = "NewReleases", sortOrder = ViewBag.CurrentSortOrder, Keyword = ViewBag.CurrentKeyword }, new AjaxOptions { UpdateTargetId = "main" })
}
else
{
@:New Releases
}
  |  
@if (ViewBag.CurrentFilter != "ComingSoon")
{
@Ajax.ActionLink("Coming Soon", "Index", new { filter = "ComingSoon", sortOrder = ViewBag.CurrentSortOrder, Keyword = ViewBag.CurrentKeyword }, new AjaxOptions { UpdateTargetId = "main" })
}
else
{
@:Coming Soon
}
</p>
@using (Html.BeginForm())
{
@:Search: @Html.TextBox("Keyword", (string)ViewBag.CurrentKeyword, new { id = "KeywordSearch" }) <input type="submit" value="Search" />
}
@Html.Partial("_Paging")
<table>
<tr>
<th>
@Ajax.ActionLink("Title", "Index", new { sortOrder = ViewBag.TitleSortParam, filter = ViewBag.CurrentFilter, Keyword = ViewBag.CurrentKeyword }, new AjaxOptions { UpdateTargetId = "main" })
</th>
<th>
@Ajax.ActionLink("Isbn", "Index", new { sortOrder = ViewBag.IsbnSortParam, filter = ViewBag.CurrentFilter, Keyword = ViewBag.CurrentKeyword }, new AjaxOptions { UpdateTargetId = "main" })
</th>
<th>
Summary
</th>
<th>
@Ajax.ActionLink("Author", "Index", new { sortOrder = ViewBag.AuthorSortParam, filter = ViewBag.CurrentFilter, Keyword = ViewBag.CurrentKeyword }, new AjaxOptions { UpdateTargetId = "main" })
</th>
<th>
Thumbnail
</th>
<th>
@Ajax.ActionLink("Price", "Index", new { sortOrder = ViewBag.PriceSortParam, filter = ViewBag.CurrentFilter, Keyword = ViewBag.CurrentKeyword }, new AjaxOptions { UpdateTargetId = "main" })
</th>
<th>
@Ajax.ActionLink("Published", "Index", new { sortOrder = ViewBag.PublishedSortParam, filter = ViewBag.CurrentFilter, Keyword = ViewBag.CurrentKeyword }, new AjaxOptions { UpdateTargetId = "main" })
</th>
<th></th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Isbn)
</td>
<td>
@Html.DisplayFor(modelItem => item.Summary)
</td>
<td>
@Html.DisplayFor(modelItem => item.Author)
</td>
<td>
@Html.DisplayFor(modelItem => item.Thumbnail)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.DisplayFor(modelItem => item.Published)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
@Html.ActionLink("Details", "Details", new { id = item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>
</tr>
}
</table>
@Html.Partial("_Paging")
<script type="text/javascript">
$(document).ready(function () {
var data = "@ViewBag.BookTitles".split("|");
$("#KeywordSearch").autocomplete(data);
});
</script>

为了实施选项2,一个Ajax搜索,而不是传递数据数组到自动完成函数,您可以传递一个URL。URL将需要接受查询字符串变量:q。这包含用户输入的搜索值。这将用于执行书本上包含部分匹配的搜索,并返回以分隔符分隔的字符串。JQuery文档中含有较多的这样的成品例子,也有其他的例子,去更新的输出结果(可能包括书的封面的缩略图)。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

jQuery 相关文章推荐
jQuery extend()详解及简单实例
May 06 jQuery
jQuery 表单序列化实例代码
Jun 11 jQuery
vue单页应用中如何使用jquery的方法示例
Jul 27 jQuery
jQuery取得元素标签名称小结(附代码)
Aug 16 jQuery
认识jQuery的Promise的具体使用方法
Oct 10 jQuery
jQuery实现的监听导航滚动置顶状态功能示例
Jul 23 jQuery
jQuery.parseJSON()函数详解
Feb 28 jQuery
通过jQuery学习js类型判断的技巧
May 27 jQuery
基于jQuery实现挂号平台首页源码
Jan 06 jQuery
jquery实现垂直手风琴导航栏
Feb 18 jQuery
Jquery滑动门/tab切换实现方法完整示例
Jun 05 jQuery
jQuery实现带进度条的轮播图
Sep 13 jQuery
使用异步controller与jQuery实现卷帘式分页
Jun 18 #jQuery
使用jQuery mobile NuGet让你的网站在移动设备上同样精彩
Jun 18 #jQuery
如何使用CSS3和JQuery easing 插件制作绚丽菜单
Jun 18 #jQuery
如何用webpack4.0撸单页/多页脚手架 (jquery, react, vue, typescript)
Jun 18 #jQuery
通过JQuery,JQueryUI和Jsplumb实现拖拽模块
Jun 18 #jQuery
如何使用CSS3+JQuery实现悬浮墙式菜单
Jun 18 #jQuery
jquery中为什么能用$操作
Jun 18 #jQuery
You might like
深入理解PHP原理之Session Gc的一个小概率Notice
2011/04/12 PHP
php随机获取金山词霸每日一句的方法
2015/07/09 PHP
Thinkphp和onethink实现微信支付插件
2016/04/13 PHP
基于dom编程中 动态创建与删除元素的使用
2013/04/17 Javascript
JS中typeof与instanceof之间的区别总结
2013/11/14 Javascript
jquery基础教程之数组使用详解
2014/03/10 Javascript
谈谈JSON对象和字符串之间的相互转换JSON.stringify(obj)和JSON.parse(string)
2015/10/01 Javascript
JS实现自动轮播图效果(自适应屏幕宽度+手机触屏滑动)
2017/06/19 Javascript
jQuery实现火车票买票城市选择切换功能
2017/09/15 jQuery
nodejs简单实现TCP服务器端和客户端的聊天功能示例
2018/01/04 NodeJs
微信小程序实现全国机场索引列表
2018/01/31 Javascript
jquery 动态遍历select 赋值的实例
2018/09/12 jQuery
详解element-ui日期时间选择器的日期格式化问题
2019/04/08 Javascript
详解element-ui 表单校验 Rules 配置 常用黑科技
2020/07/11 Javascript
Js on及addEventListener原理用法区别解析
2020/07/11 Javascript
[38:42]完美世界DOTA2联赛循环赛 Matador vs Forest BO2第二场 11.05
2020/11/05 DOTA
[52:03]DOTA2-DPC中国联赛 正赛 Ehome vs iG BO3 第三场 1月31日
2021/03/11 DOTA
如何搜索查找并解决Django相关的问题
2014/06/30 Python
深入理解Javascript中的this关键字
2015/03/27 Python
Python下简易的单例模式详解
2019/04/08 Python
Django的models模型的具体使用
2019/07/15 Python
python中for in的用法详解
2020/04/17 Python
Python接口自动化测试的实现
2020/08/28 Python
CSS3 border-image详解、应用及jQuery插件
2011/08/29 HTML / CSS
html5 实现客户端验证上传文件的大小(简单实例)
2016/05/15 HTML / CSS
HTML5中使用json对象的实例代码
2018/09/10 HTML / CSS
init进程的作用
2012/04/12 面试题
轻金属冶金专业毕业生自荐信
2013/11/02 职场文书
服装厂厂长岗位职责
2013/12/27 职场文书
给朋友的道歉信
2014/01/09 职场文书
2015年见习期工作总结
2014/12/12 职场文书
2015元旦主持词开场白和结束语
2014/12/14 职场文书
感恩教师主题班会
2015/08/12 职场文书
python实现调用摄像头并拍照发邮箱
2021/04/27 Python
使用kubeadm命令行工具创建kubernetes集群
2022/03/31 Servers
apache虚拟主机配置的三种方式(小结)
2022/07/23 Servers