使用許多獨立組件構建應用程序的想法並不新鮮。Web Component的出現,是從新回顧基於組件的應用程序開發模式的好時機。咱們能夠從這個過程當中受益,瞭解如何使用現有技術完成目標,而且在將來作出本身的前端Web應用。html
軟件開發是一個語義豐富(術語一般不止一個意思)的領域。很顯然,這裏的「組件」是一個很泛的稱呼,因此有必要指明咱們想要表達的,在前端Web應用的語言環境中的意思。前端
前端Web應用中的組件,是指一些設計爲通用性的,用來構建較大型應用程序的軟件,這些組件有多種表現形式。它能夠是有UI(用戶界面)的,也能夠是做爲 「服務」的純邏輯代碼。html5
由於有視覺上的表現形式,UI組件更容易理解。UI組件簡單的例子包括按鈕、輸入框和文本域。不管是漢堡包狀的菜單按鈕(不管你是否喜歡)、標籤頁、日曆、選項菜單或者所見即所得的富文本編輯器則是一些更加高級的例子。react
提供服務類型的組件可能會讓人難以理解,這種類型的例子包括跨瀏覽器的AJAX支持,日誌記錄或者提供某種數據持久化的功能。git
基於組件開發,最重要的就是組件能夠用來構成其餘組件,而富文本編輯器就是個很好的例子。它是由按鈕、下拉菜單和一些可視化組件等組成。另外一個例子是HTML5上的video元素。它一樣包含按鈕,也同時含有一個能從視頻數據流渲染內容的元素。angularjs
既然如今已經明白組件的意思,就看看使用組件的方法構建前端應用的好處。github
你可能據說過 「組件是自然模塊」的說法。好吧,感謝它,咱們又要解釋這裏的術語!web
你可能會以爲「組件」的說法更加適合用來描述UI,而「模塊」更適合描述提供服務的功能邏輯。而對於我來講,模塊和組件意思相近,都提供組織、聚焦和封裝,是與某個功能單位相關的。npm
又是一個軟件工程的高頻詞! 咱們將相關的一些功能組織在一塊兒,把一切封裝起來,而在組件的例子中,就多是相關的功能邏輯和靜態資源:JavaScript、HTML、CSS以及圖像等。這就是咱們所說的內聚。瀏覽器
這種作法將讓組件更容易維護,而且這麼作以後,組件的可靠性也將提升。同時,它也能讓組件的功能明確,增大組件重用的可能性。
你看到的示例組件,尤爲是Web Component,更關心可重用的問題。功能明確,實現清晰,API易於理解。天然就能促進組件複用。經過構建可重用組件,咱們不只保持了 DRY(不要重複造輪子)原則,還獲得了相應的好處。
這裏要提醒: 不要過度嘗試構建可重用組件。你更應該關注應用程序上所須要的那些特定部分。若是以後相應需求出現,或者組件的確到了可重用的地步,就花一點額外時間讓組件重用。事實上,開發者都喜歡去創造可重用功能塊(庫、組件、模塊、插件等),作得太早將會讓你後來痛苦不堪。因此,吸收基於組件開發的其餘好處,而且接受不是全部組件都能重用的事實。
一個功能明確好組件的API能讓人輕易地更改其內部的功能實現。要是程序內部的組件是鬆耦合的,那事實上能夠用一個組件輕易地替換另外一個組件,只要遵循相同的 API/接口/約定。
假如你使用GoInstant提供的實時功能服務組件,那他們這周關閉服務這樣的新聞會影響到你。然而,只要提供了相同的數據同步API,你也能夠自行構建使用一個 FirebaseComponent
組件或者 PubNubComponent
組件。
以前也討論過,基於組件的架構讓組件組合成新組件更加容易。這樣的設計讓組件更加專一,也讓其餘組件中構建和暴露的功能更好利用。
不管是給程序添加功能,仍是用來製做完整的程序,更加複雜的功能也能如法炮製。這就是這種方法的主要好處。
是否有必要把全部的東西轉換成組件,事實上取決於你本身。沒有任何理由讓你的程序由 你本身
的組件組合成你最驚歎的功能
,乃至 最花哨的功能
。而這些組件又反過來構成其餘組件。若是你從這個方法中獲得了好處,就千方百計地去堅持它。然而要注意的是,不要用一樣的方法把事情變得複雜,你並不須要過度關注如何讓組件重用。而是要關注呈現程序的功能。
在 Caplin Systems 構建基於組件的自有應用程序時,我用到了幾條原則和實踐。這些原則由 BladeRunnerJS(BRJS) 開源工具集支撐。它被稱做」BladeRunnerJS」 是由於咱們將程序功能都封裝在稱做 Blades 的東西中。Blade是能夠在某個應用中重用的功能特性,可是不能夠在程序間重用。當功能 真的 變得更加通用的時候,咱們將相應的定義移到庫文件中,供各個程序間使用。特定應用中的組件(blade)和咱們程序間的通用組件可使用,咱們只要找到最好知足需求的任何庫和框架。
那麼,如今什麼庫和框架可以幫助咱們構建組件呢?
在決定構建應用時應使用何種技術時,只須要看看流行的 TodoMVC 網站就能夠看到大量可供選擇的前端庫和框架。你也許會以爲任何一種方案都能用來構建基於組件的應用程序。然而,他們之中的一些方案內置了對組件的支持。其中比較有名的是AngularJS、Ember 和 React。
在深刻示例以前有必要簡單地提到組件間通訊的問題。若是組件之間是「獨立」、「模塊化」的,他們又是如何相互通訊的呢?
最顯而易見的答案就是讓組件間相互引用並經過他們之間的API交互。這樣作的問題就在於,這種作法會讓組件相互依賴。短時間內可能還好,一段時間之後,你在修改程序的時候程序會失控,修改一個組件就會對另外一個組件產生極大的影響。決定移除一個不能帶來預期價值組件可能會讓你的應用程序中止工做,由於它背後會有數個組件依賴於它。
此時,解決方案是提供鬆耦合的,讓組件之間不多或者幾乎不知道彼此的方案。組件並不直接建立其餘組件,在他們須要通訊的時候,他們經過「接口/約定」或者經過 「服務」。咱們在構建BRJS程序時考慮了不少這些方面的東西,而且使用 ServiceRegistry
訪問用於組件間通信的服務或者是Web API這樣的資源。Angular和Ember採用了服務和依賴注入解決這類問題。
爲了展現咱們如何用這些庫和框架構建最基本的組件,咱們創建了一個帶有UI,用於取回和顯示用戶頭像的簡單示例。在可能的狀況下,該組件會有 my-avatar
標籤,會從如下兩個屬性中取得頭像:
service
容許設置一個服務。例如 twitter
或者 facebook
username
用於取回該用戶名相對應的頭像AngularJS 多是如今用於構建程序最流行的前端解決方案了。做爲建立者的Google,從新思考HTML,考慮如何從新發明,知足現在Web開發的須要。
Angular中可使用自定義指令定義組件。以後,你可使用 HTML 標記聲明自定義組件。
查看代碼演示: http://jsbin.com/lacog/2/edit
這個例子展現了使用Angular指令的簡單程度。值scope
定義了從 my-avatar
元素中取得,而且以後用來構建相應的img標籤和渲染成用戶頭像的屬性。
框架與庫的爭論曠日持久,總的來講框架是強制你按某種方式作事情,因此它是邪惡的。很顯然,Angular是個框架,而Ember的做者,Yehuda Katz和Tom Dale也很樂意把Ember看做框架。
Ember 有對它稱做組件的內建支持。Ember Components背後的理念是儘量的向Web Components看齊,當瀏覽器支持容許時,就能夠很方便地遷移到Web Components中。
查看代碼演示: http://jsbin.com/nawuwi/4/edit
上面的例子中使用了 handlebars 作模板,因此元素的定義不是同一種語法。
React 雖然是個新人,可是卻已經有不少的追隨者。它由Facebook開發,而且已經全面用於Instagram的UI和部分Facebook的UI。
使用React構建組件的推薦方式是使用叫作 JSX 的東西來定義它們。這是一種「推薦在React上使用的JavaScript語法轉換」。請不要所以分心。他們已經在文檔中指出,這個想法就是用來幫助你在JavaScript中寫出HTML標記的。
我不是說你並不能夠直接在HTML中添加標籤,而必須使用JSX建立本身的組件。可是,只要你定義了一個組件,你就可使用這個組件創造其餘組件。
查看代碼演示: http://jsbin.com/qigoz/5/edit
所以,組件使用的聲明語法須要相應的HTML元素和對 React.RenderComponent
的調用。
Web Component纔是將來!正如名字所表示的那樣,他們承諾將帶來能夠將功能封裝成組件的瀏覽器原生支持。
我將簡單展現Web Component而且演示咱們如今能夠如何使用它。更加深刻的內容請參考本文末尾的 「外部資源」 一節。
他們提供的功能包括:
咱們在上面關注的是用Angular、Ember和React構建 my-avatar
的例子。可能的狀況下,這樣的方式將以頁面上或者模板上添加的自定義元素表示。Web Component包括經過自定義元素得到的原生支持 – 絕對是Web Component標準的基本組成部分。
定義新元素,包括訪問元素生命週期的部分事件例如什麼時候建立(createdCallback
)、什麼時候添加在DOM樹上(attachedCallback
)、什麼時候從DOM樹上分離(detachedCallback
),什麼時候元素屬性改變(attributeChangedCallback(attrName, oldVal, newVal)
)。
自定義元素的一個重要的部分就是有能力從原有元素擴展,於是獲得原有元素相應的功能。示例中咱們擴展了 <img>元素
。
最終,咱們所寫的代碼中,自定義元素正在而且傾向去作的就是將複雜的東西抽象化,讓用戶關注於單個組件產生的價值,從而用來構建更加豐富的功能。
還記得iframe們嗎?咱們還在使用它們,是由於他們能確保組件和控件的JavaScript和CSS不會影響頁面。 Shadow DOM 也能提供這樣的保護,而且沒有iframe帶來的負擔。正式的說法是:
Shadow DOM的設計是在shadow根下隱藏DOM子樹從而提供封裝機制。它提供了創建和保障DOM樹之間的功能界限,以及給這些樹提供交互的功能,從而在DOM樹上提供了更好的功能封裝。
咱們長時間之前就能夠導入JavaScript和CSS了。 HTML導入功能提供了從其餘HTML文檔中導入和重用HTML文檔的能力。這種簡單性同時意味着能夠很方便地用一些組件構建另外一些組件。
最後,這樣的格式很理想,適合可重用組件,而且能夠用你最喜歡的包管理解決方案發布(例如: bower、 npm 或者 Component)。
咱們中的許多人已經使用像handlebars、mustache或者underscore.js中的模板這樣的解決方案(就像咱們在上面的Ember示例中用的同樣)。Web Component經過 template元素
提供了模板的原生支持。
原生模板讓你能夠聲明分類爲「隱藏DOM」可是解析成HTML的標記片斷。他們在頁面加載時沒有用處,可是能夠在運行時實例化。他們能夠 被檢索到 ,可是在插入活動的DOM樹前不會加載任何相關資源。
可是,就像每次提到新特性同樣,咱們不能肯定瀏覽器是否支持這些特性。
截至2014年6月27日,Web Component 的瀏覽器支持狀況
一樣,咱們也能經過一些神奇的兼容代碼,開始使用某些Web Component所提供的功能。
有了兼容庫的Web Component支持狀況
好消息是兩個最早進的瀏覽器廠商Google和Mozilla正在努力完善兼容庫 ,幫助咱們使用Web Component。
如下示例展現使用platform.js後咱們能夠如何定義做爲img元素擴展的my-avatar元素。最棒的是它能用到原生img元素的全部功能。
查看代碼演示: http://jsbin.com/pihuz/4/edit
點擊 HTML5 Rocks Custom Elements tutorial 以查看建立自定義元素的更多信息。
注:若是你對platform.js感興趣,也能夠看看 bosonic。
原生技術的支持目的就是給咱們提供相應的構建基礎。因此Web Component並非庫和框架的末日信號。
Polymer 是演示構建基於原生Web Component功能的最佳示例。它提供了精選的機制用來建立自定義的Polymer元素,而且提供了許多核心的UI組件,讓你能夠建立本身的應用程序。
下面你能夠看到 my-avatar
元素的簡單建立過程,同時咱們也獲得了想要的標記。
查看代碼演示: http://jsbin.com/gukoku/2/edit
Google正在大力推進Polymer。請查看 Polymer getting started guide 查看更多示例。
Mozilla開發了本身的自定義元素 兼容庫,叫作 X-Tag。X-Tag是一個爲啓用Web Component進行多項兼容的庫,並即將提供對Web Component的完整支持。
如下就是使用X-Tag的 my-avatar
自定義組件,與標準文檔十分相似:
查看代碼演示:http://jsbin.com/wexiz/2/edit
Mozilla同時還創造了一個叫 Brick 的庫,其中包括X-Tag,提供「一組用來方便快速構建Web應用程序的UI組件」,使用與Google的Polymer類似的方式。
使用基於組件的架構構建應用程序有諸多好處,你能從現有的框架中學到,也能在構建前端Web應用程序時從推薦的Web Component中學習到。
這場組件化Web王國的旅程,讓咱們在面臨框架和工具的選擇時猶豫不決。可是,Web Component會是最後的明燈!
Web Component會提供構建應用程序的原生統一的方法。現有的框架頗有可能會轉而使用Web Component或者說明如何與它一同使用。Ember的策略是讓遷移到Web Component更加方便,而Facebook的React則是演示整合的好例子,已經有一個 ReactiveElements 演示它了。由於Angular和Polymer都是Google的項目,他們頗有可能會走到一塊兒。