Esaminerò alcune semplici cose che potrebbero, o meno, aiutarti. Alcuni potrebbero essere ovvi, altri potrebbero essere estremamente arcani.
Passaggio 1: compartimentare il codice
Separare il codice in più unità modulari è un ottimo primo passo. Raccogli ciò che funziona "insieme" e inseriscili nella loro piccola unità racchiusa. non preoccuparti del formato per ora, tienilo in linea. La struttura è un punto successivo.
Quindi, supponi di avere una pagina come questa:
Avrebbe senso suddividere in compartimenti in modo che tutti i gestori / raccoglitori di eventi relativi all'intestazione siano presenti, per facilitare la manutenzione (e non dover setacciare 1000 righe).
Puoi quindi utilizzare uno strumento come Grunt per ricostruire il tuo JS in una singola unità.
Passaggio 1a: gestione delle dipendenze
Usa una libreria come RequireJS o CommonJS per implementare qualcosa chiamato AMD . Il caricamento asincrono del modulo ti consente di dichiarare esplicitamente da cosa dipende il tuo codice, il che ti consente quindi di scaricare la chiamata della libreria nel codice. Puoi letteralmente dire "Questo richiede jQuery" e AMD lo caricherà ed eseguirà il tuo codice quando jQuery sarà disponibile .
Anche questo ha una gemma nascosta: il caricamento della libreria verrà effettuato non appena il DOM sarà pronto, non prima. Questo non interrompe più il caricamento della tua pagina!
Passaggio 2: modulare
Vedi il wireframe? Ho due unità pubblicitarie. Molto probabilmente avranno ascoltatori di eventi condivisi.
Il tuo compito in questo passaggio è identificare i punti di ripetizione nel tuo codice e cercare di sintetizzare tutto questo in moduli . I moduli, in questo momento, comprenderanno tutto. Divideremo le cose man mano che procediamo.
L'idea principale di questo passaggio è di andare dal passaggio 1 ed eliminare tutte le copie-pasta, per sostituirle con unità che sono vagamente accoppiate. Quindi, invece di avere:
ad_unit1.js
$("#au1").click(function() { ... });
ad_unit2.js
$("#au2").click(function() { ... });
Avro:
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();
Ciò ti consente di compartimentalizzare tra i tuoi eventi e il tuo markup oltre a sbarazzarti della ripetizione. Questo è un passaggio abbastanza decente e lo estenderemo ulteriormente in seguito.
Passaggio 3: scegli un framework!
Se desideri modulare e ridurre ulteriormente le ripetizioni, ci sono un sacco di fantastici framework in giro che implementano approcci MVC (Model - View - Controller). Il mio preferito è Backbone / Spine, tuttavia, c'è anche Angular, Yii, ... La lista potrebbe continuare.
Un modello rappresenta i tuoi dati.
Una vista rappresenta il tuo mark-up e tutti gli eventi ad esso associati
Un controller rappresenta la tua logica aziendale, in altre parole, il controller dice alla pagina quali visualizzazioni caricare e quali modelli utilizzare.
Questo sarà un passo di apprendimento significativo, ma il premio ne vale la pena: privilegia il codice pulito e modulare rispetto agli spaghetti.
Ci sono molte altre cose che puoi fare, queste sono solo linee guida e idee.
Modifiche specifiche del codice
Di seguito sono riportati alcuni miglioramenti specifici al codice:
$('.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);
}
}
});
});
Questo è meglio scritto come:
$("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);
}
});
});
All'inizio del codice:
window.Layer = function() {
this.instance = $("<div>");
// Markup generated here
};
window.Layer.prototype = {
setName: function(newName) {
},
bindToGroup: function(parentNode) {
}
}
All'improvviso, hai un modo per creare un livello standard da qualsiasi punto del tuo codice senza copiare e incollare. Lo stai facendo in cinque posti diversi. Ti ho appena salvato cinque copie.
Ancora uno:
// Wrapper della serie di regole per le azioni
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);
Questo è un modo molto potente per registrare le regole se hai eventi che non sono standard o eventi di creazione. Questo è anche seriamente kick-ass se combinato con un sistema di notifica pub / sub e quando è associato a un evento si attiva ogni volta che si creano elementi. Associazione di eventi modulari Fire'n'forget!