Лучший способ организовать код 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 97

8 ответов:

я расскажу вам несколько простых вещей, которые могут вам помочь, а могут и не помочь. Некоторые из них могут быть очевидными, некоторые могут быть чрезвычайно тайными.

Шаг 1: Разделите свой код

разделение кода на несколько модульных блоков является очень хорошим первым шагом. Соберите то, что работает "вместе" и поместите их в свой собственный маленький упакованный блок. не беспокойтесь о формате на данный момент, держите его встроенным. Структура-это более поздняя точка.

Итак, предположим у вас есть страница, как это:

enter image description here

было бы разумно разделить так, чтобы все связанные с заголовком обработчики событий/связыватели были там, для простоты обслуживания (и не нужно просеивать через 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:___________________

Я предлагаю:

  1. шаблон издателя/подписчика для управления событиями.
  2. ориентация объекта
  3. пространства имен

в вашем случае Джессика, разделите интерфейс на страницы или экраны. Страницы или экраны могут быть объектами и расширяться из некоторых родительских классов. Управление взаимодействиями между страницами с помощью класса PageManager.

Я предлагаю вам использовать что-то вроде позвоночника. Backbone-это спокойная поддерживаемая библиотека javascript. Ik делает ваш код более чистым и читаемым и является мощным при использовании вместе с requirejs.

http://backbonejs.org/

http://requirejs.org/

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/

http://laravel.com/

Ниже приведен учебник от nettuts. Nettuts имеет много высококачественных учебников:

http://net.tutsplus.com/tutorials/javascript-ajax/understanding-backbone-js-and-the-server/

может быть, пришло время для вас начать реализацию целого рабочего процесса разработки с использованием таких инструментов, как yeoman http://yeoman.io/. это поможет контролировать все ваши зависимости, построить процесс и, если вы хотите, автоматизированное тестирование. Его много работы, чтобы начать, но после реализации сделает будущие изменения намного проще.