jqueryui是一个优秀的组件库,合理利用并封装其代码,可以创造出自己的组件库,使用过程中,避免不了的需要深入其源码,并调用其内部的一些方法,来完成自己的需求。
需求场景:
jqueryui的autocomplete功能,为输入框中输入值,则自动进行suggest,但是现在有一个需求,即不让其自动提示,而是通过点击按钮来触发。
解决:
通过参数设置,是肯定不能完成这个功能了。仔细看了其source参数的自定义方式,也不能满足这个需求,进而查看其源码,发现其从输入到发送请求,到最后展现div列表项,经历了ui.autocomplete的如下方法调用
search->_search->source->response->_response->_normalize->_suggest
其中respone以后,即为数据返回后,开始创建DIV列表项了,那我们要去从中间开始,连接上这一长串的调用,就要手动调用search或者_search中的一个方法,通过对2个方法的对比,最终决定选择_search方法,其函数如下:
_search: function( value ) {
this.element.addClass( "ui-autocomplete-loading" ); this.source( { term: value }, this.response ); }
显然,只要调用这个方法,并且把输入框的值,传入函数,那么接下来的动作,就又可以交给组件进行了。
接下来就蛋疼了,关于怎么调用这个方法,颇费了一番周折。
先把调用的结果写法列出来,然后再具体分析:
if(!settings.auto){ settings.minLength=1024; $.ui.autocomplete.prototype.rqcussearch=function( value ) { this._search(value); }; $("#"+$(obj).attr("id")+"_rqautoqueryimg").bind("click",function(event){ setTimeout(function(){ inputobj.autocomplete("rqcussearch",inputobj.val()); },settings.delay); }); } inputobj.autocomplete(settings);
代码大概为,如果传来参数说不使用自动suggest,那么就将autocomplete的提示文字限制放大到1024,接下来,在ui.autocomplete对象上,添加一个自己的方法(后面再说为什么要添加方法,而不是直接调用),然后,给按钮或者图片,绑定一个click事件,点击后,再调用查询方法。这里click事件,使用了setTimeout,稍微做了延迟,也是有其用处的,后面再说。。。
(1)$.ui.autocomplete.prototype 是什么东西?
调试中,我试过各种办法去调用,不过都死在无法正确给对象指定this上,那么jqueryui中的组件autocomplete的this,到底是什么?就是$.ui.autocomplete.prototype东西,怎么得出的,还是得看源码中的相关函数,具体位置为如下代码片段:
$.widget( "ui.autocomplete", {
....
_search:function(value){xxxx},
....
});
这里是对autocomplete组件的一个声明和定义,而明显的,其是通过$.widget方法来进行的。
此方法定义如下:
$.widget = function( name, base, prototype ) { var namespace = name.split( "." )[ 0 ], fullName; name = name.split( "." )[ 1 ]; fullName = namespace + "-" + name; if ( !prototype ) { prototype = base; base = $.Widget; } // create selector for plugin $.expr[ ":" ][ fullName ] = function( elem ) { return !!$.data( elem, name ); }; $[ namespace ] = $[ namespace ] || {}; $[ namespace ][ name ] = function( options, element ) { // allow instantiation without initializing for simple inheritance if ( arguments.length ) { this._createWidget( options, element ); } }; var basePrototype = new base(); // we need to make the options hash a property directly on the new instance // otherwise we'll modify the options hash on the prototype that we're // inheriting from // $.each( basePrototype, function( key, val ) { // if ( $.isPlainObject(val) ) { // basePrototype[ key ] = $.extend( {}, val ); // } // }); basePrototype.options = $.extend( true, {}, basePrototype.options ); $[ namespace ][ name ].prototype = $.extend( true, basePrototype, { namespace: namespace, widgetName: name, widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name, widgetBaseClass: fullName }, prototype ); $.widget.bridge( name, $[ namespace ][ name ] ); };
通过阅读,可以知道,他会把传来的组件字符串名,分配到相应的属性上,并定义其方法,原型等
我们重点关注其最后一行的$.widget.bridge( name, $[ namespace ][ name ] );函数
查看其方法定义如下:
$.widget.bridge = function( name, object ) { $.fn[ name ] = function( options ) { var isMethodCall = typeof options === "string", args = Array.prototype.slice.call( arguments, 1 ), returnValue = this; // allow multiple hashes to be passed on init options = !isMethodCall && args.length ? $.extend.apply( null, [ true, options ].concat(args) ) : options; // prevent calls to internal methods if ( isMethodCall && options.charAt( 0 ) === "_" ) { return returnValue; } if ( isMethodCall ) { this.each(function() { var instance = $.data( this, name ), methodValue = instance && $.isFunction( instance[options] ) ? instance[ options ].apply( instance, args ) : instance; // TODO: add this back in 1.9 and use $.error() (see #5972) // if ( !instance ) { // throw "cannot call methods on " + name + " prior to initialization; " + // "attempted to call method '" + options + "'"; // } // if ( !$.isFunction( instance[options] ) ) { // throw "no such method '" + options + "' for " + name + " widget instance"; // } // var methodValue = instance[ options ].apply( instance, args ); if ( methodValue !== instance && methodValue !== undefined ) { returnValue = methodValue; return false; } }); } else { this.each(function() { var instance = $.data( this, name ); if ( instance ) { instance.option( options || {} )._init(); } else { $.data( this, name, new object( options, this ) ); } }); } return returnValue; }; };
这个方法,就很明显了,大概意思为当调用组件的入口方法(如:inputobj.autocomplete(settings);)时,所进行的逻辑。比如判断传来的参数是否为方法,是方法则调用,不是则设置属性。
方法调用的判断中,有这么一句话,也值得我们关注:
if ( isMethodCall && options.charAt( 0 ) === "_" ) {
return returnValue;
}
什么意思,就是说你要是调用了它以_开头的方法,就直接返回,也就是不允许你对其定义的私有方法进行调用,这也就是,我为什么要给起对象,添加一个rqcussearch方法的原因了。
看到了以上的分析,我想我们已经对jqueryui的源码,有了初步的,整体的了解,那么以后我们在使用时,遇到了问题,就无往而不利了