jQuery UI Verwenden der Widget-Factory
Wir werden einen Fortschrittsbalken erstellen. Wie im folgenden Beispiel gezeigt, kann dies durch Aufrufen vonjQuery.widget(), um dies zu erreichen, was zwei Parameter entgegennimmt: einer ist der Name des zu erstellenden Plugins, und der andere ist ein Objektliteral, das die Funktionen enthält, die das Plugin unterstützen. Wenn das Plugin aufgerufen wird, erstellt es eine neue Plugin-Instanz, und alle Funktionen werden im Kontext dieser Instanz ausgeführt. Dies unterscheidet sich in zwei wichtigen Punkten von standardmäßigen jQuery-Plugins. Erstens ist der Kontext ein Objekt, kein DOM-Element. Zweitens ist der Kontext immer ein einzelnes Objekt, keine Sammlung.
$.widget( "custom.progressbar", {
_create: function() {
var progress = this.options.value + "%";
this.element
.addClass( "progressbar" )
.text( progress );
}
});
Der Plugin-Name muss einen Namensraum enthalten. In diesem Beispiel verwenden wir dencustomNamensraum. Sie können einen Namensraum nur eine Ebene tief erstellen, alsocustom.progressbarist ein gültiger Plugin-Name, währendvery.custom.progressbarist kein gültiger Plugin-Name.
Wir können sehen, dass die Widget Factory uns zwei Eigenschaften bereitstellt.this.elementist ein jQuery-Objekt, das ein Element enthält. Wenn unser Plugin auf einem jQuery-Objekt aufgerufen wird, das mehrere Elemente enthält, wird für jedes Element eine separate Plugin-Instanz erstellt, und jede Instanz hat ihr eigenesthis.element. Die zweite Eigenschaft,this.options, ist ein Hash aus Schlüssel/Wert-Paaren, der alle Plugin-Optionen enthält. Diese Optionen können wie folgt an das Plugin übergeben werden:
$( "<div></div>" )
.appendTo( "body" )
.progressbar({ value: 20 });
Wenn wir aufrufenjQuery.widget(), erweitert es jQuery durch Hinzufügen von Funktionen zujQuery.fn(das System, das zum Erstellen von Standard-Plugins verwendet wird). Die Namen der hinzugefügten Funktionen basieren auf dem Namen, den Sie anjQuery.widget()ohne den Namensraum - "progressbar". Die an das Plugin übergebenen Optionen sind die Werte, die auf der Plugin-Instanz festgelegt sind. Wie im folgenden Beispiel gezeigt, können wir Standardwerte für jede Option angeben. Beim Entwerfen Ihrer API sollten Sie sich über die häufigsten Anwendungsfälle Ihres Plugins im Klaren sein, damit Sie geeignete Standardwerte festlegen und sicherstellen können, dass alle Optionen wirklich optional sind.
$.widget( "custom.progressbar", {
// Default options.
options: {
value: 0
},
_create: function() {
var progress = this.options.value + "%";
this.element
.addClass( "progressbar" )
.text( progress );
}
});
Plugin-Methoden aufrufen
Nachdem wir nun unsere Fortschrittsanzeige initialisieren können, werden wir Aktionen ausführen, indem wir Methoden auf der Plugin-Instanz aufrufen. Um eine Plugin-Methode zu definieren, referenzieren wir einfach eine Funktion in dem Objekt, das wir übergeben anjQuery.widget()das Objekt. Wir können auch "private" Methoden definieren, indem wir dem Funktionsnamen einen Unterstrich voranstellen.
$.widget( "custom.progressbar", {
options: {
value: 0
},
_create: function() {
var progress = this.options.value + "%";
this.element
.addClass( "progressbar" )
.text( progress );
},
// Create a public method.
value: function( value ) {
// No value passed, act as a getter.
if ( value === undefined ) {
return this.options.value;
}
// Value passed, act as a setter.
this.options.value = this._constrain( value );
var progress = this.options.value + "%";
this.element.text( progress );
},
// Create a private method.
_constrain: function( value ) {
if ( value > 100 ) {
value = 100;
}
if ( value < 0 ) {
value = 0;
}
return value;
}
});
Um eine Methode auf der Plugin-Instanz aufzurufen, können Sie den Methodennamen an das jQuery-Plugin übergeben. Wenn die aufgerufene Methode Parameter akzeptiert, übergeben Sie diese Parameter einfach nach dem Methodennamen.
Hinweis:Methoden werden ausgeführt, indem der Methodenname an dieselbe jQuery-Funktion übergeben wird, die zum Initialisieren des Plugins verwendet wird. Dies geschieht, um eine Verschmutzung des jQuery-Namensraums zu verhindern und gleichzeitig die Methodenverkettung beizubehalten. Später in diesem Kapitel werden wir andere Verwendungen sehen, die natürlicher aussehen.
var bar = $( "<div></div>" )
.appendTo( "body" )
.progressbar({ value: 20 });
// Get the current value.
alert( bar.progressbar( "value" ) );
// Update the value.
bar.progressbar( "value", 50 );
// Get the current value again.
alert( bar.progressbar( "value" ) );
Optionen verwenden
option()Die Methode wird dem Plugin automatisch bereitgestellt.option()Die Methode ermöglicht es Ihnen, Optionen nach der Initialisierung abzurufen und festzulegen. Diese Methode funktioniert wie die jQuery-.css()und.attr()Methode: Sie können nur einen Namen übergeben, um sie als Getter zu verwenden, einen Namen und einen Wert übergeben, um sie als Setter zu verwenden, oder einen Hash aus Schlüssel/Wert-Paaren übergeben, um mehrere Werte festzulegen. Wenn sie als Getter verwendet wird, gibt das Plugin den aktuellen Wert der Option zurück, die dem übergebenen Namen entspricht. Wenn sie als Setter verwendet wird, wird die_setOptionMethode des Plugins für jede festgelegte Option aufgerufen. Wir können eine_setOptionMethode in unserem Plugin angeben, um auf Optionsänderungen zu reagieren. Für Aktionen, die unabhängig ausgeführt werden sollen, wenn sich eine Option ändert, können wir überschreiben_setOptions。
$.widget( "custom.progressbar", {
options: {
value: 0
},
_create: function() {
this.options.value = this._constrain(this.options.value);
this.element.addClass( "progressbar" );
this.refresh();
},
_setOption: function( key, value ) {
if ( key === "value" ) {
value = this._constrain( value );
}
this._super( key, value );
},
_setOptions: function( options ) {
this._super( options );
this.refresh();
},
refresh: function() {
var progress = this.options.value + "%";
this.element.text( progress );
},
_constrain: function( value ) {
if ( value > 100 ) {
value = 100;
}
if ( value < 0 ) {
value = 0;
}
return value;
}
});
Callbacks hinzufügen
Der einfachste Weg, ein Plugin zu erweitern, besteht darin, Callbacks hinzuzufügen, damit Benutzer reagieren können, wenn sich der Zustand des Plugins ändert. Im folgenden Beispiel sehen wir, wie man einen Callback zum Fortschrittsbalken hinzufügt, wenn der Fortschritt 100% erreicht._trigger()Die Methode nimmt drei Parameter entgegen: den Callback-Namen, ein jQuery-Event-Objekt, das den Callback auslöst, und einen Daten-Hash, der zum Event gehört. Der Callback-Name ist der einzige erforderliche Parameter, aber die anderen Parameter sind sehr nützlich für Benutzer, die benutzerdefinierte Funktionalität im Plugin implementieren möchten. Wenn wir beispielsweise ein draggable-Plugin erstellen, können wir beim Auslösen des Drag-Callbacks das mousemove-Event übergeben, wodurch Benutzer auf das Ziehen basierend auf den vom Event-Objekt bereitgestellten x/y-Koordinaten reagieren können. Beachten Sie, dass das übergebene Event_trigger()ein jQuery-Event sein muss, kein natives Browser-Event.
$.widget( "custom.progressbar", {
options: {
value: 0
},
_create: function() {
this.options.value = this._constrain(this.options.value);
this.element.addClass( "progressbar" );
this.refresh();
},
_setOption: function( key, value ) {
if ( key === "value" ) {
value = this._constrain( value );
}
this._super( key, value );
},
_setOptions: function( options ) {
this._super( options );
this.refresh();
},
refresh: function() {
var progress = this.options.value + "%";
this.element.text( progress );
if ( this.options.value == 100 ) {
this._trigger( "complete", null, { value: 100 } );
}
},
_constrain: function( value ) {
if ( value > 100 ) {
value = 100;
}
if ( value < 0 ) {
value = 0;
}
return value;
}
});
Callback-Funktionen sind im Wesentlichen nur zusätzliche Optionen, sodass Sie sie wie jede andere Option abrufen und festlegen können. Wann immer ein Callback ausgeführt wird, wird ein entsprechendes Event ausgelöst. Der Event-Typ wird durch Verketten des Plugin-Namens und des Callback-Namens bestimmt. Sowohl Callbacks als auch Events akzeptieren dieselben zwei Parameter: ein Event-Objekt und einen Daten-Hash, der zum Event gehört, wie im folgenden Beispiel gezeigt.
Ihr Plugin muss möglicherweise Funktionalität enthalten, die Benutzer daran hindert, es zu verwenden. Um dies zu erreichen, ist der beste Weg, einen abbrechbaren Callback zu erstellen. Benutzer können den Callback oder das zugehörige Event abbrechen, genau wie sie jedes native Event abbrechen würden, indem sie aufrufenevent.preventDefault()oder zurückgebenfalseum dies zu erreichen. Wenn der Benutzer den Callback abbricht, wird die_trigger()Methode zurückgebenfalse, sodass Sie die entsprechende Funktionalität im Plugin implementieren können.
var bar = $( "<div></div>" )
.appendTo( "body" )
.progressbar({
complete: function( event, data ) {
alert( "Callbacks are great!" );
}
})
.bind( "progressbarcomplete", function( event, data ) {
alert( "Events bubble and support many handlers for extreme flexibility." );
alert( "The progress bar value is " + data.value );
});
bar.progressbar( "option", "value", 100 );
Unter der Haube
Nachdem wir nun gesehen haben, wie man die Widget Factory verwendet, um ein Plugin zu erstellen, schauen wir uns an, wie sie tatsächlich funktioniert. Wenn Sie aufrufenjQuery.widget(), es wird eine Konstruktorfunktion für das Plugin erstellt und das von Ihnen übergebene Objekt als Prototyp für Plugin-Instanzen festgelegt. Alle dem Plugin automatisch hinzugefügte Funktionalität stammt von einem Basis-Widget-Prototyp, der definiert ist alsjQuery.Widget.prototype. Wenn Sie eine Plugin-Instanz erstellen, verwenden SiejQuery.data, um sie auf dem ursprünglichen DOM-Element zu speichern, mit dem Plugin-Namen als Schlüssel.
Da die Plugin-Instanz direkt mit dem DOM-Element verknüpft ist, können Sie direkt auf die Plugin-Instanz zugreifen, ohne Plugin-Methoden zu verwenden. Dadurch können Sie Methoden direkt auf der Plugin-Instanz aufrufen, ohne den Methodennamen als String zu übergeben, und außerdem direkt auf die Eigenschaften des Plugins zugreifen.
var bar = $( "<div></div>" )
.appendTo( "body" )
.progressbar()
.data( "progressbar" );
// Call a method directly on the plugin instance.
bar.option( "value", 50 );
// Access properties on the plugin instance.
alert( bar.options.value );
Sie können auch eine Instanz erstellen, ohne Plugin-Methoden zu verwenden, indem Sie den Konstruktor direkt mit Optionen und dem Element aufrufen:
var bar = $.custom.progressbar( {}, $( "<div></div>" ).appendTo( "body") );
// Same result as before.
alert( bar.options.value );
Erweitern des Plugin-Prototyps
Der größte Vorteil eines Plugins mit Konstruktor und Prototyp ist, dass es einfach zu erweitern ist. Durch Hinzufügen oder Ändern von Methoden am Prototyp des Plugins können wir das Verhalten aller Instanzen des Plugins ändern. Wenn wir beispielsweise eine Methode zum Fortschrittsbalken hinzufügen möchten, um den Fortschritt auf 0% zurückzusetzen, können wir diese Methode zum Prototyp hinzufügen, und sie ist bei allen Plugin-Instanzen aufrufbar.
$.custom.progressbar.prototype.reset = function() {
this._setOption( "value", 0 );
};
Weitere Details zum Erweitern von Widgets und dazu, wie Sie ein brandneues Widget auf Basis eines vorhandenen Widgets erstellen, finden Sie unterErweitern von Widgets mit der Widget Factory。
Aufräumen
In manchen Fällen ist es nützlich, Benutzern zu ermöglichen, ein Plugin anzuwenden und es dann wieder zu entfernen. Dies können Sie über die_destroy()-Methode. In der_destroy()-Methode sollten Sie alles rückgängig machen, was das Plugin während der Initialisierung und späteren Verwendung getan hat._destroy()wird über die.destroy()Methode. Die.destroy()Methode wird automatisch aufgerufen, wenn das an die Plugin-Instanz gebundene Element aus dem DOM entfernt wird, daher kann dies für die Garbage Collection verwendet werden. Die grundlegende.destroy()Methode behandelt auch einige gängige Aufräumoperationen, wie das Entfernen der Instanzreferenz aus dem DOM-Element des Widgets, das Aufheben der Bindung aller Ereignisse im Widget-Namespace von dem Element und das Aufheben der Bindung aller Ereignisse, die hinzugefügt wurden mit_bind()hinzugefügte Ereignisse.
$.widget( "custom.progressbar", {
options: {
value: 0
},
_create: function() {
this.options.value = this._constrain(this.options.value);
this.element.addClass( "progressbar" );
this.refresh();
},
_setOption: function( key, value ) {
if ( key === "value" ) {
value = this._constrain( value );
}
this._super( key, value );
},
_setOptions: function( options ) {
this._super( options );
this.refresh();
},
refresh: function() {
var progress = this.options.value + "%";
this.element.text( progress );
if ( this.options.value == 100 ) {
this._trigger( "complete", null, { value: 100 } );
}
},
_constrain: function( value ) {
if ( value > 100 ) {
value = 100;
}
if ( value < 0 ) {
value = 0;
}
return value;
},
_destroy: function() {
this.element
.removeClass( "progressbar" )
.text( "" );
}
});
Schlussbemerkungen
Die Widget Factory ist nur eine Möglichkeit, zustandsbehaftete Plugins zu erstellen. Es gibt mehrere andere unterschiedliche Modelle, die Sie verwenden können, jedes mit seinen eigenen Vor- und Nachteilen. Die Widget Factory löst viele häufige Probleme und verbessert die Effizienz erheblich, während sie gleichzeitig die Code-Wiederverwendung stark verbessert, wodurch sie für jQuery UI und andere zustandsbehaftete Plugins geeignet ist.
Bitte beachten Sie, dass wir in diesem Kapitel dencustomNamespace. DeruiNamespace ist für offizielle jQuery-UI-Plugins reserviert. Wenn Sie Ihre eigenen Plugins erstellen, sollten Sie Ihren eigenen Namespace erstellen. Dadurch wird klarer, woher das Plugin stammt und zu welchem Geltungsbereich es gehört.