2012-04-24 2 views
31

Ich bin ein Projekt von einer „alten“ Browser-Stil Modulstruktur zu einem „neuen“ browser- oder Wechsel - serverseitige JavaScript Modul Struktur mit require.js.Aufrufe von Methoden in RequireJs Module von HTML-Elementen wie Onclick-Handler

Auf dem Client ich ein Offsite bin mit gehostete jQuery, so begann ich aus dem Beispiel, das sie in der "use priority config" Technik der README geben:

<title>My Page</title> 
<script src="scripts/require.js"></script> 
<script> 
require({ 
    baseUrl: 'scripts', 
    paths: { 
     jquery: 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min', 
     jqueryui: ..., 
     ... 
     ... // bunch more paths here 
    }, 
    priority: ['jquery'] 
}, [ 'main' ]); 
</script> 

Das ist eigentlich alles in Ordnung arbeiten. Aber ich möchte die Funktionalität von main auf die HTML-Webseite selbst exportieren. Zum Beispiel:

<a class="button" href="#" onclick="MyApi.foo();"> 
    <img src="foo.png" alt="foo" />Click for: <b>Foo!</b> 
</a> 

Bevor in das AMD-Modul passendes Muster hatte ich Funktionalität von meinen verschiedenen Dateien ausgesetzt durch ein Wörterbuch Objekt im globalen Raum zu schaffen:

// main.js 

var MyApi = {}; 

jQuery(document).ready(function($) { 
    // ...unexported code goes here... 

    // export function via MyApi 
    MyApi.foo = function() { 
     alert("Foo!"); 
    }; 
}); 

Aber ich weiß nicht, Was ist der richtige Ansatz in require.js? Ist es in Ordnung, in den HTML-Code mehr require Anweisungen innerhalb von <script> Tags, und dann Module benennen, so dass es von der Webseite verwendet werden kann? Oder sollte das immer dynamisch innerhalb von main.js gemacht werden, zB $('#foobutton').click(...)?

Antwort

30

Ein Vorteil der Verwendung von AMD ist, dass Namespaces nicht mehr benötigt werden. Der Versuch, sie mit RequireJS wieder zu erstellen, wird gegen die von AMD geförderten Muster gehen.

In Bezug auf die Verwendung von main.js, ist dies nur wirklich sinnvoll, wenn Sie eine einzelne Seite App haben und alle Ihre Code-Referenz von einem Ort sein. Sie können weitere Anrufe tätigen, um andere Module nach Bedarf zu laden und zu laden.

Arbeiten mit dem Beispiel von oben, könnten Sie es auf diese Weise nähern:

foo.js

define(['jquery'], function($) { 

    // Some set up 
    // code here 

    // Return module with methods 
    return { 
     bar: function() { 

     } 
    } 


}); 

page.js

require(['foo'], function(foo) { 

    // jQuery loaded by foo module so free to use it 
    $('.button').on('click', function(e) { 
     foo.bar(); 
     e.preventDefault(); 
    }); 

}); 

dann auf Ihrer Seite Anfrage die Datei page.js mit require.

Arbeiten mit dem Beispiel oben:

require({ 
    // config stuff here 
}, [ 'page' ]); 

Oder es auf der Seite Laden weiter unten:

<script> 
    require(['page']); 
</script> 

einige zusätzliche Punkte

  • das Muster unter Verwendung der oben, Seite .js könnte leicht viele andereerfordernModule zum Laden anderer seitenbezogener Funktionen.

  • Wo zuvor Mitglieder an Ihren globalen Namespace angehängt wurden, teilen Sie diesen Code jetzt in separate Module auf, die auf auf jeder Seite wiederverwendet werden können. Alles ohne auf ein globales Objekt angewiesen zu sein.

  • auf diese Weise verwenden, erfordern Ereignisse Ihre DOM-Elemente befestigen wird höchstwahrscheinlich rely on the DOM Ready module von RequireJS bereitgestellt

+0

Hey, danke (zurück zu diesem Projekt und im Detail auf die Antwort). Sie stellen den Grund in Worte, warum Code in onclick nicht passt mit dieser Methode; Handler, die direkt im HTML der Seite sind, würden von jeder API, die sie aufrufen, den gleichen importierten Namen für alle geladenen .js-Dateien haben (äh ... oder?). Aber mit diesem Token ... sollte page.js in diesem Muster nicht ausdrücklich die jquery-Zuordnung zu $ ​​erwähnen, anstatt sie zu erben, nur weil sie von foo so importiert wurde? – HostileFork

+0

Ich habe immer an Module in dem Sinne gedacht, dass sie wiederverwendbare, kategorisierte Code-Teile sind. Aber mit dieser Herangehensweise muss alles in ein Modul geworfen werden und es gibt keine klare Unterscheidung zwischen regulären Dingen wie Ereignisbindung und tatsächlichen Modulen - wenn Sie verstehen, was ich meine. Gibt es keinen anderen Weg? – backdesk

+0

In der Frage hängt das DOM vom globalen MMyApi-Objekt ab. In dieser Antwort hängt das Seitenmodul vom DOM ab, das ebenfalls global ist. Es muss eine Art Abhängigkeit geben. Welche zu verwenden ist vielleicht eine subjektive Wahl. –

3

Putting onclick="" in Ihrem Markup fühlt sich schmutzig - Mischen Präsentation mit Inhalt. Ich würde empfehlen, fügen Sie einen <script> Block und setzen Sie die require darin, und einmal innerhalb des Rückrufs, und innerhalb eines anderen inneren $(document).ready() wenn notwendig, dann verkabeln Sie Ihre Event-Handler auf die übliche Weise: $('#node').click(...). Wenn Sie dies generisch genug tun können, dass es auf mehrere Seiten anwendbar ist, fügen Sie es in eine externe Datei ein, die minimiert, kombiniert und zwischengespeichert wird. In der Regel sind diese Dinge jedoch seitenspezifisch. Daher ist ein <script>-Tag am Ende der Seite eine gute Lösung, um noch eine externe Ressourcenanforderung zu vermeiden.

+2

+1 * vor ein paar Tagen: -) * ... Ja, bei Präsentation und Inhalt, obwohl es sich anfühlt, als ob Web-Programmierung solche Stöcke und Leim ist, dass der konkrete Wert der verschachtelten "Best Practice" oft durch einfachere Methoden aufgewogen wird. Ich sah ein ähnliches Argument über das HTML5-Beispiel mit einem "Wann haben wir dieses Zeug in unseren Köpfen laufen lassen". (http://csswizarry.com/2011/01/the-real-html5-boilerplate/) Aber @ SimonSmiths * "Wenn Sie require.js verwenden wollen, dann ist das Importieren in den Seitenbereich schlecht und das ist was Sie" d muss für Code in onclick tun, um irgendetwas zu sehen "macht Sinn für mich in einem" wenn A dann B "Weise ... – HostileFork

+0

Persönlich denke ich, der Nutzen in der Lage zu sagen, was ein Knopf tut, ohne zu suchen der code und wahrscheinlich immer noch nicht finden, überwiegt stark die möglichen vorteile davon abzutrennen. Wenn Sie ein Button-Tag mit einem "Onclick" sehen, können Sie nicht raten, was passiert, wenn der Nutzer auf diesen Button klickt. HTML ist keine reine Präsentation und wird es nie sein, und das ist in Ordnung für mich. – Jasmine

14

Sie auch den Hinweis auf Javascript Fenster Klasse festlegen.

Am unteren Rand des Anwendungsmoduls window.MyApi = MyApi;

<a class="button" href="#" onclick="MyApi.foo();"></a>

2

Eine andere Lösung ist nur Code wie das verwenden (natürlich requirejs muss auf der Seite hinzugefügt werden):

<input type="button" onclick="(function() { require('mymodule').do_work() })()"/> 
Verwandte Themen