Вот шаблон, с которым я экспериментирую при создании более сложных плагинов виджетов:
(function($){
// configuration, private helper functions and variables
var _defaultConfig = {
/* ... config ... */
},
_version = 1;
// the main controller constructor
$.myplugin = function ( elm, config ) {
// if this contructor wasn't newed, then new it...
if ( this === window ) { return new $.myplugin( elm, config || {} ); }
// store the basics
this.item = $( elm );
this.config = new $.myplugin.config( config );
// don't rerun the plugin if it is already present
if ( this.item.data( 'myplugin' ) ) { return; }
// register this controlset with the element
this.item.data( 'myplugin', this );
// ... more init ...
};
$.myplugin.version = _version;
$.myplugin.config = function ( c ) { $.extend( this, $.myplugin.config, c ); };
$.myplugin.config.prototype = _defaultConfig;
$.myplugin.prototype = {
/* ... "public" methods ... */
};
// expose as a selector plugin
$.fn.myplugin = function ( config ) {
return this.each(function(){
new $.myplugin( this, config );
});
};
})(jQuery);
Я поставил конфигурацию и версию по умолчанию вверху просто потому, что это наиболее вероятно
вещь, которую каждый, кто читает код, ищет. Большую часть времени вы просто хотите изучить
блок настроек.
Это выставит «myplugin» в двух местах как конструктор для «контроллера» виджета
на $
и в качестве метода сбора на $.fn
. Как видите, метод $.fn
на самом деле ничего не делает, кроме создания новых контроллеров.
Конфиг - это прототипно унаследованный объект, в котором по умолчанию используется прототип. Это дает расширенную гибкость с начальными значениями, как вы можете
присвойте «следующие» значения по умолчанию $.myplugin.config
или измените значение по умолчанию для каждого работающего плагина с помощью $.myplugin.config.prototype
. Это требует от вас
всегда назначайте их с помощью $ .extend, иначе вы сломаете систему. Больше кода может противостоять этому, но я предпочитаю знать, что я делаю. : -)
Экземпляр контроллера привязывается к элементу с помощью метода data()
jQuery и фактически использует его для проверки того, что он не запускается дважды на одном и том же элементе (хотя вы можете разрешить его реконфигурирование).
Это дает вам следующий интерфейс к контроллеру:
// init:
$( 'div#myid' ).myplugin();
// call extraMethod on the controller:
$( 'div#myid' ).data('myplugin').extraMethod();
Самым большим недостатком этого подхода является то, что немного сложно поддерживать контекст "this" при каждом назначении события. Пока контекст для событий не появится в jQuery, это должно быть сделано с большим количеством замыканий.
Вот примерный пример того, как (неполный и бесполезный) плагин может выглядеть:
(function($){
// configuration, private helper functions and variables
var _defaultConfig = {
openOnHover: true,
closeButton: '<a href="#">Close</a>',
popup: '<div class="wrapper"></div>'
},
_version = 1;
// the main controller constructor
$.myplugin = function ( elm, config ) {
// if this contructor wasn't newed, then new it...
if ( this === window ) { return new $.myplugin( elm, config || {} ); }
this.item = $( elm );
this.config = new $.myplugin.config( config );
if ( this.item.data( 'myplugin' ) ) { return; }
this.item.data( 'myplugin', this );
// register some events
var ev = 'click' + ( this.config.openOnHover ) ? ' hover' : '';
this.item.bind(ev, function (e) {
$( this ).data( 'myplugin' ).openPopup();
});
};
$.myplugin.version = _version;
$.myplugin.config = function ( c ) { $.extend( this, $.myplugin.config, c ); };
$.myplugin.config.prototype = _defaultConfig;
$.myplugin.prototype = {
openPopup: function () {
var C = this.config;
this.pop = $( C.popup ).insertAfter( this.item );
this.pop.text( 'This says nothing' );
var self = this;
$( C.closeButton )
.appendTo( pop )
.bind('click', function () {
self.closePopup(); // closure keeps context
return false;
});
return this; // chaining
},
closePopup: function () {
this.pop.remove();
this.pop = null;
return this; // chaining
}
};
// expose as a selector plugin
$.fn.myplugin = function ( config ) {
return this.each(function(){
new $.myplugin( this, config );
});
};
})(jQuery);