[英]How to structure Javascript programs in complex web applications?
我有一個問題,不容易描述。 我正在編寫一個 Web 應用程序,它充分利用了 jQuery 和 AJAX 調用。 現在我在 Javascript 架構方面沒有很多經驗,但我意識到我的程序沒有一個好的結構。 我想我有太多的標識符指代相同的(至少或多或少)事物。
讓我們看一下構成應用程序一小部分的任意示例 UI 小部件:小部件可能是窗口的一部分,窗口可能是窗口管理器的一部分:
現在我有四個不同的對象標識符用於同一件事,需要保持同步,直到重新加載頁面。 這似乎不是一件好事。
編輯2:
我認為舉個例子會很有幫助,盡管是人為的。 下面您會看到一個記錄器小部件,可用於將塊元素添加到顯示已記錄項目的網頁。
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 元素並且需要對函數makeLogger返回的公共 API 執行某些操作時(例如在事件處理程序中),我會卡住。 這就是混亂開始的地方。 我需要將所有本機對象保存在存儲庫或其他東西中,以便我可以再次檢索。 擁有從托管對象返回到我的本機對象的連接(例如對象屬性)會更好。 我知道它可以做到,但它有一些缺點:
現在,我使用 jQuery 的 data() 方法進行反向引用。 但總而言之,我不喜歡我必須跟蹤托管對象與其本機對應對象之間關系的方式。
您可以使用全局注冊表:
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 緩存對象供以后使用。 但是您可以使用.data()
擴展上述建議的WidgetRegistry
:
var $widget = $('#myWidget');
var widgetID = 'foo';
$widget.data('widget', widgetID);
通過這種方式,您可以存儲附加到每個 jQuery 對象的小部件 ID,並從全局注冊表重新訪問它。
測試,如果一個 jQuery 對象有一個現有的小部件:
return $('#test').data('widget') &&
($('#test').data('widget') in window.WidgetRegistry);
請注意,這些只是建議。 實際上,有很多方法可以實現這樣的整合。 如果您想將您的代碼與 jQuery 更深入地結合,您可以擴展 jQuery object ,以便您可以編寫如下內容:
$('#widget').widget({'foo':'bar'});
// and/or
var allWidgets = $('*:widget');
// ...
對於需要同步的四個對象,您可以擁有一個對象並在構造函數中傳遞引用,或作為函數參數傳遞。
我解決這個問題的方法是永遠不會丟失對包裝器對象的引用。 每當需要一個 DOM 對象時(例如插入到頁面中),這個包裝器對象就會提供它。 但是將該小部件粘貼到屏幕上,包裝器對象設置特定於小部件的所有事件處理和 AJAX 處理代碼,因此在這些事件處理程序和 AJAX 回調中始終維護包裝器的引用。
我已經使用 MooTools 在 jsfiddle 上創建了一個簡單的示例,這可能對您有意義。
我不確定我是否完全理解你的問題,但我會嘗試指出一些想法。
在我看來,您應該創建基本小部件類,其中包含小部件的通用功能。
讓我們以 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);
}
您能做或不能做的很多事情取決於您對 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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.