jQuery UI Widget(1.8.1)工作原理--转载
先看下代碼的相關(guān)注釋:
/*!* jQuery UI Widget 1.8.1** Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)* Dual licensed under the MIT (MIT-LICENSE.txt)* and GPL (GPL-LICENSE.txt) licenses.** http://docs.jquery.com/UI/Widget*/ (function( $ ) {var _remove = $.fn.remove;$.fn.remove = function( selector, keepData ) {return this.each(function() {if ( !keepData ) {if ( !selector || $.filter( selector, [ this ] ).length ) {$( "*", this ).add( this ).each(function() {$( this ).triggerHandler( "remove" );});}}//dom元素在被刪除前,觸發(fā)一下remove事件,jquery框架本身沒有對元素刪除綁定事件return _remove.call( $(this), selector, keepData );}); };$.widget = function( name, base, prototype ) {var namespace = name.split( "." )[ 0 ],fullName;name = name.split( "." )[ 1 ];fullName = namespace + "-" + name;//比如ui.tab,上面的name='tab';fullName='ui-tab';if ( !prototype ) {prototype = base;base = $.Widget;}//如果沒有prototype,那么prototype就是base參數(shù),實際base默認(rèn)為$.Widget// create selector for plugin$.expr[ ":" ][ fullName ] = function( elem ) {return !!$.data( elem, name );};$[ namespace ] = $[ namespace ] || {};//是否有命名空間$[ namespace ][ name ] = function( options, element ) {//根據(jù)上面的例子,即初始化了$.ui.tab=func// allow instantiation without initializing for simple inheritanceif ( arguments.length ) {this._createWidget( options, element );}};var basePrototype = new base();//初始化,一般都是調(diào)用了new $.Widget()// 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( {}, basePrototype.options );//初始化options值,注意不需要深度拷貝$[ namespace ][ name ].prototype = $.extend( true, basePrototype, {namespace: namespace,widgetName: name,widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,widgetBaseClass: fullName}, prototype );//為新的ui模塊創(chuàng)建原型,使用深度拷貝,在basePrototype上擴展一些模塊基本信息,在擴展prototype,比如ui.tabs.js中就是tab的擁有各種方法的大對象 $.widget.bridge( name, $[ namespace ][ name ] );//將此方法掛在jQuery對象上 };$.widget.bridge = function( name, object ) {$.fn[ name ] = function( options ) {var isMethodCall = typeof options === "string",args = Array.prototype.slice.call( arguments, 1 ),returnValue = this;//如果第一個參數(shù)是string類型,就認(rèn)為是調(diào)用模塊方法//剩下的參數(shù)作為方法的參數(shù),后面會用到// allow multiple hashes to be passed on initoptions = !isMethodCall && args.length ?$.extend.apply( null, [ true, options ].concat(args) ) :options;//可以簡單認(rèn)為是$.extend(true,options,args[0],...),args可以是一個參數(shù)或是數(shù)組// prevent calls to internal methodsif ( isMethodCall && options.substring( 0, 1 ) === "_" ) {return returnValue;}//開頭帶下劃線的方法都是私有方法,不讓調(diào)用if ( isMethodCall ) {//如果是調(diào)用函數(shù)this.each(function() {var instance = $.data( this, name ),//得到實例,實例作為一個數(shù)據(jù)和元素關(guān)聯(lián)上methodValue = instance && $.isFunction( instance[options] ) ?instance[ options ].apply( instance, args ) ://如果實例和方法均存在,調(diào)用方法,把args作為參數(shù)傳進去instance;//否則返回undefinedif ( methodValue !== instance && methodValue !== undefined ) {//如果methodValue不是jquery對象也不是undefinedreturnValue = methodValue;return false;//跳出each,一般獲取options的值會走這個分支 }});} else {//不是函數(shù)調(diào)用的話this.each(function() {var instance = $.data( this, name );if ( instance ) {//實例存在if ( options ) {//有參數(shù)instance.option( options );//調(diào)用option函數(shù),一般是設(shè)置狀態(tài)之類的操作 }instance._init();//再次調(diào)用此函數(shù),根據(jù)options調(diào)整} else {$.data( this, name, new object( options, this ) );//沒有實例的話,給元素綁定一個實例。注意這里的this是dom,object是模塊類 }});}return returnValue;//返回,有可能是jquery對象,有可能是其他值 }; };$.Widget = function( options, element ) {//所有模塊的基類// allow instantiation without initializing for simple inheritanceif ( arguments.length ) {//如果有參數(shù),調(diào)用初始化函數(shù)this._createWidget( options, element );} };$.Widget.prototype = {widgetName: "widget",widgetEventPrefix: "",options: {disabled: false},//上面的屬性會在創(chuàng)建模塊時被覆蓋_createWidget: function( options, element ) {// $.widget.bridge stores the plugin instance, but we do it anyway// so that it's stored even before the _create function runsthis.element = $( element ).data( this.widgetName, this );//緩存實例,保存jquery對象this.options = $.extend( true, {},this.options,$.metadata && $.metadata.get( element )[ this.widgetName ],options );//參數(shù)處理var self = this;this.element.bind( "remove." + this.widgetName, function() {self.destroy();});//注冊銷毀事件this._create();//創(chuàng)建this._init();//初始化 },_create: function() {},_init: function() {},destroy: function() {//銷毀模塊:去除綁定事件、去除數(shù)據(jù)、去除樣式、屬性this.element.unbind( "." + this.widgetName ).removeData( this.widgetName );this.widget().unbind( "." + this.widgetName ).removeAttr( "aria-disabled" ).removeClass(this.widgetBaseClass + "-disabled " +"ui-state-disabled" );},widget: function() {//返回jquery對象return this.element;},option: function( key, value ) {//設(shè)置選項函數(shù)var options = key,self = this;if ( arguments.length === 0 ) {// don't return a reference to the internal hashreturn $.extend( {}, self.options );//返回一個新的對象,不是內(nèi)部數(shù)據(jù)的引用 }if (typeof key === "string" ) {if ( value === undefined ) {return this.options[ key ];//取值 }options = {};options[ key ] = value;//設(shè)置值 }$.each( options, function( key, value ) {self._setOption( key, value );//調(diào)用內(nèi)部的_setOption });return self;},_setOption: function( key, value ) {this.options[ key ] = value;if ( key === "disabled" ) {//增加或是去除classNamethis.widget()[ value ? "addClass" : "removeClass"](this.widgetBaseClass + "-disabled" + " " +"ui-state-disabled" ).attr( "aria-disabled", value );}return this;},enable: function() {return this._setOption( "disabled", false );},disable: function() {return this._setOption( "disabled", true );},_trigger: function( type, event, data ) {var callback = this.options[ type ];event = $.Event( event );event.type = ( type === this.widgetEventPrefix ?type :this.widgetEventPrefix + type ).toLowerCase();data = data || {};// copy original event properties over to the new event// this would happen if we could call $.event.fix instead of $.Event// but we don't have a way to force an event to be fixed multiple timesif ( event.originalEvent ) {//把原始的event屬性重新賦到event變量上for ( var i = $.event.props.length, prop; i; ) {prop = $.event.props[ --i ];event[ prop ] = event.originalEvent[ prop ];}}this.element.trigger( event, data );return !( $.isFunction(callback) &&callback.call( this.element[0], event, data ) === false ||event.isDefaultPrevented() );} };})( jQuery );上面是jquery.ui.widget.js的源碼,jquery ui的所有模塊都是基于其中的widget方法進行擴展,使用統(tǒng)一的命名規(guī)范和編碼風(fēng)格。?
先來說一下原理:?
$.widget此函數(shù)完成了對jQuery本身的擴展,根據(jù)第一個參數(shù)來確定模塊的命名空間和函數(shù)名;第二個參數(shù)確定模塊的基類(默認(rèn)是$.Widget);第三個參數(shù)實現(xiàn)模塊本身的方法。比如標(biāo)簽切換插件jquery.ui.tabs.js中開始:?
$.widget(“ui.tabs”, {…});//這里只有兩個參數(shù),那么基類就默認(rèn)是$.Widget?
第一個參數(shù):”ui.tabs”用來表示在jQuery上選擇(或增加)一個命名空間,即如果jQuery.ui不存在,則定義jQuery.ui = {},然后在jQuery.ui上增加一個函數(shù),名稱為tabs.最后調(diào)用$.widget.bridge將tabs方法掛在jQuery對象上。這樣,所有的jquery對象將擁有tabs方法。?
注意:jquery ui有嚴(yán)格的命名規(guī)范,每個控件對外只暴露一個借口。控件所有方法或?qū)傩酝ㄟ^向此借口傳遞不同參數(shù)來調(diào)用和獲取。?
jquery ui的大部分控件是基于$.Widget基類實現(xiàn)的。所以一般我們做控件是都要重寫$.Widget類中的一些方法。一般來說,一個ui控件需要實現(xiàn)下列的方法或?qū)傩?#xff1a;?
屬性:?
options 用來緩存控件各項參數(shù)?
私有方法,使用“$(xx).tabs(私有方法)”這種方式來調(diào)用私有方法時會立刻返回,調(diào)用不能成功:?
_create 控件初始化調(diào)用,多次調(diào)用$(xx).tabs()這樣不帶參數(shù)的方法只會執(zhí)行一次?
_init 一般不用實現(xiàn),默認(rèn)為空函數(shù),每次“$(xx).tabs()”這樣調(diào)用時會調(diào)用此方法?
_setOption “$(xx).tabs(‘option’,xxx)”這種調(diào)用方式會調(diào)用此方法?
公開方法:?
destroy 銷毀模塊?
option 設(shè)置或獲取參數(shù)?
enable 啟用模塊功能?
disable 禁用功能?
幾乎所有的jquery ui控件都會重寫這些接口,同時增加控件相關(guān)的私有或公有方法。?
記住,jquery ui的實例是和元素關(guān)聯(lián)起來的,作為數(shù)據(jù)保存起來了。暴露給用戶使用的只是jquery對象上增加的方法。一般我們不需要獲取ui的實例。
原文地址:http://xj19891016.iteye.com/blog/789201
轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/4024433.html
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的jQuery UI Widget(1.8.1)工作原理--转载的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cas 官方文档
- 下一篇: 改变eclipse工程中代码的层次结构