標籤:
本文由 埃姆傑 翻譯。未經許可,禁止轉載!
英文出處:Future Insights。內容提要
使用許多獨立組件構建應用程式的想法並不新鮮。Web Component的出現,是重新回顧基於組件的應用程式開發模式的好時機。我們可以從這個過程中受益,瞭解如何使用現有技術完成目標,並且在未來做出自己的前端Web應用。
什麼是組件?
軟體開發是一個語義豐富(術語通常不止一個意思)的領域。很顯然,這裡的“組件”是一個很泛的稱呼,所以有必要指明我們想要表達的,在前端Web應用的語言環境中的意思。
前端Web應用中的組件,是指一些設計為通用性的,用來構建較大型應用程式的軟體,這些組件有多種表現形式。它可以是有UI(使用者介面)的,也可以是作為 “服務”的純邏輯代碼。
因為有視覺上的表現形式,UI組件更容易理解。UI組件簡單的例子包括按鈕、輸入框和文本域。不論是漢堡包狀的功能表按鈕(無論你是否喜歡)、標籤頁、日曆、選項菜單或者所見即所得 (WYSIWYG)的富文字編輯器則是一些更加進階的例子。
提供服務類型的組件可能會讓人難以理解,這種類型的例子包括跨瀏覽器的AJAX支援,日誌記錄或者提供某種資料持久化的功能。
基於組件開發,最重要的就是組件可以用來構成其他組件,而富文字編輯器就是個很好的例子。它是由按鈕、下拉式功能表和一些可視化組件等組成。另一個例子是HTML5上的video元素。它同樣包含按鈕,也同時含有一個能從視頻資料流渲染內容的元素。
為什麼要構建組件?
既然現在已經明白組件的意思,就看看使用組件的方法構建前端應用的好處。
模組
你可能聽說過 “組件是天然模組”的說法。好吧,感謝它,我們又要解釋這裡的術語!
你可能會覺得“組件”的說法更加適合用來描述UI,而“模組”更適合描述提供服務的功能邏輯。而對於我來說,模組和組件意思相近,都提供組織、聚焦和封裝,是與某個功能單位相關的。
高內聚
又是一個軟體工程的高頻詞! 我們將相關的一些功能組織在一起,把一切封裝起來,而在組件的例子中,就可能是相關的功能邏輯和靜態資源: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採用了服務和依賴注入解決這類問題。
樣本組件my-avatar
為了展示我們如何用這些庫和架構構建最基本的組件,我們建立了一個帶有UI,用於取回和顯示帳戶圖片的簡單樣本。在可能的情況下,該組件會有 my-avatar 標籤,會從以下兩個屬性中取得頭像:
service 允許設定一個服務。例如 twitter 或者 facebook
username 用於取回該使用者名稱相對應的頭像
AngularJS
AngularJS 可能是現在用於構建程式最流行的前端解決方案了。作為建立者的Google,重新思考HTML,考慮如何重新發明,滿足如今Web開發的需要。
Angular中可以使用自訂指令定義組件。之後,你可以使用 HTML 標籤聲明自訂群組件。
查看代碼示範: http://jsbin.com/lacog/2/edit
這個例子展示了使用Angular指令的簡單程度。值scope 定義了從 my-avatar 元素中取得,並且之後用來構建相應的img標籤和渲染成帳戶圖片的屬性。
Ember
架構與庫的爭論曠日持久,總的來說架構是強制你按某種方式做事情,所以它是邪惡的。很顯然,Angular是個架構,而Ember的作者,Yehuda Katz和Tom Dale也很樂意把Ember看作架構。
Ember 有對它稱作組件的內建支援。Ember Components背後的理念是儘可能的向Web Components看齊,當瀏覽器支援允許時,就可以很方便地遷移到Web Components中。
查看代碼示範: http://jsbin.com/nawuwi/4/edit
上面的例子中使用了 handlebars 做模板,所以元素的定義不是同一種文法。
React
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才是未來!正如名字所表示的那樣,他們承諾將帶來可以將功能封裝成組件的瀏覽器原生支援。
我將簡單展示Web Component並且示範我們現在可以如何使用它。更加深入的內容請參考本文末尾的 “外部資源” 一節。
他們提供的功能包括:
自訂元素
我們在上面關注的是用Angular、Ember和React構建 my-avatar 的例子。可能的情況下,這樣的方式將以頁面上或者模板上添加的自訂元素表示。Web Component包括通過自訂元素獲得的原生支援 – 絕對是Web Component標準的基本組成部分。
定義新元素,包括訪問元素生命週期的部分事件例如何時建立(createdCallback)、何時添加在DOM樹上(attachedCallback)、何時從DOM樹上分離(detachedCallback),何時元素屬性改變(attributeChangedCallback(attrName, oldVal, newVal))。
自訂元素的一個重要的部分就是有能力從原有元素擴充,因而得到原有元素相應的功能。樣本中我們擴充了 <img>元素 。
最終,我們所寫的代碼中,自訂元素正在並且傾向去做的就是將複雜的東西抽象化,讓使用者關注於單個組件產生的價值,從而用來構建更加豐富的功能。
Shadow DOM
還記得iframe們嗎?我們還在使用它們,是因為他們能確保組件和控制項的JavaScript和CSS不會影響頁面。 Shadow DOM 也能提供這樣的保護,並且沒有iframe帶來的負擔。正式的說法是:
Shadow DOM的設計是在shadow根下隱藏DOM子樹從而提供封裝機制。它提供了建立和保障DOM樹之間的功能界限,以及給這些樹提供互動的功能,從而在DOM樹上提供了更好的功能封裝。
HTML匯入
我們長時間以前就可以匯入JavaScript和CSS了。 HTML匯入功能提供了從其他HTML文檔中匯入和重用HTML文檔的能力。這種簡單性同時意味著可以很方便地用一些組件構建另一些組件。
最後,這樣的格式很理想,適合可重用組件,並且可以用你最喜歡的包管理解決方案發布(例如: bower、 npm 或者 Component)。
模板
我們中的許多人已經使用像handlebars、mustache或者underscore.js中的模板這樣的解決方案(就像我們在上面的Ember樣本中用的一樣)。Web Component通過 template元素 提供了模板的原生支援。
原生模板讓你可以聲明分類為“隱藏DOM”但是解析成HTML的標記片段。他們在頁面載入時沒有用處,但是可以在運行時執行個體化。他們可以 被檢索到 ,但是在插入活動的DOM樹前不會載入任何相關資源。
Platform.js
但是,就像每次提到新特性一樣,我們不能確定瀏覽器是否支援這些特性。
截至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
Polymer 是示範構建基於原生Web Component功能的最佳樣本。它提供了精選的機制用來建立自訂的Polymer元素,並且提供了許多核心的UI組件,讓你可以建立自己的應用程式。
下面你可以看到 my-avatar 元素的簡單建立過程,同時我們也得到了想要的標記。
查看代碼示範: http://jsbin.com/gukoku/2/edit
Google正在大力推動Polymer。請查看 Polymer getting started guide 查看更多樣本。
X-Tag和Brick
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的項目,他們很有可能會走到一起。
外部資源(英文)
- Eric Bidelman – Google I/O 2014 – Polymer and Web Components change everything you know about Web development
- Ryan Seddon – Web Directions – Web Components, The Future of Web Development
- Addy Osmani – LXJS – Componentize The Web: Back To The Browser!
- WebComponents.org a place to discuss and evolve web component best-practices
【轉】組件化的Web王國