Лучший способ организовать код jQuery/JavaScript (2013) [закрыто]
Проблема
этот ответ был дан раньше, но они старые и не актуальны. У меня есть более 2000 строк кода в одном файле, и, как мы все знаем, это плохая практика, особенно когда я просматриваю код или добавляю новые функции. Я хочу лучше организовать свой код, сейчас и в будущем.
Я должен упомянуть, что я создаю инструмент (а не простой веб-сайт) с большим количеством кнопок, элементов пользовательского интерфейса, перетаскивания, капель, слушателей действий / обработчиков и функций в глобальной области, где несколько слушателей могут использовать одну и ту же функцию.
код$('#button1').on('click', function(e){
// Determined action.
update_html();
});
... // Around 75 more of this
function update_html(){ .... }
...
вывод
мне действительно нужно организовать этот код для лучшего использования, а не повторяться и иметь возможность добавлять новые функции и обновлять старые. Я буду работать над этим сам. Некоторые переключатели могут быть 100 строк кода другие 1. Я посмотрел немного на require.js
и нашел это своего рода повторяющимся, и на самом деле писать больше кода, чем нужно . Я открыт для любого возможного решения, которое соответствует этим критериям, и ссылка на ресурс / примеры всегда является плюсом.
спасибо.
8 ответов:
я расскажу вам несколько простых вещей, которые могут вам помочь, а могут и не помочь. Некоторые из них могут быть очевидными, некоторые могут быть чрезвычайно тайными.
Шаг 1: Разделите свой код
разделение кода на несколько модульных блоков является очень хорошим первым шагом. Соберите то, что работает "вместе" и поместите их в свой собственный маленький упакованный блок. не беспокойтесь о формате на данный момент, держите его встроенным. Структура-это более поздняя точка.
Итак, предположим у вас есть страница, как это:
было бы разумно разделить так, чтобы все связанные с заголовком обработчики событий/связыватели были там, для простоты обслуживания (и не нужно просеивать через 1000 строк).
затем вы можете использовать такой инструмент, как Grunt, чтобы восстановить JS обратно в один блок.
шаг 1a: управление зависимостями
используйте библиотеку, такую как 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). Мой любимый позвоночник/позвоночник, однако, есть также угловой, Yii ... Список можно продолжать.
A модель представляет ваши данные.
A View представляет вашу наценку и все события, связанные с ней
A контроллер представляет вашу бизнес-логику-другими словами, контроллер сообщает странице, какие представления загружать и какие модели использовать.
это будет значительный шаг обучения, но приз стоит того: он предпочитает чистый, модульный код над спагетти.
есть много других вещей, которые вы можете сделать, это просто принципы и идеи.
кодовые изменения
вот некоторые конкретные улучшения для вашего код:
$('.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);
это очень мощный способ регистрации правил, если у вас есть события это не стандартные или события создания. Это также серьезно удар по заднице в сочетании с системой уведомлений pub/sub и при привязке к событию, которое вы запускаете всякий раз, когда создаете элементы. Fire'n'forget модульная привязка событий!
вот простой способ разделить текущую кодовую базу на несколько файлов, используя require.js. Я покажу вам, как разделить ваш код на два файла. После этого добавление дополнительных файлов будет простым.
Шаг 1) в верхней части кода создайте объект приложения (или любое другое имя, например MyGame):
var App = {}
Шаг 2) конвертировать все ваши переменные и функции верхнего уровня, чтобы принадлежать к приложению объект.
вместо:
var selected_layer = "";
вы хотите:
App.selected_layer = "";
вместо:
function getModified(){ ... }
вы хотите:
App.getModified = function() { }
обратите внимание, что в этот момент ваш код не работает пока вы не закончите следующий шаг.
Шаг 3) преобразование всех глобальных переменных и ссылок на функции, чтобы пройти через приложение.
изменить вещи например:
selected_layer = "."+classes[1];
to:
App.selected_layer = "."+classes[1];
и:
getModified()
to:
App.GetModified()
Шаг 4) проверьте свой код на этом этапе-все должно работать. Вы, вероятно, получите несколько ошибок сначала, потому что вы что-то пропустили, так что исправить их, прежде чем двигаться дальше.
Шаг 5) настройка requirejs. Я предполагаю, что у вас есть веб-страница, обслуживаемая с веб-сервера, чей код находится в:
www/page.html
и jquery в
www/js/jquery.js
если эти пути не ровно как это ниже, не будет работать и вам придется изменять пути.
скачать requirejs и поставить требуют.js в вашем
для вашего вопроса и комментариев я предполагаю, что вы не хотите переносить свой код в фреймворк, такой как Backbone, или использовать библиотеку загрузчика, такую как Require. Вы просто хотите лучше организовать код, который у вас уже есть, самым простым способом.
Я понимаю, что это раздражает, чтобы прокрутить 2000+ строк кода, чтобы найти раздел, в котором вы хотите работать. Решение разделить ваш код в разных файлах, по одному для каждой функции. Например
sidebar.js
,canvas.js
etc. Затем вы можете объединить их вместе для производства с помощью Grunt, вместе с Usemin вы можете иметь что-то вроде этого:в вашем html:
<!-- build:js scripts/app.js --> <script src="scripts/sidebar.js"></script> <script src="scripts/canvas.js"></script> <!-- endbuild -->
в Gruntfile:
useminPrepare: { html: 'app/index.html', options: { dest: 'dist' } }, usemin: { html: ['dist/{,*/}*.html'], css: ['dist/styles/{,*/}*.css'], options: { dirs: ['dist'] } }
если вы хотите использовать Yeoman это даст вам шаблонный код для всего этого.
затем для каждого файла вам нужно убедиться, что вы следуете рекомендациям и что все коды и переменные находятся в этом файле и не зависят от других файлов. Этот это не значит, что вы не можете вызывать функции одного файла из другого, дело в том, чтобы иметь переменные и функции инкапсулированы. Что-то похожее на пространство имен. Я предполагаю, что вы не хотите переносить весь свой код на объектно-ориентированный, но если вы не против немного рефакторинга, я бы рекомендовал добавить что-то эквивалентное тому, что называется шаблоном модуля. Это выглядит примерно так:
боковая панель.js
var Sidebar = (function(){ // functions and vars here are private var init = function(){ $("#sidebar #sortable").sortable({ forceHelperSize: true, forcePlaceholderSize: true, revert: true, revert: 150, placeholder: "highlight panel", axis: "y", tolerance: "pointer", cancel: ".content" }).disableSelection(); } return { // here your can put your "public" functions init : init } })();
затем вы можете загрузить этот кусок кода как это:
$(document).ready(function(){ Sidebar.init(); ...
это позволит вам иметь гораздо больше кода без необходимости переписывать слишком много кода.
используйте JavaScript MVC Framework для того, чтобы организовать код javascript стандартным способом.
лучшие JavaScript MVC фреймворки доступны:
выбор JavaScript MVC framework требует так много факторов для рассмотрения. Прочитать следующее сравнительная статья, которая поможет вам выбрать лучший фреймворк на основе факторов, важных для вашего проекта: http://sporto.github.io/blog/2013/04/12/comparison-angular-backbone-can-ember/
вы также можете использовать RequireJS с фреймворком для поддержки загрузки Asynchrounous JS file & module.
Посмотрите ниже, чтобы начать работу с модулем JS loading:
http://www.sitepoint.com/understanding-requirejs-for-effective-javascript-module-loading/
классифицировать код. Этот метод помогает мне много и работает с любой JS framework:
(function(){//HEADER: menu //your code for your header })(); (function(){//HEADER: location bar //your code for your location })(); (function(){//FOOTER //your code for your footer })(); (function(){//PANEL: interactive links. e.g: var crr = null; $('::section.panel a').addEvent('click', function(E){ if ( crr) { crr.hide(); } crr = this.show(); }); })();
в вашем предпочтительном редакторе (лучший-Komodo Edit) вы можете сложить, свернув все записи, и вы увидите только заголовки:
(function(){//HEADER: menu_____________________________________ (function(){//HEADER: location bar_____________________________ (function(){//FOOTER___________________________________________ (function(){//PANEL: interactive links. e.g:___________________
Я предлагаю:
- шаблон издателя/подписчика для управления событиями.
- ориентация объекта
- пространства имен
в вашем случае Джессика, разделите интерфейс на страницы или экраны. Страницы или экраны могут быть объектами и расширяться из некоторых родительских классов. Управление взаимодействиями между страницами с помощью класса PageManager.
Я предлагаю вам использовать что-то вроде позвоночника. Backbone-это спокойная поддерживаемая библиотека javascript. Ik делает ваш код более чистым и читаемым и является мощным при использовании вместе с requirejs.
Backbone-это не настоящая библиотека. Он предназначен для придания структуры вашему коду javascript. Он может включать в себя другие библиотеки, такие как jquery, jquery-ui, google-maps и т. д. Backbone - это, на мой взгляд, самый близкий подход javascript к объектно-ориентированным и модельным структурам контроллера вида.
также относительно вашего рабочего процесса.. Если вы создаете свои приложения на PHP, используйте библиотеку Laravel. Он будет работать безупречно с позвоночником при использовании с принципом RESTfull. Ниже ссылка на Laravel Framework и учебник о создании RESTfull APIs:
http://maxoffsky.com/code-blog/building-restful-api-in-laravel-start-here/
Ниже приведен учебник от nettuts. Nettuts имеет много высококачественных учебников:
http://net.tutsplus.com/tutorials/javascript-ajax/understanding-backbone-js-and-the-server/
может быть, пришло время для вас начать реализацию целого рабочего процесса разработки с использованием таких инструментов, как yeoman http://yeoman.io/. это поможет контролировать все ваши зависимости, построить процесс и, если вы хотите, автоматизированное тестирование. Его много работы, чтобы начать, но после реализации сделает будущие изменения намного проще.