Je vais passer en revue certaines choses simples qui peuvent ou non vous aider. Certains pourraient être évidents, certains pourraient être extrêmement obscurs.
Étape 1: compartimenter votre code
Séparer votre code en plusieurs unités modulaires est une très bonne première étape. Rassemblez ce qui fonctionne «ensemble» et mettez-les dans leur propre petite unité encastrée. ne vous inquiétez pas du format pour le moment, gardez-le en ligne. La structure est un point ultérieur.
Alors, supposons que vous ayez une page comme celle-ci:
Il serait judicieux de compartimenter afin que tous les gestionnaires / classeurs d'événements liés à l'en-tête soient là, pour faciliter la maintenance (et ne pas avoir à passer au crible 1000 lignes).
Vous pouvez ensuite utiliser un outil tel que Grunt pour reconstruire votre JS en une seule unité.
Étape 1a: Gestion des dépendances
Utilisez une bibliothèque telle que RequireJS ou CommonJS pour implémenter quelque chose appelé AMD . Le chargement de module asynchrone vous permet d'indiquer explicitement de quoi dépend votre code, ce qui vous permet ensuite de décharger l'appel de bibliothèque vers le code. Vous pouvez simplement dire littéralement "Cela nécessite jQuery" et AMD le chargera et exécutera votre code lorsque jQuery sera disponible .
Cela a également un petit bijou caché: le chargement de la bibliothèque sera effectué dès que le DOM sera prêt, pas avant. Cela n'interrompt plus le chargement de votre page!
Étape 2: Modulariser
Voir le filaire? J'ai deux blocs d'annonces. Ils auront probablement des auditeurs d'événements partagés.
Votre tâche dans cette étape est d'identifier les points de répétition dans votre code et d'essayer de synthétiser tout cela en modules . Les modules, pour le moment, engloberont tout. Nous allons diviser les choses au fur et à mesure.
L'idée générale de cette étape est de passer à partir de l'étape 1 et de supprimer tous les copiés-pâtes, de les remplacer par des unités faiblement couplées. Donc, au lieu d'avoir:
ad_unit1.js
$("#au1").click(function() { ... });
ad_unit2.js
$("#au2").click(function() { ... });
J'aurai:
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();
Ce qui vous permet de compartimenter entre vos événements et votre balisage en plus de vous débarrasser de la répétition. C'est une étape assez décente et nous l'étendrons plus tard.
Étape 3: Choisissez un cadre!
Si vous souhaitez modulariser et réduire encore plus les répétitions, il existe de nombreux frameworks impressionnants qui implémentent des approches MVC (Model - View - Controller). Mon préféré est Backbone / Spine, cependant, il y a aussi Angular, Yii, ... La liste est longue.
Un modèle représente vos données.
Une vue représente votre balisage et tous les événements qui lui sont associés
Un contrôleur représente votre logique métier - en d'autres termes, le contrôleur indique à la page les vues à charger et les modèles à utiliser.
Ce sera une étape d'apprentissage importante, mais le prix en vaut la peine: il favorise un code propre et modulaire par rapport aux spaghettis.
Il y a beaucoup d'autres choses que vous pouvez faire, ce ne sont que des lignes directrices et des idées.
Modifications spécifiques au code
Voici quelques améliorations spécifiques à votre 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);
}
}
});
});
Ceci est mieux écrit comme:
$("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);
}
});
});
Plus tôt dans votre code:
window.Layer = function() {
this.instance = $("<div>");
// Markup generated here
};
window.Layer.prototype = {
setName: function(newName) {
},
bindToGroup: function(parentNode) {
}
}
Soudainement, vous avez un moyen de créer une couche standard à partir de n'importe où dans votre code sans copier-coller. Vous faites cela à cinq endroits différents. Je viens de vous sauver cinq copies-pâtes.
Un de plus:
// wrapper d'ensemble de règles pour les actions
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);
C'est un moyen très efficace d'enregistrer des règles si vous avez des événements qui ne sont pas standard ou des événements de création. Ceci est également très difficile lorsqu'il est combiné avec un système de notification de pub / sous et lorsqu'il est lié à un événement que vous déclenchez chaque fois que vous créez des éléments. Reliure événementielle modulaire Fire'n'forget!