wake-up-neo.com

Der beste Weg, um jQuery / JavaScript-Code zu organisieren (2013)

Das Problem

Diese Antwort wurde bereits beantwortet, ist jedoch alt und nicht aktuell. Ich habe über 2000 Codezeilen in einer einzigen Datei, und wie wir alle wissen, ist dies eine schlechte Praxis, insbesondere, wenn ich mich mit Code befasse oder neue Funktionen hinzufüge. Ich möchte meinen Code jetzt und für die Zukunft besser organisieren.

Ich sollte erwähnen, dass ich ein Tool (keine einfache Website) mit vielen Schaltflächen, UI-Elementen, Drag & Drop, Aktionslistenern/-handlern und Funktionen im globalen Bereich erstelle, in dem möglicherweise mehrere Listener dieselbe Funktion verwenden.

Beispielcode

$('#button1').on('click', function(e){
    // Determined action.
    update_html();
});

... // Around 75 more of this

function update_html(){ .... }

...

Mehr Beispielcode

Fazit

Ich muss diesen Code wirklich so organisieren, dass er optimal genutzt wird, und mich nicht wiederholen. Außerdem muss ich in der Lage sein, neue Funktionen hinzuzufügen und alte zu aktualisieren. Ich werde alleine daran arbeiten. Einige Selektoren können 100 Codezeilen sein, andere sind 1. Ich habe mir require.js und fand es ein bisschen repetitiv und tatsächlich mehr Code als nötig zu schreiben. Ich bin offen für jede mögliche Lösung, die diese Kriterien erfüllt, und der Link zu Ressourcen/Beispielen ist immer von Vorteil.

Vielen Dank.

101
Kivylius

Ich werde ein paar einfache Dinge durchgehen, die Ihnen vielleicht helfen oder auch nicht. Einige könnten offensichtlich sein, andere könnten extrem arkan sein.

Schritt 1: Unterteilen Sie Ihren Code

Das Aufteilen Ihres Codes in mehrere modulare Einheiten ist ein sehr guter erster Schritt. Fassen Sie zusammen, was "zusammen" funktioniert, und legen Sie sie in ihre eigene kleine ummantelte Einheit. Mach dir vorerst keine Sorgen um das Format, lass es inline. Die Struktur ist ein späterer Punkt.

Angenommen, Sie haben eine Seite wie diese:

enter image description here

Es wäre sinnvoll, die Abschnitte so zu unterteilen, dass alle Header-bezogenen Event-Handler/Binder vorhanden sind, um die Wartung zu vereinfachen (und nicht 1000 Zeilen durchsuchen zu müssen).

Sie können dann ein Tool wie Grunt verwenden, um Ihr JS wieder zu einer einzelnen Einheit zusammenzusetzen.

Schritt 1a: Abhängigkeitsmanagement

Verwenden Sie eine Bibliothek wie RequireJS oder CommonJS, um etwas zu implementieren, das AMD heißt. Durch das asynchrone Laden von Modulen können Sie explizit angeben, wovon Ihr Code abhängt. Auf diese Weise können Sie den Bibliotheksaufruf in den Code verlagern. Sie können einfach wörtlich "Dies benötigt jQuery" sagen und der AMD lädt es und führt Ihren Code aus wenn jQuery verfügbar ist.

Dies hat auch ein verstecktes Juwel: Das Laden der Bibliothek erfolgt in der Sekunde, in der das DOM fertig ist, nicht zuvor. Dies hält das Laden Ihrer Seite nicht länger an!

Schritt 2: Modularisieren

Sehen Sie das Drahtmodell? Ich habe zwei Anzeigenblöcke. Sie werden höchstwahrscheinlich gemeinsame Ereignis-Listener haben.

Ihre Aufgabe in diesem Schritt ist es, die Wiederholungspunkte in Ihrem Code zu identifizieren und zu versuchen, all dies in Module zu synthetisieren. Module werden im Moment alles umfassen. Wir werden die Dinge aufteilen, während wir weitergehen.

Die ganze Idee dieses Schritts ist, von Schritt 1 fortzufahren und alle Copy-Pastas zu löschen, um sie durch lose gekoppelte Einheiten zu ersetzen. Anstatt also:

ad_unit1.js

 $("#au1").click(function() { ... });

ad_unit2.js

 $("#au2").click(function() { ... });

Ich werde haben:

ad_unit.js:

 var AdUnit = function(elem) {
     this.element = elem || new jQuery();
 }
 AdUnit.prototype.bindEvents = function() {
     ... Events go here
 }

page.js:

 var AUs = new AdUnit($("#au1,#au2"));
 AUs.bindEvents();

Dies ermöglicht es Ihnen, zwischen Ihrem Ereignisse und Ihrem Markup zu trennen und Wiederholungen zu vermeiden. Dies ist ein ziemlich anständiger Schritt, den wir später noch weiter ausbauen werden.

Schritt 3: Wählen Sie ein Framework!

Wenn Sie Wiederholungen noch weiter modularisieren und reduzieren möchten, gibt es eine Reihe großartiger Frameworks, die MVC-Ansätze (Model-View-Controller) implementieren. Mein Favorit ist Backbone/Spine, aber es gibt auch Angular, Yii, ... Die Liste geht weiter.

Ein Modell repräsentiert Ihre Daten.

A Ansicht steht für Ihr Markup und alle damit verbundenen Ereignisse

Ein Controller repräsentiert Ihre Geschäftslogik. Mit anderen Worten, der Controller teilt der Seite mit, welche Ansichten geladen und welche Modelle verwendet werden sollen.

Dies wird ein bedeutender Lernschritt sein, aber der Preis ist es wert: Er bevorzugt sauberen, modularen Code gegenüber Spaghetti.

Es gibt viele andere Dinge, die Sie tun können, das sind nur Richtlinien und Ideen.

Code-spezifische Änderungen

Hier sind einige spezifische Verbesserungen an Ihrem Code:

 $('.new_layer').click(function(){

    dialog("Create new layer","Enter your layer name","_input", {

            'OK' : function(){

                    var reply = $('.dialog_input').val();

                    if( reply != null && reply != "" ){

                            var name = "ln_"+reply.split(' ').join('_');
                            var parent = "";

                            if(selected_folder != "" ){
                            parent = selected_folder+" .content";
                            }

                            $R.find(".layer").clone()
                            .addClass(name).html(reply)
                            .appendTo("#layer_groups "+parent);

                            $R.find(".layers_group").clone()
                            .addClass(name).appendTo('#canvas '+selected_folder);

            }

        }

    });
 });

Dies ist besser geschrieben als:

$("body").on("click",".new_layer", function() {
    dialog("Create new layer", "Enter your layer name", "_input", {
         OK: function() {
             // There must be a way to get the input from here using this, if it is a standard library. If you wrote your own, make the value retrievable using something other than a class selector (horrible performance + scoping +multiple instance issues)

             // This is where the view comes into play. Instead of cloning, bind the rendering into a JS prototype, and instantiate it. It means that you only have to modify stuff in one place, you don't risk cloning events with it, and you can test your Layer stand-alone
             var newLayer = new Layer();
             newLayer
               .setName(name)
               .bindToGroup(parent);
          }
     });
});

Früher in Ihrem Code:

window.Layer = function() {
    this.instance = $("<div>");
    // Markup generated here
};
window.Layer.prototype = {
   setName: function(newName) {
   },
   bindToGroup: function(parentNode) {
   }
}

Plötzlich haben Sie die Möglichkeit, eine Standardebene von einer beliebigen Stelle in Ihrem Code aus zu erstellen, ohne sie kopieren zu müssen. Du machst das an fünf verschiedenen Orten. Ich habe dir gerade fünf Kopierpasten gespart.

Einer noch:

// Regelsatz-Wrapper für Aktionen

var PageElements = function(ruleSet) {
ruleSet = ruleSet || [];
this.rules = [];
for (var i = 0; i < ruleSet.length; i++) {
    if (ruleSet[i].target && ruleSet[i].action) {
        this.rules.Push(ruleSet[i]);
    }
}
}
PageElements.prototype.run = function(elem) {
for (var i = 0; i < this.rules.length; i++) {
    this.rules[i].action.apply(elem.find(this.rules.target));
}
}

var GlobalRules = new PageElements([
{
    "target": ".draggable",
    "action": function() { this.draggable({
        cancel: "div#scrolling, .content",
        containment: "document"
        });
    }
},
{
    "target" :".resizable",
    "action": function() {
        this.resizable({
            handles: "all",
            zIndex: 0,
            containment: "document"
        });
    }
}

]);

GlobalRules.run($("body"));

// If you need to add elements later on, you can just call GlobalRules.run(yourNewElement);

Dies ist eine sehr wirksame Methode, um Regeln zu registrieren, wenn Sie Ereignisse haben, die keine Standardereignisse oder Erstellungsereignisse sind. In Kombination mit einem Pub-/Sub-Benachrichtigungssystem und wenn Sie jedes Mal, wenn Sie Elemente erstellen, an ein Ereignis gebunden sind, das Sie auslösen, wird dies ebenfalls zu einem echten Kick-Ass. Modulare Eventbindung für Fire'n'forget!

93

Hier ist eine einfache Möglichkeit, Ihre aktuelle Codebasis mithilfe von require.js in mehrere Dateien aufzuteilen. Ich werde Ihnen zeigen, wie Sie Ihren Code in zwei Dateien aufteilen. Danach können Sie problemlos weitere Dateien hinzufügen.

Schritt 1) ​​ Erstellen Sie oben in Ihrem Code ein App-Objekt (oder einen beliebigen Namen wie MyGame):

var App = {}

Schritt 2) Konvertieren Sie alle Variablen und Funktionen auf oberster Ebene in das App-Objekt.

Anstatt:

var selected_layer = "";

Sie wollen:

App.selected_layer = "";

Anstatt:

function getModified(){
...
}

Sie wollen:

App.getModified = function() {

}

Beachten Sie, dass Ihr Code zu diesem Zeitpunkt erst dann funktioniert , wenn Sie den nächsten Schritt abgeschlossen haben.

Schritt 3) Konvertieren Sie alle globalen Variablen- und Funktionsreferenzen, um die App zu durchlaufen.

Ändere Dinge wie:

selected_layer = "."+classes[1];

zu:

App.selected_layer = "."+classes[1];

und:

getModified()

zu:

App.GetModified()

Schritt 4) Testen Sie Ihren Code zu diesem Zeitpunkt - es sollte alles funktionieren. Sie werden wahrscheinlich zuerst ein paar Fehler bekommen, weil Sie etwas verpasst haben. Beheben Sie diese, bevor Sie fortfahren.

Schritt 5) Richten Sie die Anforderungen ein. Ich gehe davon aus, dass Sie eine Webseite haben, die von einem Webserver bereitgestellt wird und deren Code sich in Folgendem befindet:

www/page.html

und jquery in

www/js/jquery.js

Wenn diese Pfade nicht genau wie folgt lauten, funktioniert das Folgende nicht und Sie müssen die Pfade ändern.

Lade requirejs herunter und füge require.js in dein www/js Verzeichnis.

in deinem page.html, lösche alle Script-Tags und füge ein Script-Tag wie folgt ein:

<script data-main="js/main" src="js/require.js"></script>

erstellen www/js/main.js mit Inhalt:

require.config({
 "shim": {
   'jquery': { exports: '$' }
 }
})

require(['jquery', 'app']);

geben Sie dann den gesamten Code ein, den Sie gerade in den Schritten 1-3 festgelegt haben (dessen einzige globale Variable App sein sollte):

www/js/app.js

Schreiben Sie ganz oben in diese Datei:

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

Unten setzen:

})

Laden Sie dann page.html in Ihren Browser. Deine App sollte funktionieren!

Schritt 6) Erstellen Sie eine weitere Datei

Hier zahlt sich Ihre Arbeit aus, Sie können dies immer und immer wieder tun.

Ziehe einen Code aus www/js/app.js, das auf $ und App verweist.

z.B.

$('a').click(function() { App.foo() }

Gib es in www/js/foo.js

Schreiben Sie ganz oben in diese Datei:

require(['jquery', 'app'], function($, App) {

Unten setzen:

})

Ändern Sie dann die letzte Zeile von www/js/main.js in:

require(['jquery', 'app', 'foo']);

Das ist es! Tun Sie dies jedes Mal, wenn Sie Code in eine eigene Datei einfügen möchten!

13
Lyn Headley

Für Ihre Fragen und Kommentare gehe ich davon aus, dass Sie nicht bereit sind, Ihren Code auf ein Framework wie Backbone zu portieren oder eine Loader-Bibliothek wie Require zu verwenden. Sie möchten nur einen besseren Weg finden, um den Code, den Sie bereits haben, auf einfachste Weise zu organisieren.

Ich verstehe, es ist ärgerlich, durch mehr als 2000 Codezeilen zu scrollen, um den Abschnitt zu finden, an dem Sie arbeiten möchten. Die Lösung besteht darin, Ihren Code in verschiedene Dateien aufzuteilen, eine für jede Funktion. Beispielsweise sidebar.js, canvas.js etc. Dann kannst du sie für die Produktion mit Grunt zusammenfügen, zusammen mit Usemin kannst du so etwas haben:

In deinem HTML:

<!-- build:js scripts/app.js -->
<script src="scripts/sidebar.js"></script>
<script src="scripts/canvas.js"></script>
<!-- endbuild -->

In deinem Gruntfile:

useminPrepare: {
  html: 'app/index.html',
  options: {
    dest: 'dist'
  }
},
usemin: {
  html: ['dist/{,*/}*.html'],
  css: ['dist/styles/{,*/}*.css'],
  options: {
    dirs: ['dist']
  }
}

Wenn Sie Yeoman verwenden möchten, erhalten Sie dafür einen Kesselcode.

Dann müssen Sie für jede Datei selbst sicherstellen, dass Sie die Best Practices befolgen und dass sich alle Codes und Variablen in dieser Datei befinden und nicht von anderen Dateien abhängig sind. Dies bedeutet nicht, dass Sie die Funktionen einer Datei nicht von einer anderen Datei aus aufrufen können. Es geht darum, Variablen und Funktionen zu kapseln. Ähnlich wie bei Namespacing. Ich gehe davon aus, dass Sie nicht Ihren gesamten Code objektorientiert portieren möchten, aber wenn es Ihnen nichts ausmacht, ein wenig umzugestalten, würde ich empfehlen, etwas Äquivalentes zum sogenannten Modulmuster hinzuzufügen. Es sieht ungefähr so ​​aus:

sidebar.js

var Sidebar = (function(){
// functions and vars here are private
var init = function(){
  $("#sidebar #sortable").sortable({
            forceHelperSize: true,
            forcePlaceholderSize: true,
            revert: true,
            revert: 150,
            placeholder: "highlight panel",
            axis: "y",
            tolerance: "pointer",
            cancel: ".content"
       }).disableSelection();
  } 
  return {
   // here your can put your "public" functions
   init : init
  }
})();

Dann können Sie dieses Codebit wie folgt laden:

$(document).ready(function(){
   Sidebar.init();
   ...

Dies ermöglicht es Ihnen, einen viel besser wartbaren Code zu haben, ohne Ihren Code zu sehr umschreiben zu müssen.

10
Jesús Carrera

Verwenden Sie JavaScript MVC Framework, um den JavaScript-Code auf standardmäßige Weise zu organisieren.

Die besten verfügbaren JavaScript-MVC-Frameworks sind:

Bei der Auswahl eines JavaScript-MVC-Frameworks mussten so viele Faktoren berücksichtigt werden. Lesen Sie den folgenden Vergleichsartikel, der Ihnen bei der Auswahl des besten Frameworks anhand der für Ihr Projekt wichtigen Faktoren hilft: http://sporto.github.io/blog/2013/04/12/comparison-angular-backbone- can-ember /

Sie können auch RequireJS mit dem Framework verwenden, um das Laden von Asynchrounous-Js-Dateien und -Modulen zu unterstützen.
Sehen Sie sich das Folgende an, um mit dem Laden des JS-Moduls zu beginnen:
http://www.sitepoint.com/understanding-requirejs-for-effective-javascript-module-loading/

6
Rohit Tailor

Kategorisieren Sie Ihren Code. Diese Methode hilft mir sehr und funktioniert mit jedem js-Framework:

(function(){//HEADER: menu
    //your code for your header
})();
(function(){//HEADER: location bar
    //your code for your location
})();
(function(){//FOOTER
    //your code for your footer
})();
(function(){//PANEL: interactive links. e.g:
    var crr = null;
    $('::section.panel a').addEvent('click', function(E){
        if ( crr) {
            crr.hide();
        }
        crr = this.show();
    });
})();

In Ihrem bevorzugten Editor (der beste ist Komodo Edit) können Sie alle Einträge ausblenden, um nur die Titel anzuzeigen:

(function(){//HEADER: menu_____________________________________
(function(){//HEADER: location bar_____________________________
(function(){//FOOTER___________________________________________
(function(){//PANEL: interactive links. e.g:___________________
4
user2377782

Ich würde vorschlagen:

  1. publisher-/Abonnentenmuster für die Ereignisverwaltung.
  2. objektorientierung
  3. namensraum

Teilen Sie in Ihrem Fall Jessica die Benutzeroberfläche in Seiten oder Bildschirme auf. Seiten oder Bildschirme können Objekte sein und von einigen übergeordneten Klassen erweitert werden. Verwalten Sie die Interaktionen zwischen Seiten mit einer PageManager-Klasse.

3
Fazle Rabbi

Ich schlage vor, dass Sie so etwas wie Backbone verwenden. Backbone ist eine von RESTFUL unterstützte Javascript-Bibliothek. Ik macht Ihren Code sauberer und lesbarer und ist in Verbindung mit requirejs leistungsstark.

http://backbonejs.org/

http://requirejs.org/

Backbone ist keine echte Bibliothek. Es soll Ihrem Javascript-Code Struktur geben. Es ist in der Lage, andere Bibliotheken wie jquery, jquery-ui, google-maps usw. einzubeziehen. Backbone ist meiner Meinung nach der JavaScript-Ansatz, der objektorientierten und Model View Controller-Strukturen am nächsten kommt.

Auch in Bezug auf Ihren Workflow. Wenn Sie Ihre Anwendungen in PHP erstellen, verwenden Sie die Laravel Bibliothek. Sie funktioniert einwandfrei mit Backbone, wenn Sie mit dem RESTfull-Prinzip arbeiten. Unter dem Link zu Laravel Framework und einem Tutorial zum Erstellen von RESTfull-APIs:

http://maxoffsky.com/code-blog/building-restful-api-in-laravel-start-here/

http://laravel.com/

Unten ist ein Tutorial von Nettuts. Nettuts hat viele hochwertige Tutorials:

http://net.tutsplus.com/tutorials/javascript-ajax/understanding-backbone-js-and-the-server/

2
Chris Visser

Vielleicht ist es an der Zeit, mit Tools wie yeoman http://yeoman.io/ einen kompletten Entwicklungsworkflow zu implementieren. Auf diese Weise können Sie alle Abhängigkeiten, den Erstellungsprozess und, falls gewünscht, das automatisierte Testen steuern. Es ist zunächst viel Arbeit, aber sobald es implementiert ist, werden zukünftige Änderungen viel einfacher.

0
drobson