问题

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

解决方案

使用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="/UploadFiles/2021-04-02/@Url.Content(">

主要的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"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="/UploadFiles/2021-04-02/@Url.Content(">

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

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

广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!

稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!

昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。

这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。

而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?