请选择 进入手机版 | 继续访问电脑版
查看: 495|回复: 0

[.NET源码] 如何让jQuery.ui.Autocomplete显示前N条数据-两种实例(Server&Client)

3万

主题

3万

帖子

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
100197
发表于 2015-11-19 18:07:00

前言

现在的 Web Service 越来越重视使用者经验(User Experience),在网页上我们也满常看到 AutoComplete 这种 jQuery Plug-in 能让使用者在搜寻资料上更佳的方便,就像是常见的搜寻引擎我们只需输入几个字就会跳出相关的资料让我们能更快速的找到我们要的东西,前阵子在专案的上刚好碰到类似的需求,所以就先记录下来啰 ~

范例说明

这个范例会利用 ASP.NET MVC Web Api +jQuery-UI 来实作,并且会分为两种范例,如下:

第一种是利用 Server 端来达到我们的需求:

透过 WebApi 服务端搭配 LINQ 操作资料库,使用 StartWith 方法来达到从头比较,排序后在以 Take 的函式传回前N笔资料。

而这个作法也会比较简单,因为搭配 LINQ 来操作资料库可以轻松达到我们所要的需求。

第二种是透过 Client 端的 Javascript 来达到我们的需求(范例在范例一结束后)

结果如下图:


开始实作

1.先建立一个简单的 View,并在页面上引用需要的 js 档

  1. @{
  2. ViewBag.Title = "Server";
  3. }
  4. @section styles{
  5. <link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
  6. <style>
  7. .ui-autocomplete {
  8. max-height: 100px;
  9. overflow-y: auto;
  10. overflow-x: hidden;
  11. }
  12. * html .ui-autocomplete {
  13. height: 100px;
  14. }
  15. td {
  16. padding: 0;
  17. }
  18. </style>
  19. }
  20. <h2>Server Base</h2>
  21. <div>
  22. <input type="text" id="autocomplet_Server" />
  23. </div>
  24. @section scripts{
  25. <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
  26. <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
  27. }
复制代码

我们的 View 就真的那么简单 ~

2.Web Api

  1. public class AutoCompleteController : ApiController
  2. {
  3. private DotBlogEntities db = new DotBlogEntities();
  4. // GET api/AutoComplete
  5. public IEnumerable GetProducts(string term)
  6. {
  7. int length = 10;// length = 回传几笔的参数
  8. // term = 使用者输入的term
  9. var Produtct = db.Product.Where(p => p.ProductId.StartsWith(term))
  10. .OrderByDescending(p => p.ProductId).Take(length)
  11. .Select(p => new { Id = p.ProductId, Name = p.Name }).AsEnumerable();
  12. return Produtct;
  13. }
  14. }
复制代码

利用 WebApi 来当我们的 Web Service,参数 term 会接收使用者在前端页面输入的 term,并利用 StartWith 的函数做资料比对,等同于SQL 的语法 "Like term%",而返回资料后依照主键做排序,然后 Take 前几笔资料,操作逻辑还满前显易懂的,等于我们把对资料这端的处理都交给了后端的资料库,最后返回至页面端,前端接收到后直接负责做资料显示,而不用再针对资料做处理 ~www.it165.net

3. Javascript 部分:

这边运用了类似 cache 的概念,记录使用者输入的 term 以及 response 的资料,当下次使用者输入同样的 term 就不会在跟 Server 请求,而是直接取出存在记忆体内的资料以减轻 Server 的负担。

  1. $(function () {
  2. var cache = {};
  3. $("#autocomplet_Server").autocomplete({
  4. minLength: 1,
  5. source: function (request, response) {
  6. var term = request.term;
  7. if (term in cache) {
  8. response(cache[term]);
  9. return;
  10. }
  11. $.getJSON("/Api/AutoComplete/GetProducts", request, function (data, status, xhr) {
  12. cache[term] = data;
  13. response(data);
  14. });
  15. },
  16. select: function (event, ui) {
  17. this.value = ui.item.Id;
  18. return false;
  19. }
  20. }).data("ui-autocomplete")._renderItem = function (ul, item) {
  21. return $("<li>")
  22. .append("<a>" + item.Id + "
  23. " + item.Name + "</a>)
  24. .appendTo(ul);
  25. };
复制代码

第二个实例是透过 Client 端的 Javascript 来达到我们的需求,如下

1.View 的部分跟范例一相同,所以就不再赘述了。

2.Web Api

  1. public IEnumerable GetProducts()
  2. {
  3. var Produtct = db.Product.OrderByDescending(p => p.ProductId)
  4. .Select(p => new { Id = p.ProductId, Name = p.Name }).AsEnumerable();
  5. return Produtct;
  6. }
复制代码

这段程式码就更简单的,不进行任何过滤只做了排序以及 Select 我们要的栏位,最后就直接丢回页面端。

3.Javascript 部分

先想想我们的需求是,当使用者输入某个 term 后会从头比较并且只显示前N笔资料,因为 Server 端无法预先知道使用者会输入哪些 term 所以需要在一开始载入页面时就先将 DB 内的资料捞回来,如下:

  1. var data = [];
  2. $(window).load(function () {
  3. $.getJSON("/Api/AutoComplete/GetProducts", function (response, status, xhr) {
  4. data = response;
  5. });
  6. });
复制代码

最后在利用$.grep + Regex 来筛选存放于阵列中的资料,因为 $.grep 会遍历阵列里的每个值,而每次会用 regex 来进行字串笔对,若有符合的则 length 值会减一,直到小于 0 之后就不再做了,代码如下:

  1. $(function () {
  2. var cache = {};
  3. $("#autocomplet_Server").autocomplete({
  4. minLength: 1,
  5. source: function (request, response) {
  6. var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(request.term), "i");
  7. var length = 10;
  8. var res = $.grep(data, function (item) {
  9. if (length > 0) {
  10. if (matcher.test(item.Id)) {
  11. length = length - 1;
  12. return matcher.test(item.Id);
  13. }
  14. }
  15. });
  16. response(res);
  17. },
  18. select: function (event, ui) {
  19. this.value = ui.item.Id;
  20. return false;
  21. }
  22. }).data("ui-autocomplete")._renderItem = function (ul, item) {
  23. return $("<li>") .append("<a>" + item.Id + "
  24. " + item.Name + "</a>") .appendTo(ul);
  25. };
  26. });
复制代码

总结

1.两种做法都能达到相同的效果,而第一种范例也是一般实务上比较常见的作法,笔者也趁机去看了一下 Google 的搜寻机制也是透过此概念设计的,因为当使用者有输入到这个 term 才会到资料库去进行查询并回传前N笔资料,能大幅减少我们的传输量。

2.第二个范例比较需要注意的地方是在回传前N笔资料的部分,笔者当初再写的时候因为特定某个 term 符合的项目非常多,导致使用者只要输入到那个 term 显示出来的时间就会非常慢,最后加上了回传前N笔资料之后就解决了。



回复

使用道具 举报