Vou repassar algumas coisas simples que podem, ou não, ajudá-lo. Alguns podem ser óbvios, alguns podem ser extremamente misteriosos.
Etapa 1: compartimentar seu código
Separar seu código em várias unidades modulares é um primeiro passo muito bom. Reúna o que funciona "junto" e coloque-os em sua própria pequena unidade encerrada. não se preocupe com o formato por enquanto, mantenha-o embutido. A estrutura é um ponto posterior.
Então, suponha que você tenha uma página como esta:
Faria sentido compartimentar para que todos os manipuladores / fichários de eventos relacionados ao cabeçalho estivessem lá, para facilitar a manutenção (e não ter que peneirar 1000 linhas).
Você pode então usar uma ferramenta como o Grunt para reconstruir seu JS em uma única unidade.
Etapa 1a: gerenciamento de dependências
Use uma biblioteca como RequireJS ou CommonJS para implementar algo chamado AMD . O carregamento de módulo assíncrono permite declarar explicitamente do que seu código depende, o que permite descarregar a chamada de biblioteca para o código. Você pode apenas dizer literalmente "Isso precisa do jQuery" e o AMD irá carregá-lo e executar seu código quando o jQuery estiver disponível .
Isso também tem uma joia oculta: o carregamento da biblioteca será feito no segundo em que o DOM estiver pronto, não antes. Isso não interrompe mais o carregamento de sua página!
Etapa 2: modularizar
Veja o wireframe? Eu tenho dois blocos de anúncios. Provavelmente, eles terão ouvintes de eventos compartilhados.
Sua tarefa nesta etapa é identificar os pontos de repetição em seu código e tentar sintetizar tudo isso em módulos . Módulos, agora, vão abranger tudo. Vamos dividir as coisas à medida que avançamos.
A idéia geral desta etapa é ir da etapa 1 e excluir todas as massas de cópia, para substituí-las por unidades que estão fracamente acopladas. Então, em vez de ter:
ad_unit1.js
$("#au1").click(function() { ... });
ad_unit2.js
$("#au2").click(function() { ... });
Eu terei:
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();
O que permite a você compartimentar entre seus eventos e sua marcação , além de se livrar da repetição. Este é um passo bastante decente e vamos estendê-lo mais tarde.
Etapa 3: Escolha uma estrutura!
Se você gostaria de modularizar e reduzir as repetições ainda mais, existem vários frameworks incríveis que implementam abordagens MVC (Model - View - Controller). Meu favorito é Backbone / Spine, porém, também tem Angular, Yii, ... A lista é longa.
Um modelo representa seus dados.
Uma visualização representa sua marcação e todos os eventos associados a ela
Um controlador representa sua lógica de negócios - em outras palavras, o controlador informa à página quais visualizações carregar e quais modelos usar.
Essa será uma etapa de aprendizado significativa, mas o prêmio vale a pena: ele favorece um código limpo e modular em vez de espaguete.
Existem muitas outras coisas que você pode fazer; são apenas diretrizes e ideias.
Mudanças específicas do código
Aqui estão algumas melhorias específicas em seu 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);
}
}
});
});
Isso é melhor escrito 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 em seu código:
window.Layer = function() {
this.instance = $("<div>");
// Markup generated here
};
window.Layer.prototype = {
setName: function(newName) {
},
bindToGroup: function(parentNode) {
}
}
De repente, você tem uma maneira de criar uma camada padrão de qualquer lugar em seu código sem copiar e colar. Você está fazendo isso em cinco lugares diferentes. Acabei de salvar cinco cópias-pastas para você.
Mais um:
// Wrapper de conjunto de regras para ações
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 é uma maneira muito potente de registrar regras se você tiver eventos que não sejam padrão ou eventos de criação. Isso também é muito difícil quando combinado com um sistema de notificação pub / sub e quando vinculado a um evento que você dispara sempre que cria elementos. Disparar e esquecer a associação de eventos modulares!