jqueryUI之widget

jqueryUI widget 分析

$.widget 理解是个注册ui组件的工厂方法,$.widget(name,prototype) 传入ui的name和ui的prototype,就会返回新ui的构造方法。

$.widget( "ui.buttonset",/* 原型*/ {

    version: "1.10.1",

    options: {

        items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"

    },

    _create: function() {

        this.element.addClass( "ui-buttonset" );

    },

    _init: function() {

        this.refresh();

    },

 因为ui组件有很多方法是可以公用的,像共有属性、option参数设置、create/init组件执行过程、on/off/trigger事件和其他focusable等添加class的逻辑,通过$.Widget这个ui的最基类做了封装

$.Widget = function( /* options, element */ ) {};

$.Widget._childConstructors = [];

$.Widget.prototype = {

    widgetName: "widget",

    widgetEventPrefix: "",

    defaultElement: "<div>",

    options: {

        disabled: false,

        create: null

    }

如果简化ui的$.widget的逻辑

function base(){};//$.Widget 基类

base.prototype={ _create:function(){... }, ... };
function pkg(proto){//$.widget 工厂方法

  var constructor=function(opt){ this._create(opt); };
  constructor.prototype=$.extend(true,{},new base(),proto); 
  return constructor;
}

源码分析

实际的实现中$.widget做了一些自己的特殊处理:

如命名相关

    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: []

    });









    // 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 );

    }

 

和桥接ui组件成jquery插件

$.widget.bridge( name, constructor );

 

还有很多属性复制克隆防止覆盖的处理

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;

            };

        })();

    });

 

这段代码在传入的ui原型中有方法调用this._super 和this.__superApply会调用到base上(最基类上)的方法。参考测试用例中

test( "._superApply()", function() {

    expect( 10 );

    var instance;

    $.widget( "ui.testWidget", {

        method: function( a, b ) {

            deepEqual( this, instance, "this is correct in testWidget" );

            deepEqual( a, 5, "parameter passed to testWidget" );

            deepEqual( b, 10, "second parameter passed to testWidget" );

            return a + b;

        }

    });



    $.widget( "ui.testWidget2", $.ui.testWidget, {

        method: function( a, b ) {

            deepEqual( this, instance, "this is correct in testWidget2" );

            deepEqual( a, 5, "parameter passed to testWidget2" );

            deepEqual( b, 10, "second parameter passed to testWidget2" );

            return this._superApply( arguments );

        }

    });



    $.widget( "ui.testWidget3", $.ui.testWidget2, {

        method: function( a, b ) {

            deepEqual( this, instance, "this is correct in testWidget3" );

            deepEqual( a, 5, "parameter passed to testWidget3" );

            deepEqual( b, 10, "second parameter passed to testWidget3" );

            var ret = this._superApply( arguments );

            deepEqual( ret, 15, "super returned value" );

        }

    });



    instance = $( "<div>" ).testWidget3().testWidget3( "instance" );

    instance.method( 5, 10 );

    delete $.ui.testWidget3;

    delete $.ui.testWidget2;

});

 jqueryui 的widget设计,即能很好的保证代码复用和维护风格统一,也允许各自ui灵活的实现功能。除此之外jquery ui在api的灵活性和实例化步骤等地方都做的很好,在自己实现代码的时候参考下他的实现很有启发

你可能感兴趣的:(JqueryUI)