欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

jquery.ui.autocomplete 扩展:无限下拉

程序员文章站 2022-07-13 22:52:54
...
扩展自 jQuery.ui.autocomplete, 实现无限下拉功能。

使用场景:下拉列表数量巨大,并且可以分多次加载完成。

使用限制:source 需是 Function, 其他情况请使用jQuery.ui.autocomplete。

实现原理:在autocomplete中添加scroll事件,判断列表中最后一个项目是否被显示。
         当最后一个项目被显示时,调用 search(最终调用 source) 加载后续数据。
Depends:
       jquery.ui.autocomplete.js



/*!
 *
 * 扩展自 jQuery.ui.autocomplete, 实现无限下拉功能。
 * 
 * 使用场景:下拉列表数量巨大,并且可以分多次加载完成。 
 * 
 * 使用限制:source 需是 Function, 其他情况请使用jQuery.ui.autocomplete。
 * 
 * 实现原理:在autocomplete中添加scroll事件,判断列表中最后一个项目是否被显示。
 *        当最后一个项目被显示时,调用 search(最终调用 source) 加载后续数据。
 *
 * 
 * Depends:
 *	jquery.ui.autocomplete.js
 */
(function( $, undefined ) {

//输入的值是否发生了变化。
//_searchTimeout中设置为true,//this._on( "scroll") 中设置为 false。
//在__response和_suggest 中被使用。
var termChanged = true;

//用于防止多次调用 search 方法。
var lastEleAppeared  = false;

$.widget( "ui.autocompleteEx", jQuery.ui.autocomplete, {
	version: "1.10.3",

	_create: function() {
		this._super( );
		this._on( this.menu.element, {
			scroll : function(){
				var menuElement = this.menu.element;
				var lastEle = menuElement.children(":last");				

				var eleTop = lastEle.offset().top;
				var maxTop = menuElement.offset().top + menuElement.height();
				var minTop = maxTop - lastEle.height();

				if( eleTop > minTop && eleTop < maxTop ){
					if( lastEleAppeared !== true){//如最后一个元素被显示,则需加载后续数据。
						lastEleAppeared = true;
						termChanged = false;
						var tmp = this.term;
						this.search( this.term );
						this.term = tmp;
					}
				}else{
					lastEleAppeared = false;
				}
			}
		});
	},

	_searchTimeout: function( event ) {
		clearTimeout( this.searching );
		this.searching = this._delay(function() {
			// only search if the value has changed
			if ( this.term !== this._value() ) {
				this.selectedItem = null;
				termChanged = true;//*****
				this.search( null, event );
			}
		}, this.options.delay );
	},

	_response: function() {
		var that = this;
		return function( content ) {
			that.__response( content );
			that.pending--;
			if ( !that.pending ) {
				that.element.removeClass( "ui-autocomplete-loading" );
			}
		};
	},

	__response: function( content ) {
		if ( content ) {
			content = this._normalize( content );
		}
		this._trigger( "response", null, { content: content } );
		if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
			this._suggest( content );
			this._trigger( "open" );
		} else {
			// use ._close() instead of .close() so we don't cancel future searches
			if( termChanged ){//*****
				this._close();
			}//*****
		}
	},

	_suggest: function( items ) {
		//*****
		var ul = this.menu.element;
		if( termChanged ){
			ul.empty();
		}
		//*****
		this._renderMenu( ul, items );
		this.isNewMenu = true;
		this.menu.refresh();

		// size and position menu
		ul.show();
		this._resizeMenu();
		ul.position( $.extend({
			of: this.element
		}, this.options.position ));

		if ( this.options.autoFocus ) {
			this.menu.next();
		}
	},

	_move: function( direction, event ) {
		if ( !this.menu.element.is( ":visible" ) ) {
			this.search( null, event );
			return;
		}
		if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
				this.menu.isLastItem() && /^next/.test( direction ) ) {
			//this._value( this.term );
			//this.menu.blur();
			return;
		}
		this.menu[ direction ]( event );
	}
});

$.extend( $.ui.autocompleteEx, {
	escapeRegex: function( value ) {
		return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
	},
	filter: function(array, term) {
		var matcher = new RegExp( $.ui.autocompleteEx.escapeRegex(term), "i" );
		return $.grep( array, function(value) {
			return matcher.test( value.label || value.value || value );
		});
	}
});


}( jQuery ));