为什么需要研究JqueryUI 中Widget 的代码
对一般的jquery 应用的和jqueryUI的应用其实是不需要对widget 中代码和widget 的工作原理进行研究,但是如果你是的工作时需要开发widget 控件,或者是对自身的应用的技术要求比较高的话最好是对widget 的源代码和工作原理进行分析,恰好我是因为工作是基于jqueryUI 的widget 开发。
这里进行的的代码分析是使用jqueryUI-1.10.0 jquery-1.8.3,代码分析的时候最好现在他们的开发板,里边是一个工程包,目录如下,
我们需要分析的就是ui 文件夹下的文代码, ui 文件夹下代码结构很清晰,其实就是我们引入的jqueryUI.js
的分拆版本,除了core 和widget 两个文件外其他都是一些控件的代码,这里只研究core 和widget ,
CORE 文件
jquery.ui.core 文件比较简单,就是在引用jquery.js 的前提下定义$.ui ,和常用的key对应的健值,
Widget 文件
jquery.ui.widget 所有的自定义和官方UI 都是从这个东西来的,jquery 的东西都是结构很简单,但是代码比较绕,ui的设计也是这种思路
我们一般定义widget都是 例如
$.widget('ui.mytabs',{active:0,animate:false}); 就是调用这个类
$.widget = function( name, base, prototype ) {
// full Name 是一个全名
// existingConstructor
// constructor 是构建widget 的构造器
// basePrototype 传进来的prototpye 例如{active:}
var fullName, existingConstructor, constructor, basePrototype,
// proxiedPrototype allows the provided prototype to remain unmodified
// so that it can be used as a mixin for multiple widgets (#8876)
proxiedPrototype = {},
namespace = name.split( "." )[ 0 ];
name = name.split( "." )[ 1 ];
fullName = namespace + "-" + name;
if ( !prototype ) {
prototype = base;
base = $.Widget;
}
// create selector for plugin
$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
return !!$.data( elem, fullName );
};
$[ namespace ] = $[ namespace ] || {};
existingConstructor = $[ namespace ][ name ];
constructor = $[ namespace ][ name ] = function( options, element ) {
// allow instantiation without "new" keyword
if ( !this._createWidget ) {
return new constructor( options, element );
}
// allow instantiation without initializing for simple inheritance
// must use "new" keyword (the code above always passes args)
if ( arguments.length ) {
this._createWidget( options, element );
}
};
// extend with the existing constructor to carry over any static properties
$.extend( constructor, existingConstructor, {
version: prototype.version,
// copy the object used to create the prototype in case we need to
// redefine the widget later
_proto: $.extend( {}, prototype ),
// track widgets that inherit from this widget in case this widget is
// redefined after a widget inherits from it
_childConstructors: []
});
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
basePrototype.options = $.widget.extend( {}, basePrototype.options );
$.each( prototype, function( prop, value ) {
if ( !$.isFunction( value ) ) {
proxiedPrototype[ prop ] = value;
return;
}
proxiedPrototype[ prop ] = (function() {
var _super = function() {
return base.prototype[ prop ].apply( this, arguments );
},
_superApply = function( args ) {
return base.prototype[ prop ].apply( this, args );
};
return function() {
var __super = this._super,
__superApply = this._superApply,
returnValue;
this._super = _super;
this._superApply = _superApply;
returnValue = value.apply( this, arguments );
this._super = __super;
this._superApply = __superApply;
return returnValue;
};
})();
});
constructor.prototype = $.widget.extend( basePrototype, {
// TODO: remove support for widgetEventPrefix
// always use the name + a colon as the prefix, e.g., draggable:start
// don't prefix for widgets that aren't DOM-based
widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
}, proxiedPrototype, {
constructor: constructor,
namespace: namespace,
widgetName: name,
widgetFullName: fullName
});
// If this widget is being redefined then we need to find all widgets that
// are inheriting from it and redefine all of them so that they inherit from
// the new version of this widget. We're essentially trying to replace one
// level in the prototype chain.
if ( existingConstructor ) {
$.each( existingConstructor._childConstructors, function( i, child ) {
var childPrototype = child.prototype;
// redefine the child widget using the same prototype that was
// originally used, but inherit from the new version of the base
$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
});
// remove the list of existing child constructors from the old constructor
// so the old child constructors can be garbage collected
delete existingConstructor._childConstructors;
} else {
base._childConstructors.push( constructor );
}
$.widget.bridge( name, constructor );
};