jQuery UI Расширение виджетов с помощью фабрики виджетов

Фабрика виджетов jQuery UI упрощает создание виджетов, расширяющих функциональность существующих виджетов. Так вы можете создавать мощные виджеты на основе существующих или вносить тонкие изменения в функциональность существующих виджетов.

Примечание:Прежде чем изучать эту главу, вам нужно понять, что такое фабрика виджетов и как она работает. Если вы не знакомы с этой темой, сначала прочитайтеКак использовать фабрику виджетовглаву.

Создание расширений виджетов

Создание виджетов с помощью фабрики виджетов выполняется путем передачи$.widget()имени виджета и объекта-прототипа. В примере создается виджет "superDialog" в пространстве имен "custom".

$.widget( "custom.superDialog", {} );

Для поддержки расширения,$.widget()опционально принимает конструктор виджета, который будет использоваться в качестве родительского виджета. При указании родительского виджета передайте его вторым параметром, после имени виджета и перед объектом-прототипом виджета.

Как и в примере выше, следующий код также создаёт виджет "superDialog" в пространстве имён "custom". Но на этот раз он передаёт конструкторвиджета dialog из jQuery UI($.ui.dialog), указывая на то, что виджет superDialog должен использовать виджет dialog из jQuery UI в качестве родительского виджета.

$.widget( "custom.superDialog", $.ui.dialog, {} );

Здесь виджеты superDialog и dialog по сути эквивалентны, только с разными именами и пространствами имён. Чтобы сделать наш новый виджет более отличимым, мы можем добавить несколько методов в его объект-прототип.

Объект-прототип виджета — это последний параметр, передаваемый в$.widget(). Пока что в нашем примере использовался пустой объект. Теперь давайте добавим метод в этот объект:

$.widget( "custom.superDialog", $.ui.dialog, {
    red: function() {
        this.element.css( "color", "red" );
    }
});
 
// Create a new <div>, convert it into a superDialog, and call the red() method.
$( "<div>I am red</div>" )
    .superDialog()
    .superDialog( "red" );

ТеперьsuperDialogимеетred()метод, который меняет цвет его текста на красный. Обратите внимание, как Widget Factory автоматически устанавливаетthisв объект экземпляра виджета. Чтобы просмотреть список всех доступных методов и свойств экземпляра, посетитедокументацию API Widget Factory。

Расширение существующих методов

Иногда требуется настроить или добавить поведение к существующим методам виджета. Вы можете указать имя метода как имя метода для переопределения в объекте-прототипе. В следующем примере переопределяетсяopen()методdialog. Поскольку диалог по умолчанию открыт, когда этот код выполняется,"open"будет выведено в журнал.

$.widget( "custom.superDialog", $.ui.dialog, {
    open: function() {
        console.log( "open" );
    }
});
 
// Create a new <div>, and convert it into a superDialog.
$( "<div>" ).superDialog();

При выполнении этого кода возникает проблема. Потому что мы переопределилиopen()поведение по умолчанию, диалог больше не отображается на экране.

Когда мы используем метод на объекте-прототипе, мы фактически переопределяем исходный метод, используя новый метод в цепочке прототипов.

Чтобы сделать методы родительского виджета доступными, Widget Factory предоставляет два метода -_super()и_superApply()。

Использование_super()и_superApply()для доступа к родительскому виджету

_super()и_superApply()и вызвать тот же метод у родительского виджета. См. пример ниже. Как и в предыдущем примере, этот пример также переопределяетopen()метод для логирования"open". Однако на этот раз выполнение_super()вызывает у диалогаopen(), и открывает диалог.

$.widget( "custom.superDialog", $.ui.dialog, {
    open: function() {
        console.log( "open" );
 
        // Invoke the parent widget's open().
        return this._super();
    }
});
 
$( "<div>" ).superDialog();

_super()и_superApply()На самом деле это эквивалентно исходномуFunction.prototype.call()иFunction.prototype.apply()метод. Следовательно,_super()принимает список аргументов,_superApply()принимает массив в качестве аргумента. Следующий пример демонстрирует разницу между ними.

$.widget( "custom.superDialog", $.ui.dialog, {
    _setOption: function( key, value ) {
 
        // Both invoke dialog's setOption() method. _super() requires the arguments
        // be passed as an argument list, _superApply() as a single array.
        this._super( key, value );
        this._superApply( arguments );
    }
});

Переопределение виджетов

jQuery UI 1.9 добавил возможность переопределять виджеты. Поэтому вместо создания нового виджета нам нужно только передать$.widget()имя существующего виджета и конструктор. Следующий пример добавляетopen()такое же логирование в ..., но не путем создания нового виджета.

$.widget( "ui.dialog", $.ui.dialog, {
    open: function() {
        console.log( "open" );
        return this._super();
    }
});
 
$( "<div>" ).dialog();

С помощью этого метода мы можем расширить существующий метод виджета, но мы всё ещё можем использовать_super()для доступа к исходному методу - это делается не путем создания нового виджета, а путем прямого переопределения виджета.

Виджеты и полиморфизм

При взаимодействии между расширениями виджетов и их плагинами стоит отметить, что плагин родительского виджета нельзя использовать для вызова методов на элементах дочернего виджета. Следующий пример демонстрирует это.

$.widget( "custom.superDialog", $.ui.dialog, {} );
 
var dialog = $( "<div>" ).superDialog();
 
// This works.
dialog.superDialog( "close" );
 
// This doesn't.
dialog.dialog( "close" );

В примере выше плагин родительского виджета,dialog(), невозможно вызватьclose()метод для элемента superDialog. Чтобы узнать больше о вызове методов виджета, обратитесь кВызовы методов виджета。

Настройка отдельных экземпляров

До сих пор во всех примерах, которые мы видели, методы расширялись в прототипе виджета. Переопределение методов в прототипе влияет на все экземпляры виджета.

Чтобы продемонстрировать это, см. пример ниже. Оба экземпляра диалога используют один и тот жеopen()метод.

$.widget( "ui.dialog", $.ui.dialog, {
    open: function() {
        console.log( "open" );
        return this._super();
    }
});
 
// Create two dialogs, both use the same open(), therefore "open" is logged twice.
$( "<div>" ).dialog();
$( "<div>" ).dialog();

Иногда нужно изменить поведение только одного экземпляра виджета. Для этого нужно использовать обычное присваивание свойств JavaScript, получить ссылку на экземпляр и переопределить метод. Это показано в примере ниже.

var dialogInstance = $( "<div>" )
    .dialog()
    // Retrieve the dialog's instance and store it.
    .data( "ui-dialog" );
 
// Override the close() method for this dialog
dialogInstance.close = function() {
    console.log( "close" );
};
 
// Create a second dialog
$( "<div>" ).dialog();
 
// Select both dialogs and call close() on each of them.
// "close" will only be logged once.
$( ":data(ui-dialog)" ).dialog( "close" );

Техника переопределения методов в отдельном экземпляре идеально подходит для разовых настроек.

Другие расширения