Voy a repasar algunas cosas simples que pueden ayudarlo o no. Algunos pueden ser obvios, algunos pueden ser extremadamente arcanos.
Paso 1: Compartimente su código
Separar su código en múltiples unidades modulares es un muy buen primer paso. Reúna lo que funciona "en conjunto" y colóquelo en su propia unidad pequeña. no se preocupe por el formato por ahora, manténgalo en línea. La estructura es un punto posterior.
Entonces, suponga que tiene una página como esta:
Tendría sentido compartimentar de modo que todos los controladores / carpetas de eventos relacionados con el encabezado estén allí, para facilitar el mantenimiento (y no tener que examinar 1000 líneas).
Luego puede usar una herramienta como Grunt para reconstruir su JS en una sola unidad.
Paso 1a: gestión de la dependencia
Utilice una biblioteca como RequireJS o CommonJS para implementar algo llamado AMD . La carga asincrónica del módulo le permite indicar explícitamente de qué depende su código, lo que luego le permite descargar la llamada de biblioteca al código. Puedes decir literalmente "Esto necesita jQuery" y AMD lo cargará y ejecutará tu código cuando jQuery esté disponible .
Esto también tiene una joya oculta: la carga de la biblioteca se realizará en el momento en que el DOM esté listo, no antes. ¡Esto ya no detiene la carga de su página!
Paso 2: modularizar
¿Ves la estructura alámbrica? Tengo dos bloques de anuncios. Lo más probable es que tengan oyentes de eventos compartidos.
Su tarea en este paso es identificar los puntos de repetición en su código e intentar sintetizar todo esto en módulos . Los módulos, ahora mismo, abarcarán todo. Dividiremos las cosas a medida que avanzamos.
La idea general de este paso es ir desde el paso 1 y eliminar todas las pastas de copia, para reemplazarlas con unidades que estén poco acopladas. Entonces, en lugar de tener:
ad_unit1.js
$("#au1").click(function() { ... });
ad_unit2.js
$("#au2").click(function() { ... });
Tendré:
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();
Lo que le permite compartimentar entre sus eventos y su marcado, además de deshacerse de la repetición. Este es un paso bastante decente y lo ampliaremos más adelante.
Paso 3: ¡Elija un marco!
Si desea modularizar y reducir las repeticiones aún más, hay un montón de marcos impresionantes que implementan enfoques MVC (Modelo - Vista - Controlador). Mi favorito es Backbone / Spine, sin embargo, también hay Angular, Yii, ... La lista continúa.
Un modelo representa sus datos.
Una vista representa su marca y todos los eventos asociados a ella
Un controlador representa la lógica de su negocio; en otras palabras, el controlador le dice a la página qué vistas cargar y qué modelos usar.
Este será un paso de aprendizaje significativo, pero el premio lo vale: favorece el código modular y limpio sobre los espaguetis.
Hay muchas otras cosas que puede hacer, esas son solo pautas e ideas.
Cambios específicos del código
A continuación, se muestran algunas mejoras específicas para su código:
$('.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);
}
}
});
});
Esto se escribe mejor como:
$("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);
}
});
});
Anteriormente en su código:
window.Layer = function() {
this.instance = $("<div>");
// Markup generated here
};
window.Layer.prototype = {
setName: function(newName) {
},
bindToGroup: function(parentNode) {
}
}
De repente, tiene una forma de crear una capa estándar desde cualquier lugar de su código sin copiar y pegar. Estás haciendo esto en cinco lugares diferentes. Le acabo de guardar cinco copias y pegadas.
Uno mas:
// Contenedor de conjunto de reglas para acciones
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);
Esta es una forma muy potente de registrar reglas si tiene eventos que no son estándar o eventos de creación. Esto también es realmente sorprendente cuando se combina con un sistema de notificación de publicación / suscripción y cuando está vinculado a un evento, dispara cada vez que crea elementos. ¡Fire'n'forget enlace de eventos modular!