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/…

16voto

Ryan Punkte 1681

Ich bemerke, dass ich ein wenig spät zu dieser Party komme, aber ich wollte eine Lösung einbringen, die ich in letzter Zeit benutzt habe. Aber zuerst möchte ich erwähnen...

Der Rails 3.1/3.2 Weg (Nein, Sir. Das gefällt mir nicht.)

Siehe: http://guides.rubyonrails.org/asset_pipeline.html#how-to-use-the-asset-pipeline

Ich füge das Folgende der Vollständigkeit halber in diese Antwort ein, und weil es keine unhaltbare Lösung ist... obwohl es mir nicht besonders gefällt.

Der "Rails Weg" ist eine lösungsorientierte Lösung, anstelle einer ansichtsorientierten Lösung, wie vom ursprünglichen Autor dieser Frage gefordert. Es gibt controller-spezifische JS-Dateien, die nach ihren jeweiligen Controllern benannt sind. Alle diese Dateien werden in einem Ordnerbaum platziert, der standardmäßig in keinem der application.js-require-Direktiven enthalten ist.

Um kontrollerspezifischen Code einzuschließen, wird Folgendes zu einer Ansicht hinzugefügt.

<%= javascript_include_tag params[:controller] %>

Ich verabscheue diese Lösung, aber sie ist da und sie ist schnell. Möglicherweise könnten Sie stattdessen diese Dateien beispielsweise "people-index.js" und "people-show.js" nennen und dann etwas wie "#{params[:controller]}-index" verwenden, um eine ansichtsorientierte Lösung zu erhalten. Wieder ein schneller Fix, aber ich fühle mich nicht wohl dabei.

Mein Datenattribut-Weg

Nennt mich verrückt, aber ich möchte ALLEN meinen JS kompiliert und minimiert in application.js haben, wenn ich deploye. Ich möchte nicht daran denken müssen, diese kleinen Straggler-Dateien überall einzufügen.

Ich lade all meinen JS in einer kompakten, bald im Browser zwischengespeicherten, Datei. Wenn ein bestimmter Teil meines application.js auf einer Seite ausgeführt werden muss, lasse ich mir von HTML sagen, nicht von Rails.

Anstatt meinen JS an spezifische Element-IDs zu binden oder meinen HTML mit Marker-Klassen zu übersäen, verwende ich ein benutzerdefiniertes Datenattribut namens data-jstags.

Auf jeder Seite verwende ich - bevorzugte JS-Bibliotheksmethode hier einfügen -, um Code auszuführen, wenn das DOM fertig geladen ist. Dieser Bootstrap-Code führt die folgenden Aktionen aus:

  1. Iteriere über alle Elemente im DOM, die mit data-jstag markiert sind
  2. Für jedes Element, teile den Attributwert nach Leerzeichen auf und erstelle ein Array von Tag-Zeichenfolgen.
  3. Für jede Tag-Zeichenfolge suche in einem Hash nach diesem Tag.
  4. Wenn ein übereinstimmender Schlüssel gefunden wird, führe die zugehörige Funktion aus, wobei das Element als Parameter übergeben wird.

Angenommen, ich habe folgendes irgendwo in meinem application.js definiert:

function my_autosuggest_init(element) {
  /* Füge Events hinzu, um die Eingabe zu überwachen und Vorschläge zu machen... */
}

function my_hint_init(element) {
  /* Füge Events hinzu, um einen Hinweis bei Änderung/Blur anzuzeigen, wenn leer... */
  /* Ja, ich weiß, dass HTML 5 dies nativ mit Attributen machen kann. */
}

var JSTags = {
  'auto-suggest': my_autosuggest_init,
  'hint': my_hint_init
};

Das Bootstrap-Ereignis wendet die Funktionen my_autosuggest_init und my_hint_init auf die Sucheingabe an, wodurch diese zu einer Eingabe wird, die eine Liste von Vorschlägen anzeigt, während der Benutzer tippt, sowie einen Eingabehinweis anzeigt, wenn die Eingabe leer und nicht fokussiert ist.

Sofern kein Element mit data-jstag="auto-suggest" markiert ist, wird der Auto-Suggest-Code nie ausgeführt. Aber er ist immer da, minimiert und schließlich zwischengespeichert in meinem application.js für die Zeiten, in denen ich ihn auf einer Seite benötige.

Wenn Sie zusätzliche Parameter an Ihre markierten JS-Funktionen übergeben müssen, müssen Sie etwas kreativ sein. Fügen Sie entweder Data-Parameterattribute hinzu, überlegen Sie sich eine Art Parameter-Syntax oder verwenden Sie sogar einen hybriden Ansatz.

Auch wenn ich einen komplizierten Ablauf habe, der ansichtsspezifisch erscheint, erstelle ich einfach eine Datei dafür in meinem lib-Ordner, packe sie in application.js und markiere sie mit so etwas wie 'neue-sache-wizard'. Wenn mein Bootstrap dieses Tag erreicht, wird mein schöner, ausgefallener Wizard instanziiert und ausgeführt. Er läuft für die Ansichten dieses Controllers, wenn nötig, ist aber ansonsten nicht an den Controller gebunden. Tatsächlich, wenn ich meinen Wizard richtig programmiere, könnte ich alle Konfigurationsdaten in den Ansichten bereitstellen und meinen Wizard später für jeden anderen Controller wiederverwenden, der ihn benötigt.

Wie auch immer, das ist meine Art, seitenbezogenen JS bereits seit geraumer Zeit zu implementieren, und sie hat mir sowohl für einfache Seitendesigns als auch für komplexere/reichhaltige Anwendungen gut gedient. Hoffentlich ist eine der beiden Lösungen, die ich hier vorgestellt habe, meine Art oder der Rails-Weg, hilfreich für jeden, der diese Frage in Zukunft stößt.

6 Stimmen

Ein kleines Detail: In Ihrer Antwort gibt es die Annahme, dass der Browser den JS-Code nur beim ersten Mal herunterlädt und danach keine Auswirkungen mehr hat. Das stimmt nicht ganz. Der Browser vermeidet zwar den erneuten Download, wenn die JS-Datei korrekt zwischengespeichert ist, aber er kompiliert den Code immer noch bei jedem Seitenaufruf. Sie müssen also Abwägungen treffen. Wenn Sie viele JS-Dateien haben, von denen jedoch nur einige pro Seite verwendet werden, könnten Sie die Ladezeiten der Seiten verbessern, indem Sie den JS-Code aufteilen.

0 Stimmen

Für weitere Informationen zu den praktischen Auswirkungen dieses Kompilierungsschritts, über den ich spreche, siehe die Erklärung von 37 Signals, wie pjax Basecamp Next beeinflusst hat: 37signals.com/svn/posts/…

0 Stimmen

Das ist ein fairer Punkt. Nachdem ich den Artikel gelesen habe und auf Projekte zurückblicke, in denen ich die oben genannte Lösung verwendet habe, erkenne ich, dass ich im Grunde genommen die gleiche "send the changed HTML" Lösung geschrieben habe, über die sie im Artikel sprechen. Das häufige erneute Kompilieren von JS war in meinen Projekten kein Problem, weil ich das gemacht habe. Der Kompilierungsschritt ist etwas, woran ich denken werde, wenn ich an weniger "Desktop-Applikation" orientierten Websites arbeite.

7voto

Mike A Punkte 2442

Dies wurde bereits vor langer Zeit beantwortet und akzeptiert, aber ich habe meine eigene Lösung basierend auf einigen dieser Antworten und meiner Erfahrung mit Rails 3+ entwickelt.

Der Asset-Pipeline ist großartig. Nutze sie.

Zuerst solltest du in deiner application.js-Datei //= require_tree. entfernen.

Dann erstelle in deiner application_controller.rb eine Hilfsmethode:

helper_method :javascript_include_view_js //Oder etwas Ähnliches

def javascript_include_view_js
    if FileTest.exists? "app/assets/javascripts/"+params[:controller]+"/"+params[:action]+".js.erb"
        return ''
    end
end

Füge dann in deiner application.html.erb-Layout-Datei deinen neuen Helfer zu den vorhandenen JavaScript-Include hinzu, vorangestellt mit dem raw-Helfer:

    Deine Anwendung
    <%= stylesheet_link_tag "application", :media => "all" %>
    <%= javascript_include_tag "application" %>
    <%= raw javascript_include_view_js %>

Voilà, jetzt kannst du einfach view-spezifisches JavaScript erstellen, indem du die gleiche Dateistruktur verwendest, die du überall sonst in Rails verwendest. Platziere deine Dateien einfach in app/assets/:namespace/:controller/action.js.erb!

Hoffentlich hilft das jemand anderem!

1 Stimmen

Wird dies nach dem Kompilieren der Assets Probleme verursachen, und während der Laufzeit wird der <%= raw ... %> einen 404-Fehler zurückgeben?

0 Stimmen

Ich denke, dass das Asset-Pipeline nicht optimal ist, da es eine Menge Dateien erstellt, die oft nicht verwendet werden sollten. Deshalb führt für mich die Abhängigkeit von der Asset-Pipeline zu einem ineffizienten System.

1 Stimmen

@DeborahSpeece Wann erstellt die Asset-Pipeline Dateien, die nicht verwendet werden sollten? Verwechselst du die Asset-Pipeline (gut) mit require_tree / (schlecht)?

6voto

mcubik Punkte 135

Sie können diese Zeile in Ihrer Layout-Datei (z.B. application.html.erb) hinzufügen, um automatisch die controller-spezifische JavaScript-Datei zu laden (die, die erstellt wurde, als Sie den Controller generiert haben):

<%= javascript_include_tag params[:controller] %>

Sie könnten auch eine Zeile hinzufügen, um automatisch eine Skriptdatei auf einer pro-Aktion Basis zu laden.

<%= javascript_include_tag params[:controller] + "/" + params[:action] %>

Legen Sie einfach Ihre Seitenskripte in einem Unterverzeichnis mit dem Namen des Controller-Namens ab. In diesen Dateien können Sie andere Skripte mit =require einbeziehen. Es wäre ratsam, einen Helper zu erstellen, um die Datei nur einzuschließen, wenn sie vorhanden ist, um einen 404-Fehler im Browser zu vermeiden.

6voto

Mr Bohr Punkte 125
<%= javascript_include_tag params[:controller] %>

2 Stimmen

Das sieht so aus, als könnte es die Frage beantworten. Könnten Sie bitte mehr zur Antwort hinzufügen, um sie auszuarbeiten?

6voto

peresleguine Punkte 2253

Vielleicht finden Sie das pluggable_js Gem als geeignete Lösung.

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