Как структурировать программы JavaScript в сложных веб-приложениях?

У меня есть проблема, которая легко не описана. Я пишу веб-приложение, которое делает сильное использование вызовов Ajax и jQuery. Теперь у меня нет большого опыта в JavaScript archicture, но я понимаю, что моя программа не имеет хорошей структуры. Я думаю, что у меня есть слишком много идентификаторов, относящихся к тому же (по крайней мере, более или менее) вещь.

Давайте иметь взгляд на произвольный образцовый виджет UI, который составляет крошечную часть приложения: виджет может быть частью окна, и окно может быть частью менеджера окон:

  1. eventhandlers используют элементы DOM в качестве параметров. Элемент DOM представляет виджет в браузере.
  2. Много времен я использую объекты jQuery (В основном обертки вокруг элементов DOM), чтобы сделать что-то с виджетом. Иногда они используются кратковременно, иногда они хранятся в переменной в более поздних целях.
  3. Вызовы функции Ajax используют идентификаторы строки для этих виджетов. Они - обработанная сторона сервера.
  4. Около этого у меня есть класс виджета, экземпляры которого представляют виджет. Это инстанцируют через новый оператор.

Теперь у меня есть так или иначе четыре различных идентификаторов объектов для того же самого, которое должно быть сохранено в синхронизации, пока страница не загружается снова. Это, кажется, не хорошая вещь.

Совет?



Править:
@Will Morgan: это - конструктор форм, который позволяет создавать веб-формы в браузере. Бэкендом является Zope, сервер веб-приложения Python. Трудно стать более явным, поскольку это - общая проблема, я наблюдаю все время при выполнении Javasscript-разработки с трио jQuery, дерево DOM и мои собственные смоделированные экземпляры класса.

EDIT2:
Я думаю, что это было бы полезный для создания примера, хотя искусственный. Ниже Вас видят виджет регистратора, который может использоваться для добавления элемента блока к веб-странице, в которой отображены зарегистрированные объекты.

makeLogger = function(){
     var rootEl = document.createElement('div');
     rootEl.innerHTML = 'Logged items:';
     rootEl.setAttribute('class', 'logger');

     var append = function(msg){
           // append msg as a child of root element.
           var msgEl = document.createElement('div');
           msgEl.innerHTML = msg;
           rootEl.appendChild(msgEl);
     };

     return {
          getRootEl: function() {return rootEl;},
          log      : function(msg) {append(msg);}
     };
};

// Usage 
var logger = makeLogger();
var foo = document.getElementById('foo');
foo.appendChild(logger.getRootEl());
logger.log('What\'s up?');

В этой точке у меня есть обертка вокруг HTMLDivElement (размещенный объект). С наличием экземпляра регистратора (собственный объект) под рукой я могу легко работать с ним через функцию logger.getRootEl ().
То, где я застреваю, - когда я только имею элемент DOM под рукой и должен сделать что-то с общедоступным API, возвращенным функцией makeLogger (например, в обработчиках событий). И это - то, где путаница запускается. Я должен держать все собственные объекты в репозитории или чем-то так, чтобы я мог получить снова. Было бы настолько более хорошо иметь соединение (например, свойство объекта) от размещенного объекта назад к моему собственному объекту. Я знаю, что это может быть сделано, но это имеет некоторые недостатки:

  • Подобные (круговые) ссылки являются потенциально памятью, просачивающейся до IE7
  • Когда передать размещенный объект и когда передать собственный объект (в функциях)?

На данный момент я делаю заднюю ссылку с данными jQuery () метод. Но в целом мне не нравится способ, которым я должен отслеживать отношение между размещенным объектом и его собственным дубликатом.

Как Вы обрабатываете этот сценарий?



EDIT3:
После некоторого понимания я получил от примера Anurag..
@Anurag: Если я понял Ваше право в качестве примера, критическая точка состоит в том, чтобы настроить корректное (что корректно, зависит от Ваших потребностей, хотя), контекст выполнения для обработчиков событий. И это находится в Вашем случае экземпляр объекта представления, который сделан с Mootool, связывают () функцию. Таким образом, Вы удостоверяетесь, что ВСЕГДА имеете дело с интерфейсным объектом (я назвал его собственным объектом) вместо Объекта DOM, правильно?

Примечание для читателя: Вы не вынуждены использовать Mootools для достижения этого. В jQuery Вы установили бы свои обработчики событий с $ .proxy () функция, или если бы Вы используете простой JavaScript, Вы использовали бы применять свойство, которое выставляет каждая функция.

27
задан 28 revs 17 March 2010 в 19:08
поделиться

4 ответа

Для четырех объектов, которые необходимо синхронизировать, вы можете иметь один объект и передавать ссылку в конструкторе или в качестве аргументов функции.

Я решаю эту проблему, чтобы никогда не терять ссылку на объект-оболочку. Всякий раз, когда требуется объект DOM (например, для вставки на страницу), этот объект-оболочка предоставляет его. Но прикрепляя этот виджет к экрану, объект-оболочка настраивает всю обработку событий и код обработки AJAX, специфичный для виджета, поэтому ссылка на оболочку всегда сохраняется в этих обработчиках событий и обратных вызовах AJAX.

Я создал простой пример на jsfiddle с помощью MooTools, который может иметь для вас смысл.

2
ответ дан 28 November 2019 в 05:56
поделиться

Вы можете использовать глобальный реестр:

window.WidgetRegistry = {};
window.WidgetRegistry['foowidget'] = new Widget('#myID');

и когда вызовы AJAX вернутся, они могут получить виджет следующим образом:

var widgetID = data.widgetID;
if (widgetID in window.WidgetRegistry) {
    var widget = window.WidgetRegistry[widgetID];
}

Для ваших вызовов jQuery: Я предполагаю, что они относительно недорогие, поскольку jQuery кэширует объекты для последующего использования. Но вы можете расширить предложенный выше WidgetRegistry , используя .data () :

var $widget = $('#myWidget');
var widgetID = 'foo';
$widget.data('widget', widgetID);

Таким образом, вы можете сохранить идентификатор виджета, прикрепленный к каждому объекту jQuery, и повторно получить к нему доступ. из глобального реестра.

Тестирование, если объект jQuery имеет существующий виджет:

return $('#test').data('widget') &&
       ($('#test').data('widget') in window.WidgetRegistry);

Обратите внимание, что это всего лишь предложения. На самом деле, есть десятки способов добиться такой консолидации. Если вы хотите глубже объединить свой код с jQuery, вы можете расширить объект jQuery , чтобы можно было написать что-то вроде:

$('#widget').widget({'foo':'bar'});
// and/or
var allWidgets = $('*:widget');
// ...
5
ответ дан 28 November 2019 в 05:56
поделиться

Я не уверен, что полностью понял ваш вопрос, но попробую навести на некоторые мысли.

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

Возьмем для примера AppName.Widgets.base(). Одной из переменных экземпляра является _events - объект, который хранит события как ключи и функции как значения. Таким образом, каждый класс определяет события для этого виджета, и вы можете легко связать их в конструкторе. Что касается строковых идентификаторов, самый простой способ - использовать toString().

Пример:

namespace('AppName.Widgets'); // you can find implementations easy

AppName.Widgets.base = function() {
    if (!this._type) return;

    this._dom = $('div.widget.'+this._type);
    for (var e in this._events) {
        this._dom.bind(e, this._events[e]);
    }

    this.toString = function() { return this._type; };
}

AppName.Widgets.example = function() { // extends AppName.Widgets.base
    this._type   = 'example';
    this._events = { 'click' : function(e) { alert('click'); }  };

    AppName.Widgets.base.call(this);
}
1
ответ дан 28 November 2019 в 05:56
поделиться

Многое из того, что вы можете или не можете делать, будет зависеть от того, насколько вы контролируете JavaScript. Лично мне часто приходится использовать библиотеки, созданные другими, поэтому я могу получить для работы только узел DOM, но вместо этого мне действительно нужен мой объект. В этих случаях я считаю, что использование функции данных в jQuery очень удобно. Используя функцию данных, вы можете «сохранить» свой объект внутри узла DOM, чтобы получить его позже.

В приведенном выше примере вы можете использовать функцию данных, чтобы вернуть свой виджет после того, как у вас есть функции, которые используют только узел DOM.

makeLogger = function(){
     var rootEl = document.createElement('div');
     rootEl.innerHTML = 'Logged items:';
     rootEl.setAttribute('class', 'logger');

     var append = function(msg){
           // append msg as a child of root element.
           var msgEl = document.createElement('div');
           msgEl.innerHTML = msg;
           rootEl.appendChild(msgEl);
     };

     var self = {
          getRootEl: function() {return rootEl;},
          log      : function(msg) {append(msg);}
     };

    // Save a copy to the domNode
    $(rootEl).data("logger", self);
    return self;
};

// Example of only getting the dom node
function whatsUp (domNode){
   // Get the logger from the domNode
   $(domNode).data('logger').log('What\'s up?');
}

// Usage
var logger = makeLogger();
var loggerNode = logger.getRootEl();
var foo = document.getElementById('foo');
foo.appendChild(loggerNode);
whatsUp(loggerNode);
0
ответ дан 28 November 2019 в 05:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: