Component,中文稱爲組件,或者構件。使用很是比較普遍,它的核心意義在於複用,相對模塊,對於依賴性有更高的要求。
Module, 中文爲模塊或模組。它的核心意義是分離職責,屬於代碼級模塊化的產出。它自己是提供服務的功能邏輯,是一組具備必定內聚性代碼的組合,職責明確。
組件(Component)和模塊(Module)又是一對容易混淆的名詞,也經常被用來相互替換。我的總結,從設計上來看,組件強調複用,模塊強調職責(內聚、分離),或者說組件是達到可複用要求的模塊(記得有次面試的時候,面試官都搞錯了這兩個概念!)。
前端Web應用中的組件,是指一些設計爲通用性的,用來構建較大型應用程序的軟件,這些組件有多種表現形式。它能夠是有UI(用戶界面)的,也能夠是做爲 「服務」的純邏輯代碼。由於有視覺上的表現形式,UI組件更容易理解。UI組件簡單的例子包括按鈕、輸入框和文本域。不管是漢堡包狀的菜單按鈕(不管你是否喜歡)、標籤頁、日曆、選項菜單或者所見即所得的富文本編輯器則是一些更加高級的例子。提供服務類型的組件可能會讓人難以理解,這種類型的例子包括跨瀏覽器的AJAX支持,日誌記錄或者提供某種數據持久化的功能。
基於組件開發,最重要的就是組件能夠用來構成其餘組件,而富文本編輯器就是個很好的例子。它是由按鈕、下拉菜單和一些可視化組件等組成。另外一個例子是HTML5上的video元素。它一樣包含按鈕,也同時含有一個能從視頻數據流渲染內容的元素。html
咱們將相關的一些功能組織在一塊兒,把一切封裝起來,而在組件的例子中,就多是相關的功能邏輯和靜態資源:JavaScript、HTML、CSS以及圖像等。這就是咱們所說的內聚。這種作法將讓組件更容易維護,而且這麼作以後,組件的可靠性也將提升。同時,它也能讓組件的功能明確,增大組件重用的可能性。前端
你看到的示例組件,尤爲是Web Component,更關心可重用的問題。功能明確,實現清晰,API易於理解。天然就能促進組件複用。經過構建可重用組件,咱們不只保持了 DRY(不要重複造輪子)原則,還獲得了相應的好處。
這裏要提醒: 不要過度嘗試構建可重用組件。你更應該關注應用程序上所須要的那些特定部分。若是以後相應需求出現,或者組件的確到了可重用的地步,就花一點額外時間讓組件重用。事實上,開發者都喜歡去創造可重用功能塊(庫、組件、模塊、插件等),作得太早將會讓你後來痛苦不堪。因此,吸收基於組件開發的其餘好處,而且接受不是全部組件都能重用的事實。面試
一個功能明確好組件的API能讓人輕易地更改其內部的功能實現。要是程序內部的組件是鬆耦合的,那事實上能夠用一個組件輕易地替換另外一個組件,只要遵循相同的 API/接口/約定。ajax
基於組件的架構讓組件組合成新組件更加容易。這樣的設計讓組件更加專一,也讓其餘組件中構建和暴露的功能更好利用。不管是給程序添加功能,仍是用來製做完整的程序,更加複雜的功能也能如法炮製。這就是這種方法的主要好處。算法
如上圖,簡單解讀一下:編程
其中第二項描述的就近維護原則,是我以爲最具工程價值的地方,它爲前端開發提供了很好的分治策略,每一個開發者都將清楚的知道,本身所開發維護的功能單元,其代碼必然存在於對應的組件目錄中,在那個目錄下能找到有關這個功能單元的全部內部邏輯,樣式也好,JS也好,頁面結構也好,都在那裏。
基於這樣的工程理念,咱們很容易將系統以獨立的組件爲單元進行分工劃分:bootstrap
因爲系統功能被分治到獨立的組件中,粒度比較精細,組織形式鬆散,開發者之間不會產生開發時序的依賴,大幅提高並行的開發效率,也更容易支持多個團隊共同維護一個大型站點的開發。數組
整個前端項目能夠劃分爲這麼幾種開發概念:
- JS模塊:獨立的算法和數據單元,瀏覽器環境檢測(detect),網絡請求(ajax),應用配置(config),DOM操做(dom),工具函數(utils),以及組件裏的JS單元;
- CSS模塊:獨立的功能性樣式單元,柵格系統(grid),字體圖標(icon-fonts),動畫樣式(animate),以及組件裏的CSS單元;
- UI組件:獨立的可視/可交互功能單元 ,頁頭(header),頁尾(footer),導航欄(nav),搜索框(search);
- 頁面:前端這種GUI軟件的界面狀態,是UI組件的容器 首頁(index),列表頁(list),用戶管理(user);
- 應用:整個項目或整個站點被稱之爲應用,由多個頁面組成。瀏覽器
基於這些理念,前端開發就成了這個樣子:緩存
綜合上面的描述,對於通常中小規模的項目,大體能夠規劃出這樣的源碼目錄結構:
所謂組件化,核心意義莫過於提取真正有複用價值的東西。那怎樣的東西有複用價值呢?
公共樣式的複用性也是比較容易承認的,所以也會有bootstrap,foundation,semantic這些東西的流行,不過它們也不是純粹的樣式庫了,也帶有一些小的邏輯封裝。業務邏輯這一塊的複用是存在不少爭議的,一方面,不少人不認同業務邏輯也須要組件化,另外一方面,這塊東西究竟怎樣去組件化,也很須要思考。除了這些以外,還有大量的業務界面,這塊東西很顯然複用價值很低,基本不存在複用性,但仍然有不少方案中把它們「組件化」了,使得它們成爲了「不具備複用性的組件」。
組件化的本質目的並不必定是要爲了可複用,而是提高可維護性。
對於一個有必定規模的Web應用來講,把全部東西都「組件化」,在管理上會有較大的便利性。我舉個例子,一樣是編寫代碼,短代碼明顯比長代碼的可讀性更高,因此不少語言裏會建議「一個方法通常不要超過多少行,一個類最好不要超過多少行」之類。
這個時候咱們再看HTML的部分,若是不考慮模板等技術的使用,某些界面光佈局代碼寫起來就很是多了,像一些表單,都須要一層套一層,不少簡單的表單元素都須要套個三層左右,更沒必要說一些有複雜佈局的東西了。尤爲是整個系統單頁化以後,界面的header,footer,各類nav或者aside,極可能都有必定複雜性。若是這些東西的代碼不做切分,那麼主界面的HTML必定比較難看。
從這個角度看,這些拆出去的東西都像組件,但若是從複用性的角度看,極可能多數東西,每一塊都只有一個地方用,壓根沒有複用度。這個拆出去,純粹是爲了使得整個工程易於管理,易於維護。
這時候咱們再來關注不一樣框架/庫對UI層組件化的處理方式,發現有兩個類型,模板和函數。
模板是一種很常見的東西,它用HTML字符串的方式表達界面的原始結構,而後經過代入數據的方式生成真正的界面,有的是生成目標HTML,有的還生成各類事件的自動綁定。前者是靜態模板,後者是動態模板。
另外有一些框架/庫偏心用函數邏輯來生成界面,早期的ExtJS,如今的React(它內部仍是可能使用模板,並且對外提供的是組件建立接口的進一步封裝——jsx)等,這種實現技術的優點是不一樣平臺上編程體驗一致,甚至能夠給每種平臺封裝相同的組件,調用方輕鬆寫一份代碼,在Web和不一樣Native平臺上可用。但這種方式也有比較麻煩的地方,那就是界面調整比較繁瑣。
有這麼一個簡單場景:一個僱員列表界面包括兩個部分,僱員表格和用於填寫僱員信息的表單。在這個場景下,存在哪些組件?
對於這個問題,主要存在兩種傾向,一種是僅僅把「控件」和比較有通用性的東西封裝成組件,另一種是整個應用都組件化。對前一種方式來講,這裏面只存在數據表格這麼一個組件。 對後一種方式來講,這裏面有可能存在:數據表格,僱員表單,甚至還包括僱員列表界面這麼一個更大的組件。這兩種方式,就是咱們以前所說的「局部組件化」,「全組件化」。
咱們前面提到,全組件化在管理上是存在優點的,它能夠把不一樣層面的東西都搞成相似結構,好比剛纔的這個業務場景,極可能最後寫起來是這個樣子:
<Employee-Panel>
<Employee-List></Employee-List>
<Employee-Form></Employee-Form>
</Employee-Panel>
全標籤化的問題主要有這些:
第一,語義化代價太大。只要用了標籤,就必定須要給它合適的語義,也就是命名。但實際用的時候,極可能只是爲了把一堆html簡化一下而已,到底簡化出來的那東西應當叫什麼名字,光是起名也費不知多少腦細胞。第二,配置過於複雜。有不少東西其實不太適合封裝,不但封裝的代價大,使用的代價也會很大。有時候會發現,調用代碼的絕大部分都是在寫各類配置。
這個問題討論完了,咱們來看看另一個問題:若是UI組件有業務邏輯,應該如何處理。
好比說,性別選擇的下拉框,它是一個很是通用化的功能,照理說是很適合被當作組件來提供的。可是究竟如何封裝它,咱們就有些犯難了。這個組件裏除了界面,還有數據,這些數據應當內置在組件裏嗎?理論上從組件的封裝性來講,是都應當在裏面的,因而就這麼造了一個組件:
<GenderSelect></GenderSelect>
性別的數據很天然地是放在組件的實現內部,一個寫死的數組中。這個太簡單了,咱們改一下,改爲商品銷售的國家下拉框。但咱們有個要求,本公司商品銷售的國家的信息是統一配置的,也就是說,這個數據來源於服務端。這時候,你是否是想把一個http請求封裝到這組件裏?
這樣作也不是不能夠,但存在至少兩個問題:
若是這類組件在同一個界面中出現屢次,就可能存在請求的浪費,由於有一個組件實例就會產生一個請求。 若是國家信息的配置界面與這個組件同時存在,當咱們在配置界面中新增一個國家了,下拉框組件中的數據並不會實時刷新。 第一個問題只是資源的浪費,第二個就是數據的不一致了。曾經在不少系統中,你們都是手動刷新當前頁面來解決這問題的,但到了這個時代,人們都是追求體驗的,在一個全組件化的解決方案中,不該再出現此類問題。
如何解決這樣的問題呢?那就是引入一層Store的概念,每一個組件不直接去到服務端請求數據,而是到對應的前端數據緩存中去獲取數據,讓這個緩存本身去跟服務端保持同步。因此,在實際作方案的過程當中,無論是基於Angular,React,Polymer,最後確定都作出一層Store了,否則會有不少問題。