1. Code
  2. JavaScript

jQuery-Anti-Patterns und Best Practices

Vor langer Zeit war JavaScript in einer weit entfernten Galaxie eine verhasste Sprache. In der Tat ist "gehasst" eine Untertreibung; JavaScript war eine verachtete Sprache. Infolgedessen haben Entwickler es im Allgemeinen als solches behandelt und ihre Zehen nur dann in das JavaScript-Wasser getaucht, wenn sie ein wenig Flair in ihre Anwendungen einbringen mussten. Trotz der Tatsache, dass die JavaScript-Sprache aufgrund der weit verbreiteten Unwissenheit eine Menge Gutes enthält, haben sich nur wenige die Zeit genommen, sie richtig zu lernen. Wie einige von Ihnen vielleicht erinnern, war die Standardnutzung von JavaScript mit einem erheblichen Kopier- und Einfügevorgang verbunden.
Scroll to top

German (Deutsch) translation by Katharina Grigorovich-Nevolina (you can also view the original English article)

Vor langer Zeit war JavaScript in einer weit entfernten Galaxie eine verhasste Sprache. In der Tat ist "gehasst" eine Untertreibung; JavaScript war eine verachtete Sprache. Infolgedessen haben Entwickler es im Allgemeinen als solches behandelt und ihre Zehen nur dann in das JavaScript-Wasser getaucht, wenn sie ein wenig Flair in ihre Anwendungen einbringen mussten. Trotz der Tatsache, dass die JavaScript-Sprache aufgrund der weit verbreiteten Unwissenheit eine Menge Gutes enthält, haben sich nur wenige die Zeit genommen, sie richtig zu lernen. Wie einige von Ihnen vielleicht erinnern, war die Standardnutzung von JavaScript mit einem erheblichen Kopier- und Einfügevorgang verbunden.

"Lernen Sie nicht, was der Code bewirkt oder ob er den Best Practices entspricht. Fügen Sie ihn einfach ein!" - Der schlechteste Rat aller Zeiten

Da der Aufstieg von jQuery das Interesse an der JavaScript-Sprache wieder geweckt hat, sind viele Informationen im Web etwas lückenhaft.

Ironischerweise stellte sich heraus, dass vieles, was die Entwicklergemeinde hasste, sehr wenig mit der JavaScript-Sprache selbst zu tun hatte. Nein, die wirkliche Bedrohung unter der Maske war das DOM oder "Document Object Model", das gerade zu dieser Zeit von Browser zu Browser schrecklich inkonsistent war. "Sicher, es kann in Firefox funktionieren, aber was ist mit IE8? Okay, es kann in IE8 funktionieren, aber was ist mit IE7?" Die Liste ging unermüdlich weiter!

Glücklicherweise würde die JavaScript-Community ab etwa fünf Jahren eine unglaubliche Veränderung zum Besseren erleben, da Bibliotheken wie jQuery der Öffentlichkeit vorgestellt wurden. Diese Bibliotheken boten nicht nur eine ausdrucksstarke Syntax, die besonders für Webdesigner attraktiv war, sondern sie schafften es auch, das Spielgefühl zu verbessern, indem sie die Problemumgehungen für die verschiedenen Browser-Macken in ihre API steckten. Lösen Sie $.ajax aus und lassen Sie jQuery den schwierigen Teil erledigen. Schneller Vorlauf bis heute, und die JavaScript-Community ist lebendiger als je zuvor - hauptsächlich aufgrund der jQuery-Revolution.

Da der Aufstieg von jQuery das Interesse an der JavaScript-Sprache wieder geweckt hat, sind viele Informationen im Web etwas lückenhaft. Dies liegt weniger an der Unwissenheit der Autoren als vielmehr an der Tatsache, dass wir alle gelernt haben. Es braucht Zeit, bis Best Practices herauskommen.

Glücklicherweise ist die Community seit diesen Tagen immens gereift. Bevor wir uns mit einigen dieser Best Practices befassen, wollen wir zunächst einige schlechte Ratschläge aufdecken, die im Internet verbreitet wurden.


Verwenden Sie jQuery nicht

Das Problem bei solchen Tipps ist, dass sie die Idee der Voroptimierung auf ein Extrem bringen.

Ähnlich wie bei Ruby on Rails erfolgte die erste Einführung vieler Entwickler in JavaScript über jQuery. Dies führte zu einem gemeinsamen Zyklus: Lernen Sie jQuery, verlieben Sie sich, vertiefen Sie sich in Vanille-JavaScript und steigen Sie auf.

An diesem Zyklus ist sicherlich nichts auszusetzen, aber er hat den Weg für unzählige Artikel geebnet, in denen empfohlen wurde, dass Benutzer jQuery aufgrund von "Leistungsproblemen" in verschiedenen Situationen nicht verwenden. Es wäre nicht ungewöhnlich zu lesen, dass es besser ist, Vanille for-Schleifen zu verwenden, über $.each. Oder Sie haben irgendwann gelesen, dass es die beste Vorgehensweise ist, document.getElementsByClassName über die Sizzle-Engine von jQuery zu verwenden, da diese schneller ist.

Das Problem mit solchen Tipps ist, dass sie die Idee der Voroptimierung auf ein Extrem bringen und verschiedene Browser-Inkonsistenzen nicht berücksichtigen - die Dinge, die jQuery für uns behoben hat! Das Ausführen eines Tests und das Beobachten einer Einsparung von einigen Millisekunden bei Tausenden von Wiederholungen ist kein Grund, jQuery und seine elegante Syntax aufzugeben. Ihre Zeit ist viel besser investiert, um Teile Ihrer Anwendung zu optimieren, die tatsächlich einen Unterschied machen, wie z. B. die Größe Ihrer Bilder.


Mehrere jQuery-Objekte

Dieses zweite Anti-Muster war wiederum das Ergebnis der Community (einschließlich Ihrer wirklich an einem Punkt), die nicht vollständig verstand, was unter der jQuery-Haube vor sich ging. Als solches sind Sie wahrscheinlich auf Code gestoßen (oder haben sich selbst geschrieben), der ein Element innerhalb einer Funktion unzählige Male in das jQuery-Objekt eingeschlossen hat.

1
$('button.confirm').on('click', function() {
2
    // Do it once
3
    $('.modal').modal();
4
5
    // And once more
6
    $('.modal').addClass('active');
7
8
    // And again for good measure
9
    $('modal').css(...);
10
});

Während dieser Code auf den ersten Blick harmlos erscheint (und im Großen und Ganzen wahrheitsgemäß ist), folgen wir der schlechten Praxis, mehrere Instanzen des jQuery-Objekts zu erstellen. Jedes Mal, wenn wir auf $('.modal') verweisen, wird ein neues jQuery-Objekt generiert. Ist das klug?

Stellen Sie sich das DOM als Pool vor: Jedes Mal, wenn Sie $('.modal') aufrufen, taucht jQuery in den Pool ein und jagt die zugehörigen Münzen (oder Elemente). Wenn Sie das DOM wiederholt nach demselben Selektor abfragen, werfen Sie diese Münzen im Wesentlichen zurück ins Wasser, um dann wieder einzuspringen und sie wiederzufinden!

Verketten Sie Selektoren immer, wenn Sie sie mehrmals verwenden möchten. Das vorherige Code-Snippet kann wie folgt überarbeitet werden:

1
$('button.confirm').on('click', function() {
2
    $('.modal')
3
        .modal()
4
        .addClass('active')
5
        .css(...);
6
});

Alternativ können Sie "Caching" verwenden.

1
$('button.confirm').on('click', function() {
2
    // Do it ONLY once
3
    var modal = $('.modal');
4
5
    modal.modal();
6
    modal.addClass('active');
7
    modal.css(...);
8
});

Mit dieser Technik springt jQuery insgesamt einmal und nicht dreimal in den DOM-Pool.


Auswahlleistung

Der Auswahlleistung wird zu viel Aufmerksamkeit geschenkt.

Obwohl das Web heutzutage nicht allzu allgegenwärtig ist, wurde es vor nicht allzu langer Zeit von unzähligen Artikeln über die Optimierung der Selektorleistung in jQuery bombardiert. Ist es beispielsweise besser, $('div p') oder $('div').find('p') zu verwenden?

Sind Sie für die Wahrheit bereit? Es ist nicht wirklich wichtig. Es ist sicherlich eine gute Idee, ein grundlegendes Verständnis dafür zu haben, wie die Sizzle-Engine von jQuery Ihre Selektorabfragen von rechts nach links analysiert (was bedeutet, dass es besser ist, am Ende Ihres Selektors genauer zu sein als am Anfang). Und je spezifischer Sie sein können, desto besser. Es ist klar, dass $('a.button') für die Leistung besser ist als $('.button'), da jQuery mit ersteren die Suche eher auf die Ankerelemente auf der Seite beschränken kann als alle Elemente.

Darüber hinaus wird der Selektorleistung jedoch zu viel Aufmerksamkeit geschenkt. Vertrauen Sie im Zweifelsfall darauf, dass das jQuery-Team aus den besten JavaScript-Entwicklern der Branche besteht. Wenn in der Bibliothek eine Leistungssteigerung erzielt werden soll, haben sie diese entdeckt. Und wenn nicht, wird eines der Community-Mitglieder eine Pull-Anfrage einreichen.

Beachten Sie in diesem Zusammenhang Ihre Selektoren, aber kümmern Sie sich nicht zu sehr um die Auswirkungen auf die Leistung, es sei denn, Sie können verbalisieren, warum dies erforderlich ist.


Rückruf Hölle

jQuery hat die weit verbreitete Verwendung von Rückruffunktionen gefördert, die sicherlich einen angenehmen Komfort bieten können. Verwenden Sie einfach eine Rückruffunktion, anstatt eine Funktion zu deklarieren. Beispielsweise:

1
$('a.external').on('click', function() {
2
    // this callback function is triggered
3
    // when .external is clicked
4
});

Sie haben sicherlich viel Code geschrieben, der genau so aussieht. Ich weiß ich habe! Bei sparsamer Verwendung dienen anonyme Rückruffunktionen als hilfreiche Annehmlichkeiten. Die Reibung tritt auf der ganzen Linie auf, wenn wir ... die Rückrufhölle betreten (Blitzschlag auslösen)!

Die Hölle des Rückrufs ist, wenn sich Ihr Code mehrmals einrückt, während Sie die Rückruffunktionen weiter verschachteln.

Betrachten Sie den folgenden recht häufigen Code:

1
$('a.data').on('click', function() {
2
    var anchor = $(this);
3
    $(this).fadeOut(400, function() {
4
        $.ajax({
5
            // ...
6
            success: function(data) {
7
                anchor.fadeIn(400, function() {
8
                    // you've just entered callback hell
9
                });
10
            }
11
        });
12
    });
13
});

Als Faustregel gilt: Je stärker Ihr Code eingerückt ist, desto wahrscheinlicher ist es, dass ein Code riecht. Oder, noch besser, fragen Sie sich, sieht mein Code aus wie der Mighty Ducks Flying V?

Wenn Sie Code wie diesen umgestalten, müssen Sie sich fragen: "Wie kann dies getestet werden?" Innerhalb dieses scheinbar einfachen Codebits ist ein Ereignis-Listener an eine Verknüpfung gebunden, das Element wird ausgeblendet, ein AJAX-Aufruf wird ausgeführt. Nach Erfolg wird das Element wieder eingeblendet. Vermutlich werden die resultierenden Daten irgendwo angehängt. Das ist sicher viel zu testen!

Wäre es nicht besser, diesen Code in handlichere und testbarere Teile aufzuteilen? Bestimmt. Obwohl Folgendes weiter optimiert werden kann, könnte ein erster Schritt zur Verbesserung dieses Codes sein:

1
var updatePage = function(el, data) {
2
    // append fetched data to DOM
3
};
4
5
var fetch = function(ajaxOptions) {
6
    ajaxOptions = ajaxOptions || {
7
        // url: ...
8
        // dataType: ...
9
        success: updatePage
10
    };
11
12
    return $.ajax(ajaxOptions);
13
};
14
15
$('a.data').on('click', function() {
16
    $(this).fadeOut(400, fetch);
17
});

Noch besser ist es, wenn Sie eine Vielzahl von Aktionen auslösen müssen, die relevanten Methoden in einem Objekt zu enthalten.

Überlegen Sie, wie in einem Fast-Food-Restaurant wie McDonalds jeder Mitarbeiter für eine Aufgabe verantwortlich ist. Joe macht die Pommes, Karen registriert Kunden und Mike grillt Burger. Wenn alle drei Mitarbeiter alles tun würden, würde dies eine Vielzahl von Wartbarkeitsproblemen mit sich bringen. Wenn Änderungen umgesetzt werden müssen, müssen wir uns mit jeder Person treffen, um sie zu besprechen. Wenn wir beispielsweise Joe ausschließlich auf die Pommes konzentrieren, müssen wir nur mit Joe und niemand anderem sprechen, falls wir die Anweisungen für die Zubereitung von Pommes anpassen müssen. Sie sollten einen ähnlichen Ansatz für Ihren Code wählen. Jede Funktion ist für eine Aufgabe verantwortlich.

Im obigen Code löst die fetch-Funktion lediglich einen AJAX-Aufruf der angegebenen URL aus. Die updatePage-Funktion akzeptiert einige Daten und hängt sie an das DOM an. Wenn wir nun eine dieser Funktionen testen möchten, um sicherzustellen, dass sie wie erwartet funktioniert, z. B. die updatePage-Methode, können wir das Datenobjekt verspotten und an die Funktion senden. Einfach!


Das Rad neu erfinden

Es ist wichtig, sich daran zu erinnern, dass das jQuery-Ökosystem in den letzten Jahren stark gereift ist. Wenn Sie eine bestimmte Komponente benötigen, hat sie wahrscheinlich bereits von einer anderen Komponente erstellt. Erstellen Sie auf jeden Fall weiterhin Plugins, um Ihr Verständnis der jQuery-Bibliothek zu verbessern (wir werden in diesem Artikel tatsächlich eines schreiben). Für die Verwendung in der Praxis sollten Sie sich jedoch auf potenzielle vorhandene Plugins beziehen, bevor Sie das Rad neu erfinden.

Benötigen Sie beispielsweise eine Datumsauswahl für ein Formular? Sparen Sie sich die Beinarbeit und nutzen Sie stattdessen die Community-gesteuerte und hoch getestete jQuery-UI-Bibliothek.

Sobald Sie auf die erforderliche jQuery-UI-Bibliothek und das zugehörige Stylesheet verweisen, ist das Hinzufügen einer Datumsauswahl zu einer Eingabe so einfach wie folgt:

1
<input id="myDateInput" type="text">
2
3
<script>
4
$("#myDateInput").datepicker({
5
   dateFormat: 'yy-mm-dd'
6
}); 
7
8
// Demo: https://jsbin.com/ayijig/2/
9
</script>

Oder was ist mit einem Akkordeon? Natürlich können Sie diese Funktionalität selbst schreiben oder stattdessen erneut die jQuery-Benutzeroberfläche nutzen.

Erstellen Sie einfach das erforderliche Markup für Ihr Projekt.

1
<div id="accordion">
2
    <h3><a href="#">Chapter 1</a></h3>
3
    <div><p>Some text.</p></div>
4
5
    <h3><a href="#">Chapter 2</a></h3>
6
    <div><p>Some text.</p></div>
7
8
    <h3><a href="#">Chapter 3</a></h3>
9
    <div><p>Some text.</p></div>
10
11
    <h3><a href="#">Section 4</a></h3>
12
    <div><p>Some text.</p></div>
13
</div>

Dann verwandeln Sie es automatisch in ein Akkordeon.

1
$(function() {
2
    $("#accordion").accordion();
3
});

Was wäre, wenn Sie in 30 Sekunden Registerkarten erstellen könnten?

Erstellen Sie das Markup:

1
<div id="tabs">
2
    <ul>
3
        <li><a href="#tabs-1">About Us</a></li>
4
        <li><a href="#tabs-2">Our Mission</a></li>
5
        <li><a href="#tabs-3">Get in Touch</a></li>
6
    </ul>
7
    <div id="tabs-1">
8
        <p>About us text.</p>
9
    </div>
10
    <div id="tabs-2">
11
        <p>Our mission text.</p>
12
    </div>
13
    <div id="tabs-3">
14
        <p>Get in touch text.</p>
15
    </div>
16
</div>

Und aktiviere das Plugin.

1
$(function() {
2
    $("#tabs").tabs();
3
});

Getan! Es erfordert nicht einmal ein nennenswertes Verständnis von JavaScript.


Plugin-Entwicklung

Lassen Sie uns nun einige bewährte Methoden zum Erstellen von jQuery-Plugins untersuchen, die Sie irgendwann in Ihrer Entwicklungskarriere ausführen müssen.

Wir werden ein relativ einfaches MessageBox-Plugin als Demo für unser Lernen verwenden. Fühlen Sie sich frei, mitzuarbeiten; in der Tat, bitte tun!

Die Aufgabe: Implementieren Sie die erforderliche Funktionalität zum Anzeigen von Dialogfeldern mithilfe der Syntax $.message ('SAY TO THE USER'). Auf diese Weise können wir beispielsweise den Benutzer vor dem dauerhaften Löschen eines Datensatzes bitten, die Aktion zu bestätigen, anstatt auf unflexible und hässliche alert-Felder zurückzugreifen.


Schritt 1

Der erste Schritt besteht darin, herauszufinden, wie $.message "aktiviert" wird. Anstatt den Prototyp von jQuery zu erweitern, müssen wir für die Anforderungen dieses Plugins nur eine Methode an den jQuery-Namespace anhängen.

1
(function($) {
2
    $.message = function(text) {
3
    console.log(text);
4
  };
5
})(jQuery);

So einfach ist das; Probieren Sie es aus! Wenn Sie $.message ('Here is my message') aufrufen, sollte diese Zeichenfolge in der Browserkonsole protokolliert werden (Umschalt + Befehl + i in Google Chrome).


Schritt 2

Es gibt zwar nicht genügend Platz, um den Prozess des Testens des Plugins abzudecken, dies ist jedoch ein wichtiger Schritt, den Sie untersuchen sollten. Beim Refactoring von getestetem Code tritt ein erstaunliches Gefühl der Sicherheit auf.

Wenn Sie beispielsweise die Testsuite QUnit von jQuery verwenden, können Sie den Code aus Schritt 1 testen, indem Sie Folgendes schreiben:

1
 module('jQuery.message', {
2
    test('is available on the jQuery namespace', 1, function() {
3
        ok($.message, 'message method should exist');
4
    });
5
 });

Die über QUnit verfügbare Funktion ok behauptet lediglich, dass das erste Argument ein wahrer Wert ist. Wenn die message-Methode im jQuery-Namespace nicht vorhanden ist, wird false zurückgegeben. In diesem Fall schlägt der Test fehl.

Nach dem testgetriebenen Entwicklungsmuster wäre dieser Code der erste Schritt. Sobald Sie festgestellt haben, dass der Test fehlgeschlagen ist, müssen Sie im nächsten Schritt die entsprechende message-Methode hinzufügen.

Der Kürze halber wird in diesem Artikel nicht weiter auf den Prozess der testgetriebenen Entwicklung in JavaScript eingegangen. Sie sollten sich jedoch auf das GitHub-Repo für dieses Projekt beziehen, um alle Tests für das Plugin zu überprüfen: https://github.com/JeffreyWay/MessageBox/blob/master/test/MessageBox_test.js


Schritt 3

Eine message-Methode, die nichts tut, hilft niemandem! Nehmen wir die bereitgestellte Nachricht und zeigen sie dem Benutzer an. Anstatt jedoch einen großen Code-Globus in die $.message-Methode einzubetten, verwenden wir stattdessen einfach die Funktion, um ein Message-Objekt zu instanziieren und zu initialisieren.

1
(function($) {
2
    "use strict";
3
4
    var Message = {
5
        initialize: function(text) {
6
            this.text = text;
7
8
            return this;
9
        }
10
    };
11
12
    $.message = function(text) {
13
        // Needs polyfill for IE8--
14
        return Object.create(Message).initialize(text);
15
    };
16
})(jQuery);

Dieser Ansatz macht nicht nur das Message-Objekt wieder testbarer, sondern ist auch eine sauberere Technik, die unter anderem die Rückrufhölle wieder schützt. Stellen Sie sich dieses Message-Objekt als Darstellung eines einzelnen Nachrichtenfelds vor.


Schritt 4

Wenn die Message ein einzelnes Nachrichtenfeld darstellt, wie lautet der HTML-Code für eines? Erstellen wir ein div mit einer Klasse von message-box und stellen es der Message-Instanz über eine el-Eigenschaft zur Verfügung.

1
var Message = {
2
    initialize: function(text) {
3
        this.el = $('<div>', {
4
            'class': 'message-box',
5
            'style': 'display: none'
6
        });
7
        this.text = text;
8
9
        return this;
10
    }
11
};

Das Objekt hat jetzt einen unmittelbaren Verweis auf das Wrapping-div für das Meldungsfeld. Um Zugang dazu zu erhalten, könnten wir Folgendes tun:

1
var msg = Object.create(Message).initialize();
2
3
// [<div class=​"message-box" style=​"display:​ none">​</div>​] 
4
console.log(msg.el);

Denken Sie daran, wir haben jetzt ein HTML-Fragment, das jedoch noch nicht in das DOM eingefügt wurde. Dies bedeutet, dass wir uns keine Gedanken über unnötige Rückflüsse machen müssen, wenn wir Inhalte an das div anhängen.


Schritt 5

Der nächste Schritt besteht darin, die bereitgestellte Nachrichtenzeichenfolge in das div einzufügen. Das ist leicht!

1
initialize: function(text) {
2
    // ...
3
    this.el.html(this.text);
4
}
5
6
// [<div class=​"message-box" style=​"display:​ none">​Here is an important message​</div>​]

Es ist jedoch unwahrscheinlich, dass wir den Text direkt in das div einfügen möchten. Realistischer wird das Meldungsfeld eine Vorlage haben. Während wir den Benutzer des Plugins eine Vorlage erstellen und darauf verweisen lassen könnten, lassen Sie uns die Dinge einfach halten und die Vorlage auf das Message-Objekt beschränken.

1
 var Message = {
2
    template: function(text, buttons) {
3
        return [
4
            '<p class="message-box-text">' + text + '</p>',
5
            '<div class="message-box-buttons">',
6
                buttons,
7
            '</div>'
8
        ].join('');
9
10
    // ...
11
  };

In Situationen, in denen Sie keine andere Wahl haben, als HTML in Ihr JavaScript zu verschachteln, besteht ein beliebter Ansatz darin, die HTML-Fragmente als Elemente in einem Array zu speichern und sie dann zu einer HTML-Zeichenfolge zusammenzufügen.

In diesem Ausschnitt oben wird der Text der Nachricht jetzt in einen Absatz mit einer Klasse von message-box-text eingefügt. Wir haben auch einen Platz für die Schaltflächen festgelegt, die wir in Kürze implementieren werden.

Jetzt kann die initialize-Methode aktualisiert werden auf:

1
initialize: function(text) {
2
    // ...
3
    this.el.html(this.template(text, buttons));
4
}

Beim Auslösen erstellen wir die Struktur für das Meldungsfeld:

1
<div class="message-box" style="display: none;">
2
    <p class="message-box-text">Here is an important message.</p>
3
    <div class="message-box-buttons></div>
4
</div>

Bei komplexeren Projekten sollten Sie die beliebte Templating-Engine für Lenker verwenden.


Schritt 6

Damit das Meldungsfeld so flexibel wie möglich ist, muss der Benutzer des Plugins optional festlegen können, welche Schaltflächen dem Benutzer angezeigt werden sollen, z. B. "Okay", "Abbrechen", "Ja" , "usw. Wir sollten in der Lage sein, den folgenden Code hinzuzufügen:

1
$.message('Are you sure?', {
2
    buttons: ['Yes', 'Cancel']
3
});

... und generieren Sie ein Meldungsfeld mit zwei Schaltflächen.

Um diese Funktionalität zu implementieren, aktualisieren Sie zuerst die $.message-Definition.

1
$.message = function(text, settings) {
2
    var msg = Object.create(Message);
3
    msg.initialize(text, settings);
4
5
    return msg;
6
};

Jetzt wird das settings-Objekt an die initialize-Methode übergeben. Lassen Sie es uns aktualisieren.

1
initialize: function(text, settings) {
2
    this.el = $('<div>', {'class': 'message-box', 'style': 'display: none'});
3
    this.text = text;
4
    this.settings = settings
5
6
    this.el.html(this.template(text, buttons));
7
}

Nicht schlecht, aber was ist, wenn der Plugin-Benutzer keine Einstellungen angibt? Berücksichtigen Sie immer die verschiedenen Verwendungsmöglichkeiten Ihres Plugins.


Schritt 7

Wir gehen davon aus, dass der Benutzer des Plugins beschreibt, welche Schaltflächen angezeigt werden sollen. Aus Sicherheitsgründen ist es jedoch wichtig, eine Reihe von Standardeinstellungen anzugeben. Dies ist eine bewährte Methode beim Erstellen von Plugins.

1
$.message = function(text, settings) {
2
    var msg = Object.create(Message);
3
    msg.initialize(text, settings);
4
5
    return msg;
6
};
7
8
$.message.defaults = {
9
    icon: 'info',
10
    buttons: ['Okay'],
11
    callback: null
12
};

Sollte der Plugin-Benutzer bei diesem Ansatz die Standardeinstellungen ändern müssen, muss er nur $.message.defaults nach Bedarf aktualisieren. Denken Sie daran: Verbergen Sie niemals die Standardeinstellungen vor dem Benutzer. Stellen Sie sie "nach außen" zur Verfügung.

Hier haben wir einige Standardeinstellungen festgelegt: das Symbol, die Schaltflächen und eine Rückruffunktion, die ausgelöst werden soll, sobald der Benutzer auf eine der Schaltflächen im Meldungsfeld geklickt hat.

jQuery bietet eine hilfreiche Möglichkeit, die Standardoptionen für ein Plugin (oder wirklich jedes Objekt) über seine extend-Methode zu überschreiben.

1
initialize: function(text, buttons) {
2
    // ...
3
    this.settings = $.extend({}, $.message.defaults, settings);
4
}

Mit dieser Änderung entspricht this.settings nun einem neuen Objekt. Wenn der Plugin-Benutzer Einstellungen angibt, überschreibt er das defaults-Objekt des Plugins.


Schritt 8

Wenn Sie dem Meldungsfeld abhängig von der Aktion ein benutzerdefiniertes Symbol hinzufügen möchten, müssen Sie dem Element eine CSS-Klasse hinzufügen und dem Benutzer das entsprechende Anwenden eines Hintergrundbilds ermöglichen.

Fügen Sie innerhalb der initialize-Methode Folgendes hinzu:

1
this.el.addClass('message-box-' + this.settings.icon);

Wenn im settings-Objekt kein Symbol angegeben ist, wird die Standardeinstellung info verwendet: .message-box-info. Jetzt können wir eine Vielzahl von CSS-Klassen anbieten (über den Rahmen dieses Tutorials hinaus), die verschiedene Symbole für das Meldungsfeld enthalten. Hier sind einige Beispiele, um Ihnen den Einstieg zu erleichtern.

1
.message-box-info {
2
    background: url(path/to/info/icon.png) no-repeat;
3
}
4
5
.message-box-warning {
6
    background: url(path/to/warning/icon.png) no-repeat;
7
}

Idealerweise möchten Sie als Teil Ihres MessageBox-Plugins ein externes Stylesheet einfügen, das das grundlegende Styling für das Meldungsfeld, diese Klassen und eine Handvoll Symbole enthält.


Schritt 9

Das Plugin akzeptiert jetzt eine Reihe von Schaltflächen, die auf die Vorlage angewendet werden sollen, aber wir haben noch nicht die Funktionalität geschrieben, um diese Informationen nutzbar zu machen. Der erste Schritt besteht darin, ein Array von Schaltflächenwerten zu verwenden und diese in die erforderlichen HTML-Eingaben zu übersetzen. Erstellen Sie eine neue Methode für das Message-Objekt, um diese Aufgabe zu erledigen.

1
createButtons: function(buttons) {}

jQuery.map ist eine hilfreiche Methode, die eine Funktion auf jedes Element in einem Array anwendet und ein neues Array mit den angewendeten Änderungen zurückgibt. Dies ist perfekt für unsere Bedürfnisse. Für jedes Element im Schaltflächenarray, z. B. ['Yes', 'No'], möchten wir den Text durch eine HTML-Eingabe ersetzen, wobei der Wert entsprechend festgelegt wird.

1
createButtons: function(buttons) {
2
  return $.map(buttons, function(button) {
3
    return '<input type="submit" value="' + button + '">';
4
  }).join('');
5
}

Aktualisieren Sie als Nächstes die initialize-Methode, um diese neue Methode aufzurufen.

1
initialize: function(text, settings) {
2
    this.el = $('<div>', {'class': 'message-box', 'style': 'display: none'});
3
    this.text = text;
4
    this.settings = $.extend({}, $.message.defaults, settings);
5
6
    var buttons = this.createButtons(this.settings.buttons);
7
    this.el.html(this.template(text, buttons));
8
9
    return this;
10
}

Schritt 10

Was nützt eine Schaltfläche, wenn beim Klicken des Benutzers nichts passiert? Ein guter Ort zum Speichern aller Ereignis-Listener für eine Ansicht ist eine spezielle events-Methode für das zugeordnete Objekt, wie folgt:

1
initialize: function() {
2
    // ...
3
    this.el.html(this.template(text, buttons));
4
    this.events();
5
},
6
7
events: function() {
8
  var self = this;
9
10
  this.el.find('input').on('click', function() {
11
    self.close();
12
    if ( typeof self.settings.callback === 'function' ) {
13
      self.settings.callback.call(self, $(this).val());
14
    }
15
  });
16
}

Dieser Code ist etwas komplexer, da der Benutzer des Plugins die Möglichkeit haben muss, seine eigene Rückruffunktion auszulösen, wenn auf eine Schaltfläche im Meldungsfeld geklickt wird. Der Code bestimmt einfach, ob eine callback-Funktion registriert wurde, löst sie in diesem Fall aus und sendet den Wert der ausgewählten Schaltfläche. Stellen Sie sich vor, ein Meldungsfeld bietet zwei Schaltflächen: "Akzeptieren" und "Abbrechen". Der Benutzer des Plugins muss eine Möglichkeit haben, den Wert der angeklickten Schaltfläche zu erfassen und entsprechend zu reagieren.

Beachten Sie, wo wir self.close() aufrufen? Diese Methode, die noch erstellt werden muss, ist für eines verantwortlich: Schließen und Entfernen des Meldungsfelds aus dem DOM.

1
close: function() {
2
  this.el.animate({
3
    top: 0,
4
    opacity: 'hide'
5
  }, 150, function() {
6
    $(this).remove();
7
  });
8
}

Um ein wenig Flair hinzuzufügen, blenden wir nach dem Ausblenden des Nachrichtenfelds im Verlauf von 150 Millisekunden das Feld aus und wechseln es nach oben.


Schritt 11

Die Funktionalität wurde implementiert! Der letzte Schritt besteht darin, dem Benutzer das Meldungsfeld zu präsentieren. Wir fügen dem Message-Objekt eine letzte show-Methode hinzu, mit der das Nachrichtenfeld in das DOM eingefügt und positioniert wird.

1
show: function() {
2
  this.el.appendTo('body').animate({
3
    top: $(window).height() / 2 - this.el.outerHeight() / 2,
4
    opacity: 'show'
5
  }, 300);
6
}

Es ist nur eine einfache Berechnung erforderlich, um das Feld vertikal in der Mitte des Browserfensters zu positionieren. Damit ist das Plugin fertig!

1
$.message = function(text, settings) {
2
  var msg = Object.create(Message).initialize(text, settings);
3
4
  msg.show();
5
6
  return msg;
7
};

Schritt 12

Um Ihr neues Plugin zu verwenden, rufen Sie einfach $.message() auf und übergeben Sie eine Nachricht und alle zutreffenden Einstellungen wie folgt:

1
$.message('The row has been updated.');

Oder um eine Bestätigung für eine destruktive Aktion anzufordern:

1
$.message('Do you really want to delete this record?', {
2
    buttons: ['Yes', 'Cancel'],
3
    icon: 'alert',
4
    callback: function(buttonText) {
5
        if ( buttonText === 'Yes' ) {
6
            // proceed and delete record
7
        }
8
    }
9
});

Gedanken schließen

Um mehr über die Entwicklung von jQuery zu erfahren, lesen Sie bitte meinen Kurs auf dieser Website "30 Tage zum Erlernen von jQuery".

Während der Erstellung dieses Beispiel-MessageBox-Plugins wurden verschiedene bewährte Methoden entwickelt, z. B. das Vermeiden von Rückrufen, das Schreiben von testbarem Code, das Bereitstellen der Standardoptionen für den Plugin-Benutzer und das Sicherstellen, dass jede Methode für genau eine Aufgabe verantwortlich ist.

Während man sicherlich den gleichen Effekt erzielen könnte, wenn man unzählige Rückruffunktionen in $.message einbettet, ist dies selten eine gute Idee und wird sogar als Anti-Pattern angesehen.

Denken Sie an die drei Schlüssel für wartbaren Code und flexible jQuery-Plugins und -Skripte:

  1. Könnte ich das testen? Wenn nicht, überarbeiten Sie den Code und teilen Sie ihn in Blöcke auf.
  2. Habe ich die Möglichkeit angeboten, meine Standardeinstellungen zu überschreiben?
  3. Befolge ich schlechte Praktiken oder mache ich Annahmen?

Um mehr über die Entwicklung von jQuery zu erfahren, lesen Sie bitte meinen Screencast-Kurs auf dieser Website "30 Tage zum Erlernen von jQuery".