2011-01-20 107 views
7

我注意到JavaScript中的一個常見模式,我一直在編寫,並且想知道是否已經有一個模式定義類似於最佳實踐的模式?從本質上講,它是如何獲得一個DOM元素並將其包裝/關聯到一個JavaScript對象。以此示例爲例,您需要在Web應用程序中使用過濾器。您的網頁看起來是這樣的:包裝JavaScript對象中的DOM元素

<html> 
<head></head> 
<body> 
    <div id="filter"></div> 
</body> 
</html> 

你會然後包像這樣的元素:

var myFilter = new Filter({ 
    elem: document.getElementById('filter'), 
    prop: 'stacks-test', 
    someCallback: function() { 
     // specify a callback 
    } 
}); 

和JavaScript(這裏spec是傳遞給構造一個對象):

var Filter = function(spec) { 
    this.elem = spec.elem; 
    this.prop = spec.prop; 
    this.callback = spec.someCallback; 
    this.bindEvents(); 
}; 

Filter.prototype.bindEvents = function() { 
    var self = this; 
    $(this.elem).click(function(e) { 
     self.updateFeed(); 
    }; 
}; 

Filter.prototype.updateFeed = function() { 
    this.prop; // 'stacks-test' 
    this.callback(); 
    // ... 
    // code to interact with other JavaScript objects 
    // who in turn, update the document 
}; 

這種方法稱爲什麼,最佳實踐和注意事項是什麼?

+0

我不想聽起來像一個沒心沒肺的jQuery粉絲,但它看起來像你最好使用jQuery或類似的框架。雖然它的主要目的是幫助你選擇和操作DOM,但是整個庫建立在你正在討論的DOM包裝模式的基礎上,所以它的插件功能和其他輔助函數自然而然地使你很容易做到這一點好。 – 2011-01-20 06:21:57

+0

我仍然需要使用構造函數,因爲在一個文檔中會有多個過濾器。你能告訴我一個使用jQuery和Filter對象的例子嗎? – 2011-01-20 06:39:12

+0

我會盡快發佈答案。另外,下次請記住在您的評論中包含@ Box9,以便我收到通知。我只是偶然發現了這個問題。 – 2011-01-20 07:19:01

回答

2

你可能會對Dojo的小部件庫Dijit感興趣 - 如果我正確理解你的問題,它基本上可以做你正在問的東西,還有更多。在Dijit中,一個小部件實際上封裝了一個DOM節點,它的內容,任何定義其行爲的JavaScript,以及(單獨導入)CSS來設計其外觀。小部件有自己的生命週期,註冊表和事件(包括許多簡單地映射到小部件內的節點上的DOM事件,例如myWidget.onClick可以有效地調用myWidget.domNode.onclick)。

小工具可以(但不必)在獨立的HTML模板文件中定義其初始內容,通過該文件還可以將模板內節點上的事件綁定到小部件方法,以及在小部件引用模板中的特定節點。

我幾乎沒有在這裏抓表面。如果您想了解更多關於這一點,你可以用這些參考頁開始:

所有說,我不知道你最終瞄準什麼,也許這對你的目的有點(考慮我把你的整個其他庫),但認爲它可能激起你的興趣至少。

1

繼續我對這個問題的評論,jQuery是一個潛在的工具工具,因爲它已經爲您的工作提供了一些基礎。然而,儘管如此,它確實引入了自己的複雜性,並且並不是所有的「jQuery方法」都是平等的。我會提出一種使用jQuery作爲「對象模型」的方法,但它可能會或可能不適合您的需要。


首先要做的事情。 jQuery的哲學是,你首先選擇元素,使用$()或等效地jQuery()來啓動所有的事情。所有的操作都是從這個開始的。與創建一個包裝元素並保持對該包裝器的引用的對象相比,這是一種稍微不同的思維方式,但本質上這就是jQuery爲您做的。對$('#some-id')的調用抓取id爲「some-id」的元素並將其包裝在一個jQuery對象中。


方式一:寫 「過濾器」 插件。

將您的構造函數替換爲initFilter() jQuery方法。你可以通過修改jQuery原型並使用jQuery對象作爲包裝來實現。 jQuery的原型是由jQuery.fn引用的,所以:

jQuery.fn.initFilter = function (prop, callback) { 
    // Save prop and callback 
    this.data('filter-prop', prop); 
    this.data('filter-callback', callback); 

    // Bind events (makes sense to do this during init) 
    this.click(function() { 
     $(this).updateFeed(); 
    }); 
}; 

然後做類似的事情updateFeed()

jQuery.fn.updateFeed = function() { 
    this.data('filter-prop'); 
    this.data('filter-callback')(); 
}); 

而且使用這樣的:

$('#filter').initFilter(prop, callback); 

注意updateFeed可以簡單地插入到點擊處理程序中以防止對jQuery名稱空間造成不必要的污染。然而,像這樣使用jQuery的一個優點是,如果以後需要調用某個函數,則不需要保留該對象的引用,因爲jQuery將所有引用綁定到實際元素。如果你想打電話updateFeed編程,那麼:

$('#filter').updateFeed(); 

然後將正確的對象上調用。


有些事情要考慮

當然有缺點這種方法。一個是所有屬性,我們已經使用.data()針對元素保存的所有屬性在所有jQuery函數之間共享,這些函數作用於該元素。我試圖通過在屬性名稱前添加「filter-」來減輕這一點,但取決於對象的複雜性,這可能不合適。另外,這種確切的方法可能不適合需要大量操作的對象(即具有許多函數的對象),因爲所有這些函數對所有jQuery對象都是通用的。有許多方法可以封裝我不會在這裏介紹的所有內容,但jQuery-ui使用它們的小部件來完成此操作,而且我正在嘗試在我創建的庫中另一個替代方案。

但是,拉回來一點,我首先建議使用jQuery的唯一原因是您的Filter對象似乎與DOM密切相關。它將事件綁定到DOM,它基於用戶交互來修改DOM,基本上它似乎生活在DOM中,所以使用基於DOM的東西,即jQuery。