客戶端框架介紹
我們將從對框架領域進行概括性介紹開始,回顧 JavaScript 和框架的簡要歷史,探討框架存在的原因和它們提供的好處,如何開始考慮選擇一個框架來學習,以及客戶端框架的替代方案。
| 預備知識 | 熟悉核心 HTML、CSS 和 JavaScript 語言。 |
|---|---|
| 學習成果 |
|
庫和框架的興起
JavaScript 於 1996 年首次亮相,為此前由靜態文件組成的 Web 增添了偶爾的互動性和趣味性。Web 不再僅僅是一個“**閱讀事物**”的地方,而是一個“**做事情**”的地方。JavaScript 的受歡迎程度穩步上升。使用 JavaScript 的開發人員編寫工具來解決他們面臨的問題,並將它們打包成可重用包,稱為**庫**,以便與他人分享他們的解決方案。這個共享的庫生態系統幫助塑造了 Web 的發展,並最終催生了框架。
**框架**是一個庫,它對軟體的構建方式提供了意見。這些意見使得應用程式具有可預測性和同質性;可預測性使得軟體能夠擴充套件到巨大的規模並仍然易於維護;可預測性和可維護性對於軟體的健康和壽命至關重要。現代 JavaScript 框架的出現使得構建高度動態、互動式應用程式變得更加容易。
JavaScript 框架為現代 Web 上許多令人印象深刻的軟體提供支援,包括你每天可能使用的許多網站。
有哪些框架?
市面上的框架很多,但目前被認為是“四大”的框架如下。
Ember
Ember 最初於 2011 年 12 月釋出,是 SproutCore 專案工作的延續。它是一個較老的框架,使用者比 React 和 Vue 等現代替代方案少,但由於其穩定性、社群支援和一些巧妙的編碼原則,它仍然享有相當大的歡迎。
Angular
Angular 是一個開源 Web 應用程式框架,由 Google 的 Angular 團隊以及個人和公司社群主導。它是構建 AngularJS 的同一團隊的完全重寫。Angular 於 2016 年 9 月 14 日正式釋出。
Angular 是一個基於元件的框架,使用宣告式 HTML 模板。在構建時,框架的編譯器對開發人員透明地將模板轉換為最佳化的 JavaScript 指令。Angular 使用 TypeScript,它是 JavaScript 的超集,我們將在下一章中更詳細地介紹。
Vue
在參與並從原始 AngularJS 專案中學習之後,尤雨溪於 2014 年釋出了 Vue。Vue 是四大框架中最年輕的,但最近受歡迎程度有所上升。
Vue,像 AngularJS 一樣,用它自己的一些程式碼擴充套件了 HTML。除此之外,它主要依賴於現代的、標準的 JavaScript。
React
Facebook 於 2013 年釋出了 React。在此之前,它已經在內部使用 React 解決了許多問題。從技術上講,React 本身**不是**一個框架;它是一個用於渲染 UI 元件的庫。React 與**其他**庫結合使用來構建應用程式——React 和 React Native 使開發人員能夠製作移動應用程式;React 和 ReactDOM 使他們能夠製作 Web 應用程式,等等。
因為 React 和 ReactDOM 經常一起使用,所以 React 被口語化地理解為 JavaScript 框架。當你閱讀本模組時,我們將以這種口語化的理解來工作。
React 用類似 HTML 的語法擴充套件了 JavaScript,稱為 JSX。
為什麼會有框架?
我們已經討論了激發框架建立的環境,但沒有真正討論開發人員為什麼感到需要建立它們。探索“為什麼”需要首先審視軟體開發的挑戰。
考慮一種常見的應用程式:一個待辦事項列表建立器,我們將在未來的章節中研究使用各種框架來實現它。這個應用程式應該允許使用者做一些事情,比如渲染任務列表、新增新任務和刪除任務;它必須在可靠地跟蹤和更新應用程式底層資料的同時完成這些操作。在軟體開發中,這種底層資料被稱為狀態。
我們的每個目標在理論上都是獨立的簡單。我們可以迭代資料來渲染它;我們可以向物件新增內容來建立新任務;我們可以使用識別符號來查詢、編輯或刪除任務。當我們記住應用程式必須讓使用者透過瀏覽器完成所有這些事情時,一些問題就開始顯現出來。**真正的問題是:每次我們更改應用程式的狀態時,我們都需要更新 UI 以匹配。**
我們可以透過檢視待辦事項列表應用程式的**一個**功能來審視這個問題的難度:渲染任務列表。
DOM 更改的冗長性
構建 HTML 元素並在適當的時間在瀏覽器中渲染它們需要驚人的大量程式碼。假設我們的狀態是一個鍵值儲存,包含 `taskName`(由文字輸入控制)和 `tasks` 列表。
const state = {
taskName: "",
tasks: [
{
id: "todo-0",
name: "Learn some frameworks!",
},
],
};
我們如何向用戶展示其中一個任務?我們希望將每個任務表示為一個列表項——一個 HTML ``
)內部。我們如何製作它?它可能看起來像這樣:
function buildTodoItemEl(id, name) {
const item = document.createElement("li");
const span = document.createElement("span");
span.textContent = name;
item.id = id;
item.appendChild(span);
item.appendChild(buildDeleteButtonEl(id));
return item;
}
在這裡,我們使用 `document.createElement()` 方法來建立我們的 `
前面的程式碼片段引用了另一個構建函式:`buildDeleteButtonEl()`。它遵循與我們用於構建列表項元素類似的模式。
function buildDeleteButtonEl(id) {
const button = document.createElement("button");
button.setAttribute("type", "button");
button.addEventListener("click", () => {
state.tasks = state.tasks.filter((t) => t.id !== id);
renderTodoList();
});
button.textContent = "Delete";
return button;
}
有趣的是,每次我們更新狀態時,我們都需要手動呼叫 `renderTodoList`,以便我們的狀態與螢幕同步。在頁面上渲染專案的程式碼可能如下所示:
function renderTodoList() {
const frag = document.createDocumentFragment();
state.tasks.forEach((task) => {
const item = buildTodoItemEl(task.id, task.name);
frag.appendChild(item);
});
while (todoListEl.lastChild) {
todoListEl.removeChild(todoListEl.lastChild);
}
todoListEl.appendChild(frag);
}
我們現在有將近三十行程式碼**只**用於 UI——**只**用於在 DOM 中渲染一些東西——而且我們從未新增過以後可以用來樣式化列表項的類!
如果你好奇,下面有一個完整的執行演示。你可以點選“播放”按鈕在演練場中檢視原始碼。
像這個例子一樣直接使用 DOM,需要了解許多關於 DOM 如何工作的事情:如何建立元素;如何改變它們的屬性;如何將元素巢狀在一起;如何將它們呈現在頁面上。所有這些程式碼實際上都沒有處理使用者互動,也沒有解決新增或刪除任務的問題。如果我們要新增這些功能,我們必須記住在正確的時間以正確的方式更新我們的 UI。
JavaScript 框架的建立是為了讓這種工作變得更容易——它們的存在是為了提供更好的**開發者體驗**。它們並沒有為 JavaScript 帶來全新的功能;它們讓你更容易地訪問 JavaScript 的功能,這樣你就可以為今天的 Web 進行構建。
閱讀有關本節中使用的 JavaScript 功能的更多資訊
構建 UI 的另一種方式
每個 JavaScript 框架都提供了一種更**宣告性**地編寫使用者介面的方式。也就是說,它們允許你編寫描述 UI 應該如何顯示的程式碼,然後框架會在後臺在 DOM 中實現它。
香草 JavaScript 重複構建新 DOM 元素的方法很難一眼看懂。相比之下,以下程式碼塊說明了你如何使用 Vue 來描述我們的任務列表:
<ul>
<li v-for="task in tasks" v-bind:key="task.id">
<span>{{task.name}}</span>
<button type="button">Delete</button>
</li>
</ul>
就是這樣。這個程式碼片段將近三十行程式碼縮減到六行。如果這裡的花括號和 `v-` 屬性對你來說不熟悉,那沒關係;你將在模組後面學習 Vue 特定的語法。這裡需要記住的是,這段程式碼看起來像它所代表的 UI,而香草 JavaScript 程式碼則不是。
多虧了 Vue,我們不必自己編寫構建 UI 的函式;框架將以最佳化、高效的方式為我們處理。我們在這裡的唯一作用是向 Vue 描述每個專案應該是什麼樣子。熟悉 Vue 的開發人員在加入我們的專案時可以迅速弄清楚發生了什麼。Vue 並非獨一無二:使用框架可以提高團隊和個人效率。
在原生 JavaScript 中,可以做**類似**的事情。模板字面量字串 可以輕鬆編寫 HTML 字串,這些字串代表最終元素的外觀。對於像我們的待辦事項列表應用程式這樣簡單的事情,這可能是一個有用的想法,但對於管理數千條資料記錄並可能在使用者介面中渲染同樣多獨特元素的大型應用程式來說,它是不可維護的。
框架為我們帶來的其他好處
讓我們看看框架提供的其他一些優勢。正如我們之前提到的,框架的優勢在原生 JavaScript 中也可以實現,但使用框架可以消除你自己解決這些問題所需的所有認知負擔。
工具
由於本模組中的每個框架都有一個龐大而活躍的社群,每個框架的生態系統都提供了改進開發人員體驗的工具。這些工具可以輕鬆新增測試(以確保你的應用程式按預期執行)或 Linting(以確保你的程式碼無錯誤且樣式一致)等功能。
**注意:** 如果你想了解更多關於 Web 工具概念的詳細資訊,請檢視我們的客戶端工具概述。
模組化
大多數主流框架鼓勵開發人員將其使用者介面的不同部分抽象為**元件**——可維護、可重用的程式碼塊,它們可以相互通訊。與給定元件相關的所有程式碼都可以位於一個檔案(或幾個特定檔案)中,這樣作為開發人員,你就可以準確地知道在哪裡可以更改該元件。在原生 JavaScript 應用程式中,你必須建立自己的一套約定才能以高效、可擴充套件的方式實現這一點。許多 JavaScript 開發人員,如果讓他們自行其是,最終可能會將與 UI 的一部分相關的所有程式碼分散在整個檔案中,或者完全在另一個檔案中。
路由
Web 最基本的功能是允許使用者從一個頁面導航到另一個頁面——畢竟,它是一個互聯文件的網路。當你點選這個網站上的一個連結時,你的瀏覽器會與伺服器通訊並獲取新的內容來顯示給你。這樣做時,位址列中的 URL 會改變。你可以儲存這個新的 URL 並在以後回到該頁面,或者與他人分享,以便他們可以輕鬆找到同一頁面。你的瀏覽器會記住你的導航歷史記錄,並允許你前後導航。這稱為**伺服器端路由**。
現代 Web 應用程式通常不獲取和渲染新的 HTML 檔案——它們載入一個 HTML shell,並不斷更新其中的 DOM(稱為**單頁應用程式**,或 **SPA**),而無需將使用者導航到 Web 上的新地址。每個新的偽網頁通常稱為**檢視**,並且預設情況下不進行路由。
當 SPA 足夠複雜,並渲染足夠多的獨特檢視時,將路由功能引入應用程式非常重要。人們習慣於能夠連結到應用程式中的特定頁面,在導航歷史記錄中前進和後退等,當這些標準 Web 功能被破壞時,他們的體驗會受到影響。當路由以這種方式由客戶端應用程式處理時,它恰當地被稱為**客戶端路由**。
使用 JavaScript 和瀏覽器原生功能構建路由器是**可能**的,但流行且活躍開發的框架都有配套庫,使路由成為開發過程中更直觀的一部分。
使用框架時需要考慮的事項
成為一名高效的 Web 開發人員意味著為工作使用最合適的工具。JavaScript 框架使前端應用程式開發變得容易,但它們並非解決所有問題的萬能藥。本節討論了你在使用框架時應該考慮的一些事項。請記住,你可能根本不需要框架——請注意,不要僅僅為了使用框架而使用框架。
對工具的熟悉程度
就像原生 JavaScript 一樣,框架也需要時間學習並有其獨特之處。在決定為專案使用框架之前,請確保你有足夠的時間學習其功能,使其對你有所幫助,而不是阻礙你,並確保你的隊友也對此感到滿意。
過度設計
如果你的 Web 開發專案是一個包含少量頁面且幾乎沒有互動功能的個人作品集,那麼框架(及其所有 JavaScript)可能根本沒有必要。話雖如此,框架並非一成不變,有些框架比其他框架更適合小型專案。在 Smashing Magazine 的一篇文章中,Sarah Drasner 撰文講述了 Vue 如何取代 jQuery 作為使網頁小部分具有互動性的工具。
更大的程式碼庫和抽象
框架允許你編寫更宣告性的程式碼——有時總體上程式碼會更少——透過在幕後為你處理 DOM 互動。這種抽象對於你的開發人員體驗來說非常棒,但它並非沒有代價。為了將你編寫的內容轉換為 DOM 更改,框架必須執行自己的程式碼,這反過來會使你的最終軟體更大,執行成本更高。
一些額外的程式碼是不可避免的,支援搖樹最佳化(在構建過程中刪除應用程式中實際未使用的任何程式碼)的框架將使你的應用程式保持較小,但你仍然需要在考慮應用程式效能時記住這個因素,尤其是在網路/儲存受限的裝置(如手機)上。
框架的抽象不僅影響你的 JavaScript,還影響你與 Web 本質的關係。無論你如何構建 Web,最終結果,即使用者最終與之互動的層面,都是 HTML。用 JavaScript 編寫整個應用程式可能會讓你忽視 HTML 及其各種標籤的目的,並導致你生成一個非語義化且不可訪問的 HTML 文件。事實上,有可能編寫一個完全依賴 JavaScript 且沒有 JavaScript 就無法執行的脆弱應用程式。
框架並非我們問題的根源。在錯誤的優先順序下,任何應用程式都可能脆弱、臃腫且無法訪問。然而,框架確實會放大我們作為開發人員的優先順序。如果你的優先順序是建立一個複雜的 Web 應用程式,那麼這樣做很容易。但是,如果你的優先順序沒有仔細保護效能和可訪問性,框架將放大你的脆弱性、臃腫性和不可訪問性。由框架放大的現代開發人員優先順序,在許多地方顛覆了 Web 的結構。Web 現在常常將 JavaScript 放在首位,將使用者體驗放在最後,而不是一個健壯的、內容優先的文件網路。
框架驅動的 Web 上的可訪問性
讓我們在前一節所說的基礎上,再多談一些可訪問性。建立使用者介面可訪問性總是需要一些思考和努力,而框架可能會使這個過程複雜化。你通常需要使用高階框架 API 來訪問原生瀏覽器功能,例如 ARIA 即時區域 或焦點管理。
在某些情況下,框架應用程式會建立傳統網站不存在的輔助功能障礙。其中最大的例子就是前面提到的客戶端路由。
使用傳統(伺服器端)路由,瀏覽網頁會產生可預測的結果。瀏覽器知道將焦點設定在頁面頂部,輔助技術會宣佈頁面標題。這些事情在你每次導航到新頁面時都會發生。
使用客戶端路由時,你的瀏覽器不會載入新的網頁,因此它不知道應該自動調整焦點或宣佈新的頁面標題。框架作者投入了大量時間和精力來編寫 JavaScript 來重新建立這些功能,即使如此,也沒有任何框架做得完美。
結果是,你應該從**每個**Web 專案一開始就考慮可訪問性,但請記住,如果你的程式碼庫使用框架並抽象化,那麼如果做不到這一點,很可能會出現重大的可訪問性問題。
如何選擇框架
本模組中討論的每個框架都採用不同的方法進行 Web 應用程式開發。每個框架都在不斷改進或改變,並且各有優缺點。選擇合適的框架是一個依賴於團隊和專案的過程,你應該自己研究以發現適合你需求的產品。話雖如此,我們已經確定了幾個你可以提出的問題,以便更有效地研究你的選擇:
- 框架支援哪些瀏覽器?
- 框架使用了哪些領域特定語言?
- 框架是否有強大的社群和良好的文件(以及其他支援)可用?
本節中的表格一目瞭然地總結了每個框架當前提供的**瀏覽器支援**,以及它可以使用**領域特定語言**。
廣義上說,領域特定語言(DSLs) 是在軟體開發特定領域相關的程式語言。在框架的上下文中,DSLs 是 JavaScript 或 HTML 的變體,可以使該框架的開發更容易。至關重要的是,沒有一個框架**要求**開發人員使用特定的 DSL,但它們幾乎都設計時都考慮到了特定的 DSL。選擇不使用框架首選的 DSL 意味著你將錯過原本可以改善開發人員體驗的功能。
在為任何新專案做出選擇時,您應該認真考慮框架的支援矩陣和 DSL。瀏覽器支援不匹配可能會成為使用者訪問的障礙;DSL 支援不匹配可能會成為您和您的隊友的障礙。
| 框架 | 瀏覽器支援 | 首選 DSL | 支援的 DSL | 引用 |
|---|---|---|---|---|
| Angular | 現代 | TypeScript | 基於 HTML;TypeScript | 官方文件 |
| React | 現代 | JSX | JSX;TypeScript | 官方文件 |
| Vue | 現代 (Vue 2 中的 IE9+) | 基於 HTML | 基於 HTML,JSX,Pug | 官方文件 |
| Ember | 現代 (Ember 版本 2.18 中的 IE9+) | Handlebars | Handlebars,TypeScript | 官方文件 |
**注意:** 我們描述為“基於 HTML”的 DSL 沒有官方名稱。它們並非真正的 DSL,但它們是非標準 HTML,因此我們認為它們值得強調。
框架是否有強大的社群?
這或許是最難衡量的一個指標,因為社群規模與易於獲取的數字並不直接相關。你可以檢視一個專案的 GitHub 星星數量或每週 npm 下載量來了解它的受歡迎程度,但有時最好的方法是搜尋一些論壇或與其他開發者交流。這不僅僅是關於社群的規模,還在於它是否熱情和包容,以及可用文件的質量如何。
網路上的觀點
不要只聽我們的一面之詞——網路上有很多討論。維基媒體基金會最近選擇在其前端使用 Vue,併發布了一份關於框架採納的徵求意見(RFC)。RFC 的作者 Eric Gardner 花時間概述了維基媒體專案的需求以及為什麼某些框架是團隊的良好選擇。這份 RFC 是你在計劃使用前端框架時應該自己進行研究的一個很好的例子。
JavaScript 狀態調查是 JavaScript 開發人員反饋的有用集合。它涵蓋了許多與 JavaScript 相關的主題,包括框架使用情況和開發人員對它們的看法。目前,有幾年的資料可用,可以讓你瞭解框架的受歡迎程度。
Vue 團隊詳盡地將 Vue 與其他流行框架進行了比較。這種比較可能存在一些偏見(他們也提到了),但它仍然是一個寶貴的資源。
客戶端框架的替代方案
如果你正在尋找加速 Web 開發過程的工具,並且你知道你的專案不需要密集的客戶端 JavaScript,你可以選擇其他一些解決方案來構建 Web:
- 內容管理系統
- 伺服器端渲染
- 靜態網站生成器
內容管理系統
**內容管理系統** (**CMS**) 是任何允許使用者直接建立 Web 內容而無需自己編寫程式碼的工具。它們是大型專案的好解決方案,特別是那些需要編碼能力有限的內容作者輸入,或者希望節省時間的程式設計師的專案。然而,它們需要大量的時間來設定,並且使用 CMS 意味著你至少在一定程度上放棄了對網站最終輸出的控制。例如:如果你選擇的 CMS 預設不創作可訪問的內容,那麼通常很難改進這一點。
伺服器端渲染
**伺服器端渲染** (**SSR**) 是一種應用程式架構,其中**伺服器**負責渲染單頁應用程式。這與**客戶端渲染**相反,後者是構建 JavaScript 應用程式最常見和最直接的方式。伺服器端渲染對客戶端裝置來說更容易,因為你只向它們傳送渲染過的 HTML 檔案,但與客戶端渲染的應用程式相比,它的設定可能很困難。
本模組中介紹的所有框架都支援伺服器端渲染和客戶端渲染。請檢視 React 的 Next.js、Vue 的 Nuxt(是的,這令人困惑,不,這些專案沒有關聯!)、Ember 的 FastBoot 和 Angular 的 Angular Universal。
**注意:** 有些 SSR 解決方案是由社群編寫和維護的,而有些則是框架維護者提供的“官方”解決方案。
靜態站點生成器
靜態網站生成器是一種程式,它動態生成多頁網站的所有網頁——包括任何相關的 CSS 或 JavaScript——以便它們可以釋出到任意數量的地方。例如,釋出主機可以是 GitHub pages 分支、Netlify 例項,或你選擇的任何私有伺服器。這種方法有許多優點,主要圍繞效能(使用者的裝置不需要用 JavaScript 構建頁面;它已經完成)和安全性(靜態頁面具有更少的攻擊向量)。這些網站仍然可以在需要時使用 JavaScript,但它們不**依賴**它。靜態網站生成器需要時間來學習,就像任何其他工具一樣,這可能會成為你開發過程的障礙。
靜態網站可以有任意數量的獨特頁面。就像框架賦能你快速編寫客戶端 JavaScript 應用程式一樣,靜態網站生成器為你提供了一種快速建立 HTML 檔案的方式,否則你將不得不單獨編寫這些檔案。與框架一樣,靜態網站生成器允許開發人員編寫定義網頁常見部分的元件,並將這些元件組合起來建立最終頁面。在靜態網站生成器的上下文中,這些元件被稱為**模板**。由靜態網站生成器構建的網頁甚至可以託管框架應用程式:例如,如果你希望你的靜態生成網站的某個特定頁面在使用者訪問時啟動 React 應用程式,你也可以這樣做。
靜態網站生成器已經存在了相當長的時間,並且它們正在不斷最佳化和創新。存在一系列選擇,包括 Astro、Eleventy、Hugo、Jekyll 和 Gatsby,它們建立在各種技術棧上並提供獨特的功能。其他選項,例如 Docusaurus 和 VitePress,則使用客戶端框架而不是模板,但生成同樣最佳化的靜態檔案。
如果你想全面瞭解靜態站點生成器,請檢視 Tatiana Mac 的 Eleventy 入門指南。在該系列的第一篇文章中,她解釋了什麼是靜態站點生成器,以及它與釋出 Web 內容的其他方式之間的關係。
總結
至此,我們對框架的介紹就結束了——我們還沒有教你任何程式碼,但希望我們已經為你提供了有用的背景知識,讓你瞭解為什麼首先要使用框架以及如何選擇框架,並讓你對學習更多和深入其中感到興奮!
我們的下一篇文章將深入探討更底層的內容,研究框架通常提供的特定功能型別,以及它們的工作原理。