autocomplete

html文件:

1
<input id="theInput"type="text" autocomplete="off">
js文件:

1
this.initAutoComplete = function () { 2 $("#theInput").autocomplete({                        //将$("#theInput")绑上autocomplete 3 source: function (request, response) {                 //source 参数 4 $.ajax({ 5 type: 'post', 6 url: "/CustomAccount/GetADUsers", 7 dataType: "json", 8 data: { mail: request.term,isall:false }, //mail:request.term 传进去的是在#theInput中输入的值 9 success: function (data) { 10 response($.map(data, function (item) { 11 return { 12 displayname: item 13 }; 14 })); 15 } 16 }); 17 }, 18 select: function (event, ui) {         //select参数 19 $(this).val(ui.item.displayname); 20 return false; 21 }, 22 max: 10, 23 }).each(function () { 24 $(this).data("autocomplete")._renderItem = function (ul, item) { //重写了autocomplete里面的_renderItem函数 25 return $("<li>") 26 .data("item.autocomplete", item) 27 .append("<a data-type='autocomplete-item'>" + item.displayname + "</a>").attr('title', item.displayname) 28 .appendTo(ul); 29 }; 30 }); 31 };

前台js调用这个initAutoComplete 函数,利用ajax在controller里面取值,controller


CustomAccountController里面的GetADUsers方法:
1  [HttpPost]
2  public ActionResult GetADUsers(string mail, Boolean isall)
3 {
4   var results = this.systemUserService.FindADUsers(mail, isall);                           //return 一个list<String>,是根据传进来的mail值过滤的
5   results.AddRange(this.systemUserService.FindADGroups(mail, isall).Select(g => g.Email));//在原来的results里加上另一个根据传进来的mail值过滤的的List<> 
6
results.Sort(); //排序
7
return this.Json(results, JsonRequestBehavior.AllowGet);
8
}

 附件jQuery UI Autocomplete 1.9.1:

  1 /*!
  2  * jQuery UI Autocomplete 1.9.1
  3  * http://jqueryui.com
  4  *
  5  * Copyright 2012 jQuery Foundation and other contributors
  6  * Released under the MIT license.
  7  * http://jquery.org/license
  8  *
  9  * http://api.jqueryui.com/autocomplete/
 10  *
 11  * Depends:
 12  *    jquery.ui.core.js
 13  *    jquery.ui.widget.js
 14  *    jquery.ui.position.js
 15  *    jquery.ui.menu.js
 16  */
 17 (function ($, undefined) {
 18 
 19     // used to prevent race conditions with remote data sources
 20     var requestIndex = 0;
 21 
 22     $.widget("ui.autocomplete", {
 23         version: "1.9.1",
 24         defaultElement: "<input>",
 25         options: {
 26             appendTo: "body",
 27             autoFocus: false,
 28             delay: 300,
 29             minLength: 1,
 30             position: {
 31                 my: "left top",
 32                 at: "left bottom",
 33                 collision: "none"
 34             },
 35             source: null,            
 36             // callbacks
 37             change: null,
 38             close: null,
 39             focus: null,
 40             open: null,
 41             response: null,
 42             search: null,
 43             select: null,
 44              0,
 45             max: 10,
 46 
 47         },
 48 
 49         pending: 0,
 50 
 51         _create: function () {
 52             // Some browsers only repeat keydown events, not keypress events,
 53             // so we use the suppressKeyPress flag to determine if we've already
 54             // handled the keydown event. #7269
 55             // Unfortunately the code for & in keypress is the same as the up arrow,
 56             // so we use the suppressKeyPressRepeat flag to avoid handling keypress
 57             // events when we know the keydown event was used to modify the
 58             // search term. #7799
 59             var suppressKeyPress, suppressKeyPressRepeat, suppressInput;
 60 
 61             this.isMultiLine = this._isMultiLine();
 62             this.valueMethod = this.element[this.element.is("input,textarea") ? "val" : "text"];
 63             this.isNewMenu = true;
 64 
 65             this.element
 66                 .addClass("ui-autocomplete-input")
 67                 .attr("autocomplete", "off");
 68 
 69             this._on(this.element, {
 70                 keydown: function (event) {
 71                     if (this.element.prop("readOnly")) {
 72                         suppressKeyPress = true;
 73                         suppressInput = true;
 74                         suppressKeyPressRepeat = true;
 75                         return;
 76                     }
 77 
 78                     suppressKeyPress = false;
 79                     suppressInput = false;
 80                     suppressKeyPressRepeat = false;
 81                     var keyCode = $.ui.keyCode;
 82                     switch (event.keyCode) {
 83                         case keyCode.PAGE_UP:
 84                             suppressKeyPress = true;
 85                             this._move("previousPage", event);
 86                             break;
 87                         case keyCode.PAGE_DOWN:
 88                             suppressKeyPress = true;
 89                             this._move("nextPage", event);
 90                             break;
 91                         case keyCode.UP:
 92                             suppressKeyPress = true;
 93                             this._keyEvent("previous", event);
 94                             break;
 95                         case keyCode.DOWN:
 96                             suppressKeyPress = true;
 97                             this._keyEvent("next", event);
 98                             break;
 99                         case keyCode.ENTER:
100                         case keyCode.NUMPAD_ENTER:
101                             // when menu is open and has focus
102                             if (this.menu.active) {
103                                 // #6055 - Opera still allows the keypress to occur
104                                 // which causes forms to submit
105                                 suppressKeyPress = true;
106                                 event.preventDefault();
107                                 this.menu.select(event);
108                             }
109                             break;
110                         case keyCode.TAB:
111                             if (this.menu.active) {
112                                 this.menu.select(event);
113                             }
114                             break;
115                         case keyCode.ESCAPE:
116                             if (this.menu.element.is(":visible")) {
117                                 this._value(this.term);
118                                 this.close(event);
119                                 // Different browsers have different default behavior for escape
120                                 // Single press can mean undo or clear
121                                 // Double press in IE means clear the whole form
122                                 event.preventDefault();
123                             }
124                             break;
125                         default:
126                             suppressKeyPressRepeat = true;
127                             // search timeout should be triggered before the input value is changed
128                             this._searchTimeout(event);
129                             break;
130                     }
131                 },
132                 keypress: function (event) {
133                     if (suppressKeyPress) {
134                         suppressKeyPress = false;
135                         event.preventDefault();
136                         return;
137                     }
138                     if (suppressKeyPressRepeat) {
139                         return;
140                     }
141 
142                     // replicate some key handlers to allow them to repeat in Firefox and Opera
143                     var keyCode = $.ui.keyCode;
144                     switch (event.keyCode) {
145                         case keyCode.PAGE_UP:
146                             this._move("previousPage", event);
147                             break;
148                         case keyCode.PAGE_DOWN:
149                             this._move("nextPage", event);
150                             break;
151                         case keyCode.UP:
152                             this._keyEvent("previous", event);
153                             break;
154                         case keyCode.DOWN:
155                             this._keyEvent("next", event);
156                             break;
157                     }
158                 },
159                 input: function (event) {
160                     if (suppressInput) {
161                         suppressInput = false;
162                         event.preventDefault();
163                         return;
164                     }
165                     this._searchTimeout(event);
166                 },
167                 focus: function () {
168                     this.selectedItem = null;
169                     this.previous = this._value();
170                 },
171                 blur: function (event) {
172                     if (this.cancelBlur) {
173                         delete this.cancelBlur;
174                         return;
175                     }
176 
177                     clearTimeout(this.searching);
178                     this.close(event);
179                     this._change(event);
180                 }
181             });
182 
183             this._initSource();
184             this.menu = $("<ul>")
185                 .addClass("ui-autocomplete")
186                 .appendTo(this.document.find(this.options.appendTo || "body")[0])
187                 .menu({
188                     // custom key handling for now
189                     input: $(),
190                     // disable ARIA support, the live region takes care of that
191                     role: null
192                 })
193                 .zIndex(this.element.zIndex() + 1)
194                 .hide()
195                 .data("menu");
196 
197             this._on(this.menu.element, {
198                 mousedown: function (event) {
199                     // prevent moving focus out of the text field
200                     event.preventDefault();
201 
202                     // IE doesn't prevent moving focus even with event.preventDefault()
203                     // so we set a flag to know when we should ignore the blur event
204                     this.cancelBlur = true;
205                     this._delay(function () {
206                         delete this.cancelBlur;
207                     });
208 
209                     // clicking on the scrollbar causes focus to shift to the body
210                     // but we can't detect a mouseup or a click immediately afterward
211                     // so we have to track the next mousedown and close the menu if
212                     // the user clicks somewhere outside of the autocomplete
213                     var menuElement = this.menu.element[0];
214                     if (!$(event.target).closest(".ui-menu-item").length) {
215                         this._delay(function () {
216                             var that = this;
217                             this.document.one("mousedown", function (event) {
218                                 if (event.target !== that.element[0] &&
219                                         event.target !== menuElement &&
220                                         !$.contains(menuElement, event.target)) {
221                                     that.close();
222                                 }
223                             });
224                         });
225                     }
226                 },
227                 menufocus: function (event, ui) {
228                     // #7024 - Prevent accidental activation of menu items in Firefox
229                     if (this.isNewMenu) {
230                         this.isNewMenu = false;
231                         if (event.originalEvent && /^mouse/.test(event.originalEvent.type)) {
232                             this.menu.blur();
233 
234                             this.document.one("mousemove", function () {
235                                 $(event.target).trigger(event.originalEvent);
236                             });
237 
238                             return;
239                         }
240                     }
241 
242                     // back compat for _renderItem using item.autocomplete, via #7810
243                     // TODO remove the fallback, see #8156
244                     var item = ui.item.data("ui-autocomplete-item") || ui.item.data("item.autocomplete");
245                     if (false !== this._trigger("focus", event, { item: item })) {
246                         // use value to match what will end up in the input, if it was a key event
247                         if (event.originalEvent && /^key/.test(event.originalEvent.type)) {
248                             this._value(item.value);
249                         }
250                     } else {
251                         // Normally the input is populated with the item's value as the
252                         // menu is navigated, causing screen readers to notice a change and
253                         // announce the item. Since the focus event was canceled, this doesn't
254                         // happen, so we update the live region so that screen readers can
255                         // still notice the change and announce it.
256                         this.liveRegion.text(item.value);
257                     }
258                 },
259                 menuselect: function (event, ui) {
260                     // back compat for _renderItem using item.autocomplete, via #7810
261                     // TODO remove the fallback, see #8156
262                     var item = ui.item.data("ui-autocomplete-item") || ui.item.data("item.autocomplete"),
263                         previous = this.previous;
264 
265                     // only trigger when focus was lost (click on menu)
266                     if (this.element[0] !== this.document[0].activeElement) {
267                         this.element.focus();
268                         this.previous = previous;
269                         // #6109 - IE triggers two focus events and the second
270                         // is asynchronous, so we need to reset the previous
271                         // term synchronously and asynchronously :-(
272                         this._delay(function () {
273                             this.previous = previous;
274                             this.selectedItem = item;
275                         });
276                     }
277 
278                     if (false !== this._trigger("select", event, { item: item })) {
279                         this._value(item.value);
280                     }
281                     // reset the term after the select event
282                     // this allows custom select handling to work properly
283                     this.term = this._value();
284 
285                     this.close(event);
286                     this.selectedItem = item;
287                 }
288             });
289 
290             this.liveRegion = $("<span>", {
291                 role: "status",
292                 "aria-live": "polite"
293             })
294                 .addClass("ui-helper-hidden-accessible");
295                 //.insertAfter(this.element);
296 
297             if ($.fn.bgiframe) {
298                 this.menu.element.bgiframe();
299             }
300 
301             // turning off autocomplete prevents the browser from remembering the
302             // value when navigating through history, so we re-enable autocomplete
303             // if the page is unloaded before the widget is destroyed. #7790
304             this._on(this.window, {
305                 beforeunload: function () {
306                     this.element.removeAttr("autocomplete");
307                 }
308             });
309         },//end _create
310 
311         _destroy: function () {
312             clearTimeout(this.searching);
313             this.element
314                 .removeClass("ui-autocomplete-input")
315                 .removeAttr("autocomplete");
316             this.menu.element.remove();
317             this.liveRegion.remove();
318         },
319 
320         _setOption: function (key, value) {
321             this._super(key, value);
322             if (key === "source") {
323                 this._initSource();
324             }
325             if (key === "appendTo") {
326                 this.menu.element.appendTo(this.document.find(value || "body")[0]);
327             }
328             if (key === "disabled" && value && this.xhr) {
329                 this.xhr.abort();
330             }
331         },
332 
333         _isMultiLine: function () {
334             // Textareas are always multi-line
335             if (this.element.is("textarea")) {
336                 return true;
337             }
338             // Inputs are always single-line, even if inside a contentEditable element
339             // IE also treats inputs as contentEditable
340             if (this.element.is("input")) {
341                 return false;
342             }
343             // All other element types are determined by whether or not they're contentEditable
344             return this.element.prop("isContentEditable");
345         },
346 
347         _initSource: function () {
348             var array, url,
349                 that = this;
350             if ($.isArray(this.options.source)) {
351                 array = this.options.source;
352                 this.source = function (request, response) {
353                     response($.ui.autocomplete.filter(array, request.term));
354                 };
355             } else if (typeof this.options.source === "string") {
356                 url = this.options.source;
357                 this.source = function (request, response) {
358                     if (that.xhr) {
359                         that.xhr.abort();
360                     }
361                     that.xhr = $.ajax({
362                         url: url,
363                         data: request,
364                         dataType: "json",
365                         success: function (data) {
366                             response(data);
367                         },
368                         error: function () {
369                             response([]);
370                         }
371                     });
372                 };
373             } else {
374                 this.source = this.options.source;
375             }
376         },
377 
378         _searchTimeout: function (event) {
379             clearTimeout(this.searching);
380             this.searching = this._delay(function () {
381                 // only search if the value has changed
382                 if (this.term !== this._value()) {
383                     this.selectedItem = null;
384                     this.search(null, event);
385                 }
386             }, this.options.delay);
387         },
388 
389         search: function (value, event) {
390             value = value != null ? value : this._value();
391 
392             // always save the actual value, not the one passed as an argument
393             this.term = this._value();
394 
395             if (value.length < this.options.minLength) {
396                 return this.close(event);
397             }
398 
399             if (this._trigger("search", event) === false) {
400                 return;
401             }
402 
403             return this._search(value);
404         },
405 
406         _search: function (value) {
407             this.pending++;
408             this.element.addClass("ui-autocomplete-loading");
409             this.cancelSearch = false;
410 
411             this.source({ term: value }, this._response());
412         },
413 
414         _response: function () {
415             var that = this,
416                 index = ++requestIndex;
417 
418             return function (content) {
419                 if (index === requestIndex) {
420                     that.__response(content);
421                 }
422 
423                 that.pending--;
424                 if (!that.pending) {
425                     that.element.removeClass("ui-autocomplete-loading");
426                 }
427             };
428         },
429 
430         __response: function (content) {
431             if (content) {
432                 content = this._normalize(content);
433             }
434             this._trigger("response", null, { content: content });
435             //content && content.length && 
436             if (!this.options.disabled && !this.cancelSearch) {
437                 this._suggest(content);
438                 this._trigger("open");
439             } else {
440                 // use ._close() instead of .close() so we don't cancel future searches
441                 this._close();
442             }
443         },
444 
445         close: function (event) {
446             this.cancelSearch = true;
447             this._close(event);
448         },
449 
450         _close: function (event) {
451             if (this.menu.element.is(":visible")) {
452                 this.menu.element.hide();
453                 this.menu.blur();
454                 this.isNewMenu = true;
455                 this._trigger("close", event);
456             }
457         },
458 
459         _change: function (event) {
460             if (this.previous !== this._value()) {
461                 this._trigger("change", event, { item: this.selectedItem });
462             }
463         },
464 
465         _normalize: function (items) {
466             // assume all items have the right format when the first item is complete
467             if (items.length && items[0].label && items[0].value) {
468                 return items;
469             }
470             return $.map(items, function (item) {
471                 if (typeof item === "string") {
472                     return {
473                         label: item,
474                         value: item
475                     };
476                 }
477                 return $.extend({
478                     label: item.label || item.value,
479                     value: item.value || item.label
480                 }, item);
481             });
482         },
483 
484         _suggest: function (items) {
485             var ul = this.menu.element
486                 .empty()
487                 .zIndex(this.element.zIndex() + 1);
488             this._renderMenu(ul, items);
489             this.menu.refresh();
490             // size and position menu
491             ul.show();
492             this._resizeMenu();
493             ul.position($.extend({
494                 of: this.element
495             }, this.options.position));
496 
497             if (this.options.autoFocus) {
498                 this.menu.next();
499             }
500         },
501 
502         _resizeMenu: function () {
503             var that = this;
504             var ul = this.menu.element;
505             
506             ul.outerWidth(                
507                 this.element.outerWidth()
508             );
509             
510             
511         },
512 
513         _limitNumberOfItems:function(available) {
514             return this.options.max && this.options.max < available
515             ? this.options.max
516             : available;
517         },
518 
519         _renderMenu: function (ul, items) {
520             var that = this;
521             var max = that._limitNumberOfItems(items.length);
522             var num = 0;
523             for (var i = 0; i < max; i++) {      
524                     that._renderItemData(ul, items[i]);
525                     num++;  
526             }
527             //$.each(items, function (index, item) {
528             //    that._renderItemData(ul, item);
529             //    num++;
530             //});           
531             var bottomlist = "<span class='autocomplete_bottom'>" +
532                                 "<span class='firstline'>Showing " +num+" Users</span>" +
533                                 "<span class='secondline' >"+
534                                     "<span class='sprite-icon sprite-icon-info-16x16'></span>"+
535                                     "<span class='autocomplete_bottom_txt'>Please type in more characters to narrow down the results.</span>" +
536                                 "</span></span>";
537             ul.append(bottomlist);
538             if (num == 0) {
539                 $('.secondline').hide();
540                 $('.firstline').text('No search results.');
541             }
542         },
543 
544         _renderItemData: function (ul, item) {
545             return this._renderItem(ul, item).data("ui-autocomplete-item", item);
546         },
547 
548         _renderItem: function (ul, item) {
549             return $("<li>")
550                 .append($("<a>").text(item.label))
551                 .appendTo(ul);
552         },
553 
554         _move: function (direction, event) {
555             if (!this.menu.element.is(":visible")) {
556                 this.search(null, event);
557                 return;
558             }
559             if (this.menu.isFirstItem() && /^previous/.test(direction) ||
560                     this.menu.isLastItem() && /^next/.test(direction)) {
561                 this._value(this.term);
562                 this.menu.blur();
563                 return;
564             }
565             this.menu[direction](event);
566         },
567 
568         widget: function () {
569             return this.menu.element;
570         },
571 
572         _value: function () {
573             return this.valueMethod.apply(this.element, arguments);
574         },
575 
576         _keyEvent: function (keyEvent, event) {
577             if (!this.isMultiLine || this.menu.element.is(":visible")) {
578                 this._move(keyEvent, event);
579 
580                 // prevents moving cursor to beginning/end of the text field in some browsers
581                 event.preventDefault();
582             }
583         }
584     });//end $.widget()
585 
586 
587     $.extend($.ui.autocomplete, {
588         escapeRegex: function (value) {
589             return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
590         },
591         filter: function (array, term) {
592             var matcher = new RegExp($.ui.autocomplete.escapeRegex(term), "i");
593             return $.grep(array, function (value) {
594                 return matcher.test(value.label || value.value || value);
595             });
596         }
597     });
598 
599     // live region extension, adding a `messages` option
600     // NOTE: This is an experimental API. We are still investigating
601     // a full solution for string manipulation and internationalization.
602     $.widget("ui.autocomplete", $.ui.autocomplete, {
603         options: {
604             messages: {
605                 noResults: "No search results.",
606                 results: function (amount) {
607                     return amount + (amount > 1 ? " results are" : " result is") +
608                         " available, use up and down arrow keys to navigate.";
609                 }
610             }
611         },
612 
613         __response: function (content) {
614             var message;
615             this._superApply(arguments);
616             if (this.options.disabled || this.cancelSearch) {
617                 return;
618             }
619             if (content && content.length) {
620                 message = this.options.messages.results(content.length);
621             } else {
622                 message = this.options.messages.noResults;
623             }
624             this.liveRegion.text(message).css('position','');
625         }
626     });
627 
628 
629 }(jQuery));
View Code
原文地址:https://www.cnblogs.com/mousehhq/p/4365987.html