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的源码,有了初步的,整体的了解,那么以后我们在使用时,遇到了问题,就无往而不利了