Я перегляну кілька простих речей, які можуть допомогти вам, а можуть і не допомогти. Деякі можуть бути очевидними, деякі - надзвичайно задушливими.
Крок 1: Продемонструйте свій код
Розділення коду на кілька модульних одиниць - це дуже хороший перший крок. Закруглете те, що працює «разом», і покладіть їх у свій маленький укладений блок. не хвилюйтесь про формат поки що, тримайте його в Inline. Структура є пізнішим моментом.
Отже, припустимо, у вас є така сторінка:
Було б сенс розділити так, щоб усі обробники подій, що стосуються заголовка, були там, для зручності обслуговування (і не потрібно просіювати 1000 рядків).
Потім ви можете використовувати такий інструмент, як Grunt, щоб відновити свій JS назад до одного блоку.
Крок 1а: управління залежністю
Використовуйте бібліотеку, таку як RequireJS або CommonJS, щоб реалізувати щось, що називається AMD . Асинхронна завантаження модуля дозволяє чітко заявити, від чого залежить ваш код, що дозволяє потім вивантажувати бібліотеку-виклик до коду. Ви можете просто дослівно сказати "Для цього потрібен jQuery", і AMD завантажить його та виконає ваш код, коли jQuery буде доступний .
У цьому також є прихований дорогоцінний камінь: завантаження бібліотеки буде здійснено вдруге, коли DOM буде готовий, а не раніше. Це більше не зупиняє завантаження вашої сторінки!
Крок 2: модуляція
Бачите каркас? У мене є два рекламні блоки. Вони, швидше за все, мають спільних слухачів подій.
Ваше завдання на цьому кроці - визначити точки повторення у вашому коді та спробувати синтезувати все це у модулі . Модулі прямо зараз охоплюватимуть усе. Ми розділимо речі, поки будемо йти.
Вся ідея цього кроку полягає в тому, щоб перейти з кроку 1 і видалити всі пасти для копіювання, замінити їх на одиниці, які нещільно пов'язані. Отже, замість того, щоб:
ad_unit1.js
$("#au1").click(function() { ... });
ad_unit2.js
$("#au2").click(function() { ... });
Я буду мати:
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();
Що дозволяє розділити між своїми подіями та розміткою, а також позбутися від повторення. Це досить гідний крок, і ми продовжимо це далі.
Крок 3: Виберіть рамку!
Якщо ви хочете ще більше модулювати та зменшувати повтори, навколо вас існує купа дивовижних рамок, що реалізують підходи MVC (Model - View - Controller). Моя улюблена - хребет / хребет, однак, є також Angular, Yii, ... Список продовжується.
Модель представляє дані.
View представляє свою націнку і всі події , пов'язані з ним
Контролер являє бізнес - логіку - іншими словами, контролер повідомляє сторінку , які уявлення для навантаження і які моделі використання.
Це буде суттєвим кроком у навчанні, але приз вартий цього: він надає перевагу чистому модульному коду над спагетті.
Ви можете зробити багато інших речей, це лише вказівки та ідеї.
Зміни, що стосуються коду
Ось деякі конкретні вдосконалення вашого коду:
$('.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);
}
}
});
});
Це краще записується як:
$("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);
}
});
});
Раніше у вашому коді:
window.Layer = function() {
this.instance = $("<div>");
// Markup generated here
};
window.Layer.prototype = {
setName: function(newName) {
},
bindToGroup: function(parentNode) {
}
}
Раптом у вас є спосіб створити стандартний шар з будь-якої точки коду, не вставляючи копію. Ви робите це в п'яти різних місцях. Щойно я врятував вам п'ять копій-паст.
Ще один:
// Рулетка обгортка для дій
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);
Це дуже потужний спосіб реєстрації правил, якщо у вас є події, які не є стандартними, або події створення. Це також є серйозним ударом у поєднанні із системою сповіщень про паб / підкоманду та у зв’язку із подією, яку ви запускаєте під час створення елементів. Забудьте про модульну прив'язку подій!