为什么需要研究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 ); };