389 Stimmen

Unter Verwendung von Rails 3.1, wo platzieren Sie Ihren "seitenübergreifenden" JavaScript-Code?

Nach meinem Verständnis wird Ihr gesamter JavaScript-Code in eine Datei zusammengeführt. Rails macht dies standardmäßig, wenn es //= require_tree . am Ende Ihrer application.js-Manifestdatei hinzufügt.

Dies klingt wie ein Lebensretter, aber ich mache mir ein wenig Sorgen um seitenbezogenen JavaScript-Code. Wird dieser Code auf jeder Seite ausgeführt? Das Letzte, was ich möchte, ist, dass alle meine Objekte für jede Seite instanziiert werden, wenn sie nur auf einer Seite benötigt werden.

Besteht nicht auch das Risiko von konkurrierendem Code?

Oder setzen Sie einfach ein kleines script-Tag am Ende der Seite, das einfach eine Methode aufruft, die den JavaScript-Code für die Seite ausführt?

Brauchen Sie dann nicht mehr require.js?

Danke

EDIT: Ich schätze alle Antworten... aber ich glaube nicht, dass sie wirklich das Problem ansprechen. Einige von ihnen handeln von Styling und scheinen nicht zuzutreffen... und andere erwähnen nur javascript_include_tag... was ich weiß (offensichtlich...) aber anscheinend ist der Weg für Rails 3.1, zukünftig Ihren gesamten JavaScript-Code in eine Datei zu packen, anstatt einzelnes JavaScript am Ende jeder Seite zu laden.

Die beste Lösung, die ich mir vorstellen kann, ist, bestimmte Funktionen in div-Tags mit ids oder classen zu packen. Im JavaScript-Code prüfen Sie einfach, ob die id oder class auf der Seite vorhanden ist, und wenn ja, führen Sie den entsprechenden JavaScript-Code aus. Auf diese Weise wird der JavaScript-Code nicht ausgeführt, wenn das dynamische Element nicht auf der Seite ist - obwohl er in der großen application.js-Datei enthalten ist, die von Sprockets gebündelt wird.

Meine obige Lösung hat den Vorteil, dass z.B. wenn eine Suchleiste auf 8 der 100 Seiten enthalten ist, sie nur auf diesen 8 Seiten läuft. Außerdem müssen Sie den Code nicht auf 8 der Seiten der Website einfügen. Tatsächlich müssen Sie niemals wieder manuelle Skript-Tags auf Ihrer Website einfügen.

Ich denke, das ist die eigentliche Antwort auf meine Frage.

11 Stimmen

"Der Weg von Rails 3.1 ist es, alle deine JavaScript-Dateien in eine Datei zu packen, anstatt einzelne JavaScript-Dateien am Ende jeder Seite zu laden." — Nur weil das Rails-Kernteam wirklich schlecht darin ist, zu wissen, wie man JavaScript verwaltet. Kleine Dateien sind im Allgemeinen besser (siehe meine Kommentare anderswo). Wenn es um JavaScript geht, ist der Rails-Weg selten der richtige Weg (außer beim Asset-Pipeline, die wirklich gut ist, und der Förderung von CoffeeScript).

0 Stimmen

So werden Sie Ihre seitenbezogenen JS-Dateien auf jeder Seite einfügen? Ich denke, das ist eine Verschwendung, ich stimme ClosureCowboys Antwort mehr zu.

1 Stimmen

Hast du dir die akzeptierte Antwort auf diese Frage angesehen? stackoverflow.com/questions/6571753/…

156voto

meleyal Punkte 30244

Die Asset-Pipeline-Dokumentation zeigt, wie man controller-spezifisches JS macht:

Zum Beispiel, wenn ein ProjectsController generiert wird, wird eine neue Datei unter app/assets/javascripts/projects.js.coffee und eine weitere unter app/assets/stylesheets/projects.css.scss erstellt. Sie sollten jegliches JavaScript oder CSS, das spezifisch für einen Controller ist, in ihre entsprechenden Asset-Dateien platzieren, da diese Dateien dann nur für diese Controller geladen werden können, mit Zeilen wie <%= javascript_include_tag params[:controller] %> oder <%= stylesheet_link_tag params[:controller] %>.

Link zu: asset_pipeline

50 Stimmen

Das ist die eleganteste Möglichkeit, es zu tun. Aber du musst auch die Zeile //= require_tree . aus der application.js.coffee entfernen.

2 Stimmen

Ich stimme voll und ganz mit dieser Methode überein. Die anderen Methoden scheinen sehr umständlich zu sein und laden letztendlich immer noch eine riesige JS-Datei. Das Projekt, an dem ich arbeite, hat fast 2 MB an JS-Dateien / Plugins usw., NACHDEM sie kombiniert / minimiert wurden.

2 Stimmen

Ich bin ziemlich neu in Rails, aber es scheint mir, dass dies das Standardverhalten sein sollte.

77voto

welldan97 Punkte 3053

Für das seitenbezogene js können Sie die Garber-Irish-Lösung verwenden.

Also könnte Ihr Rails-Javascript-Ordner für zwei Controller - cars und users - so aussehen:

javascripts/
 application.js
 init.js
 markup_based_js_execution
 cars
    init .js
    index.js
    ...
 users
     ...

Und das Javascript würde so aussehen:

// application.js

//= 
//= require init.js
//= require_tree cars
//= require_tree users

// init.js

SITENAME = new Object();
SITENAME.cars = new Object;
SITENAME.users = new Object;

SITENAME.common.init = function (){
  // Ihr js-Code für alle Seiten hier
}

// cars/init.js

SITENAME.cars.init = function (){
  // Ihr js-Code für den Cars-Controller hier
}

// cars/index.js

SITENAME.cars.index = function (){
  // Ihr js-Code für die Index-Methode des Cars-Controllers
}

und markup_based_js_execution wird Code für das UTIL-Objekt enthalten, und bei DOM-Ready wird die UTIL.init ausgeführt.

Und vergessen Sie nicht, dies in Ihre Layoutdatei einzufügen:

Ich denke auch, dass es besser ist, Klassen anstelle von data-*-Attributen zu verwenden, für besseres seitenbezogenes CSS. Wie Jason Garber erwähnt hat: seitenbezogene CSS-Selektoren können wirklich umständlich werden (wenn Sie data-*-Attribute verwenden)

Ich hoffe, das hilft Ihnen.

4 Stimmen

Was ist, wenn Sie eine Variable benötigen, die für alle Aktionen im Benutzer-Controller verfügbar ist, aber nicht in anderen Controllern? Hat diese Methode nicht einige Scoping-Probleme?

0 Stimmen

@tybro0103, Ich denke, um dieses Verhalten umzusetzen, möchten Sie etwas Ähnliches wie window.varForOneController='val' in dieser Controller-Init-Funktion schreiben. Die Gon-Gem kann auch helfen (github.com/gazay/gon). Es gibt auch andere Lösungsansätze.

0 Stimmen

Derzeit versuche ich, keine seitenbezogenen js zu verwenden. Ich versuche bei $(.Klassenname) Selektoren zu bleiben, aber ich setze nicht viel Logik in js.

64voto

sujal Punkte 1604

Ich sehe, dass du deine eigene Frage beantwortet hast, aber hier ist eine andere Option:

Grundsätzlich gehst du davon aus, dass //= require_tree . erforderlich ist. Das ist es nicht. Du kannst es entfernen. In meiner aktuellen Anwendung, die ehrlich gesagt das erste Mal mit 3.1.x ist, habe ich drei verschiedene oberste JS-Dateien erstellt. Meine application.js Datei enthält nur

//= require jquery
//= require jquery_ujs
//= require_directory .
//= require_directory ./api
//= require_directory ./admin

So kann ich Unterverzeichnisse erstellen, mit ihren eigenen obersten JS-Dateien, die nur das enthalten, was ich brauche.

Die Schlüssel sind:

  1. Du kannst require_tree entfernen - Rails ermöglicht es dir, die Annahmen, die es macht, zu ändern
  2. Es ist nichts Besonderes an dem Namen application.js - jede Datei im Unterverzeichnis assets/javascript kann Vorverarbeitungsdirektiven mit //= enthalten

Hoffentlich hilft das und fügt einige Details zu ClosureCowboy's Antwort hinzu.

8 Stimmen

+1 Das ist toll zu wissen für einen Neuling wie mich. Ich würde es +2 geben, wenn ich könnte.

6 Stimmen

@sujal Ganz genau. Das Rails-Kernteam ist berüchtigt für die miserable Verwaltung von JavaScript. Ignoriere ruhig ihre Vorschläge und nutze einfach die guten Teile des Asset-Pipelines. :)

1 Stimmen

Vielen Dank für diesen Ratschlag. Ich habe mehrere "top-level" JS-Dateien, je nach Modul meiner App. Funktioniert gut.

41voto

ClosureCowboy Punkte 20059

Another option: um seiten- oder modellspezifische Dateien zu erstellen, könnten Sie Verzeichnisse innerhalb Ihres assets/javascripts/ Ordners erstellen.

assets/javascripts/global/
assets/javascripts/cupcakes
assets/javascripts/something_else_specific

Ihre Hauptdatei application.js Manifest könnte so konfiguriert werden, dass es seine Dateien von global/ lädt. Spezifische Seiten oder Gruppen von Seiten könnten ihre eigenen Manifestdateien haben, die Dateien aus ihren eigenen spezifischen Verzeichnissen laden. Sprockets wird automatisch die durch application.js geladenen Dateien mit Ihren seiten-spezifischen Dateien kombinieren, was diese Lösung ermöglicht.

Diese Technik kann auch für style_sheets/ verwendet werden.

13 Stimmen

Du hast mich jetzt nach Cupcakes verlangen lassen.. Verdammt!

0 Stimmen

Ich mag diese Lösung wirklich. Das einzige Problem, das ich damit habe, ist, dass diese zusätzlichen Manifeste nicht komprimiert/verdichtet sind. Sie sind jedoch ordnungsgemäß kompiliert. Gibt es eine Lösung oder fehlt mir etwas?

1 Stimmen

Bedeutet dies, dass der Browser eine JS-Datei lädt, die eine Kombination aus globaler Datei und dateispezifischer Datei ist?

23voto

Fire Emblem Punkte 5961

Ich schätze alle Antworten... und ich glaube nicht, dass sie wirklich das Problem lösen. Einige von ihnen handeln von Styling und scheinen nicht relevant zu sein... und andere erwähnen einfach javascript_include_tag... das natürlich existiert (offensichtlich...) aber es scheint, dass der Weg mit Rails 3.1 darin besteht, all Ihren Javascript-Code in eine Datei zu packen, anstatt einzelne Javascript-Dateien am Ende jeder Seite zu laden.

Die beste Lösung, die ich finden kann, besteht darin, bestimmte Funktionen in div-Tags mit ids oder classes zu umhüllen. Im Javascript-Code überprüfen Sie dann einfach, ob das id oder class auf der Seite vorhanden ist, und wenn ja, wird der zugehörige Javascript-Code ausgeführt. Auf diese Weise wird der Javascript-Code nicht ausgeführt, wenn das dynamische Element nicht auf der Seite vorhanden ist - obwohl er in der massiven application.js-Datei enthalten ist, die von Sprockets verpackt wurde.

Meine oben genannte Lösung hat den Vorteil, dass eine Suchbox auf 8 von 100 Seiten enthalten ist, wird sie nur auf diesen 8 Seiten ausgeführt. Außerdem müssen Sie den gleichen Code nicht auf 8 Seiten der Website einschließen. Tatsächlich müssen Sie nie wieder manuelle Skript-Tags auf Ihrer Website irgendwo anders einfügen - außer vielleicht zum Vorladen von Daten.

Ich glaube, das ist die eigentliche Antwort auf meine Frage.

0 Stimmen

Aber du willst tatsächlich diese manuellen </code> Tags haben. Ja, Klassen und IDs sind Teil der Antwort, aber es ergibt keinen Sinn für den Benutzer, JavaScript zu laden, das von dieser speziellen Seite nicht benötigt wird.</x-turndown>

4 Stimmen

@ MarnenLaibow-Koser Der Grund, warum keine manuellen Skript-Tags zu jeder eindeutigen Seite hinzugefügt werden, ist, dass der Skriptinhalt bei jedem Seitenaufruf heruntergeladen werden muss. Wenn Sie in der Lage sind, alle JavaScript-Dateien in application.js mithilfe des Asset-Pipelines zu bündeln, lädt der Benutzer diese Skripte nur einmal herunter und ruft application.js bei allen nachfolgenden Seitenaufrufen aus dem Cache ab.

0 Stimmen

@jakeonrails "Der Grund dafür, dass auf jeder eindeutigen Seite keine manuellen Skripttags hinzugefügt werden, ist, dass Sie diesen Skriptinhalt bei jedem Seitenaufruf herunterladen müssen" - ziemlich falsch. Das Skript wird einmal heruntergeladen und wird dann bei weiteren Anfragen aus dem Browsercache abgerufen. "Wenn Sie in der Lage sind, alle JavaScript-Dateien in application.js mit dem Asset-Pipeline zu bündeln, dann lädt der Benutzer diese Skripte nur einmal herunter" - das stimmt, aber auf Kosten von viel unnötigem Code. Wenn Sie Ihren JS in viele kleine Dateien anstatt in eine große strukturieren können, erhalten Sie Caching-Vorteile ohne unnötigen Code.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X