65.9K
CodeProject 正在变化。 阅读更多。
Home

JQueryUI smartAutocomplete

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (9投票s)

2012年2月6日

CPOL

3分钟阅读

viewsIcon

84964

downloadIcon

3256

这个小部件通过在从远程源加载数据时添加无限滚动,扩展了 jQueryUI Autocomplete 小部件的功能。

jquery-smartautocomplete_1

引言

这个小部件通过在从远程源加载数据时添加无限滚动,扩展了 jQueryUI Autocomplete 小部件 的功能。

您可以在 我的博客上找到原始文章。

先决条件

  • JavaScript, jQuery, jQueryUI
  • ASP.NET

背景

假设我们有一个项目正在使用 Autocomplete Widget,并且每次按键给出的结果数量非常多,影响了应用程序的响应速度。

我们希望能够最初只加载少量项目,并且对于每次其他请求,只加载给定数量的项目。 因此,我们将加载前 N 个项目,并且当用户到达最后一个项目时(通过滚动到它或不断按下向下键直到到达最后一个项目),我们向服务器发出另一个请求以加载接下来的 N 个项目。

Using the Code

假设我们有一个输入框

<input id="inp" style="width: 350px;" type="text" />

以及小部件实现

$("#inp").autocomplete(options);

有关此代码的更多详细信息,请访问 jQueryUI Autocomplete 文档网站

我们希望尽可能少地更改代码,以获得无限滚动的预期效果。 新代码将如下所示

$("#inp").smartautocomplete({
   getDataFunc: getData,
   pageSize: 15
   ...
});

为了本示例的目的,我使用了一个 ASP.NET 应用程序,该应用程序公开了一个 WebMethod,该方法返回一些虚拟数据以与我们的输入一起使用。 该函数如下所示

//In this example I use a WebMethod, but you can call anything from a 
//local source to a web service.
var getData = function (input, pageIndex, pageSize, callback) {
   PageMethods.GetData(input, pageIndex, pageSize, function (response) {
      if (response) {
         //Data is assumed to be received in a {label: , value: , ...} form, 
         //as needed by jQueryUI Autocomplete. Of course, if you change 
         //the _renderItem function, you are free to modify this as you want
         response = $.map(response, function (item) {
              return {
            label: item,
        value: item
     }});
     callback(response);
      }
      else callback();
   });
}

如上所示,我们有一个从中获取数据的来源。 它可以是 Web 服务或其他任何东西。

代码

我们将不得不创建一个包装器小部件,该小部件在下面具有原始的自动完成小部件,但是以略有不同的方式处理数据加载逻辑。 我们首先按照 jQuery 插件创作文档的说明创建一个 jQuery 插件。 新的小部件将采用两个新参数

  1. pageSize:每次请求加载的项目数
  2. getDataFunc:用于从服务器返回数据的要调用的函数

我们用我们自己的函数覆盖 option.source 参数,该函数可以执行魔法

//We overwrite the source logic to call our getDataFunc function
options.source = function (request, response) {
   ...
   //We call the function to get the data
   options.getDataFunc(term, pageIndex + 1, options.pageSize, function (r) {
      if (r) {
         //We allow scrolling
         if (!r.length)
         startedLoadingFromScroll = false;
         //If data already exists, we add our new data to the existing data
         if (data.length)
            for (var i = 0; i < r.length; i++)
               data.push(r[i]);
         else data = r;
         response(data);
         //We scroll to the last position
         autocomplete.scrollTop(lastScrollTop);
         //We increment the current page index
         pageIndex++;
      }
   });
   ...
};

接下来,我们绑定到由自动完成小部件触发的几个事件。 我们首先绑定到 autocompletecreate 事件,以便在自动完成小部件创建后立即实现我们自己的功能。 在这里,我们将绑定到自动完成下拉列表的滚动事件,以处理我们到达列表末尾的情况。 我们通过不断验证以下不等式来实现此目的

autocomplete[0].scrollHeight - autocomplete.scrollTop()

只有当我们滚动到列表末尾时,结果才为 true。 如果是这种情况,我们将调用我们的 startSearching 函数。

.bind('autocompletecreate', function () {
   //We get the elements created by JqueryUI Autocomplete
   autocomplete = $(this).autocomplete('widget');
   menu = parent.data().autocomplete.menu.element;
   if (autocomplete.attr('sa-scroll') != 'on') {
      //We create the scrolling functionality to request new data 
      //when we arrived at the end of list
         autocomplete.scroll(function (e) {
         if (loading)
            return stopEvent(e);
         if (startedLoadingFromScroll) {
            if ($.browser.msie || $.browser.mozilla)
               autocomplete.scrollTop(lastScrollTop);
            return stopEvent(e);
         }
         if (autocomplete[0].scrollHeight - autocomplete.scrollTop()

接下来,我们绑定到 autocompletefocus。 每次我们使用键盘在下拉项中导航时,都会调用此方法。 默认情况下,自动完成为焦点元素提供类 ui-state-hover。 因此,通过验证 autocomplete.find(".ui-menu-item:last .ui-state-hover").length == 1,我们可以确定*最后一项已聚焦。 这是我们需要加载更多数据的另一种情况。

.bind('autocompletefocus', function (event, ui) {
   focusedItem = ui.item;
   if (ignoreFocus) {
      ignoreFocus = false;
      return;
   }
   //If we reached the last element in the list, we get new data
   if (autocomplete.find(".ui-menu-item:last .ui-state-hover").length)
   startSearching();
})

*jQueryUI 有一种特定的方式来呈现列表项。 如果我们 更改项的呈现方式,则必须重新考虑此验证。

然后,我们绑定到 autocompleteopen 以将焦点设置到下拉列表关闭之前最后聚焦的项目。

.bind('autocompleteopen', function (event, ui) {
   if (!selectedIndex) {
      if (options.autoFocus) {
         ignoreFocus = true;
         menu.menu('activate', event, autocomplete.find(".ui-menu-item:first"));
      }
   }
   else {
      ignoreFocus = true;
      menu.menu('activate', event, autocomplete.find
    (".ui-menu-item:eq(" + selectedIndex + ")"));
   }
})

我们要做的最后一件事是绑定到 autocompleteclose 以重置我们的搜索数据。

.bind('autocompleteclose', function (event, ui) {
   //When the dropdown closes, we reset the current search
   resetData();
})

未来开发需要考虑的事项

  1. 该小部件利用了尚未发布的 Menu Widget。 因此,其功能的任何更改都会直接影响我们的功能。
  2. 我们基于以下前提找到焦点项目的算法:它具有 ui-state-hover 类。 当自定义搜索结果渲染系统时,这可能不是一件好事。
  3. 应为本地源实现分页。

历史

  • 2012 年 2 月 4 日:初始版本
  • 2012 年 2 月 22 日:更新的源代码
© . All rights reserved.