這個頁面無疑是最難編寫的,但我們認為它也是非常重要的。或許你曾遇到了一些問題并且已經用其他的框架解決了。你來這里的目的是看看 Vue 是否有更好的解決方案。這也是我們在此想要回答的。
客觀來說,作為核心團隊成員,顯然我們會更偏愛 Vue,認為對于某些問題來講用 Vue 解決會更好。如果沒有這點信念,我們也就不會整天為此忙活了。但是在此,我們想盡可能地公平和準確地來描述一切。其他的框架也有顯著的優點,例如 React 龐大的生態系統,或者像是 Knockout 對瀏覽器的支持覆蓋到了 IE6。我們會嘗試著把這些內容全部列出來。
我們也希望得到**你**的幫助,來使文檔保持最新狀態,因為 JavaScript 的世界進步的太快。如果你注意到一個不準確或似乎不太正確的地方,請[提交問題](https://github.com/vuejs/vuejs.org/issues/new?title=Inaccuracy+in+comparisons+guide)讓我們知道。
## React
React 和 Vue 有許多相似之處,它們都有:
- 使用 Virtual DOM
- 提供了響應式 (Reactive) 和組件化 (Composable) 的視圖組件。
- 將注意力集中保持在核心庫,而將其他功能如路由和全局狀態管理交給相關的庫。
由于有著眾多的相似處,我們會用更多的時間在這一塊進行比較。這里我們不只保證技術內容的準確性,同時也兼顧了平衡的考量。我們需要承認 React 比 Vue 更好的地方,比如更豐富的生態系統。
下列部分章節會略微有些過時,因為最近 React 16+ 的發布,我們計劃在不久的將來和 React 社區一起重寫這部分內容。
### 運行時性能
React 和 Vue 都是非常快的,所以速度并不是在它們之中做選擇的決定性因素。對于具體的數據表現,可以移步這個[第三方 benchmark](https://stefankrause.net/js-frameworks-benchmark8/table.html),它專注于渲染/更新非常簡單的組件樹的真實性能。
#### 優化
在 React 應用中,當某個組件的狀態發生變化時,它會以該組件為根,重新渲染整個組件子樹。
如要避免不必要的子組件的重渲染,你需要在所有可能的地方使用 `PureComponent`,或是手動實現 `shouldComponentUpdate` 方法。同時你可能會需要使用不可變的數據結構來使得你的組件更容易被優化。
然而,使用 `PureComponent` 和 `shouldComponentUpdate` 時,需要保證該組件的整個子樹的渲染輸出都是由該組件的 props 所決定的。如果不符合這個情況,那么此類優化就會導致難以察覺的渲染結果不一致。這使得 React 中的組件優化伴隨著相當的心智負擔。
在 Vue 應用中,組件的依賴是在渲染過程中自動追蹤的,所以系統能精確知曉哪個組件確實需要被重渲染。你可以理解為每一個組件都已經自動獲得了 `shouldComponentUpdate`,并且沒有上述的子樹問題限制。
Vue 的這個特點使得開發者不再需要考慮此類優化,從而能夠更好地專注于應用本身。
### HTML & CSS
在 React 中,一切都是 JavaScript。不僅僅是 HTML 可以用 JSX 來表達,現在的潮流也越來越多地將 CSS 也納入到 JavaScript 中來處理。這類方案有其優點,但也存在一些不是每個開發者都能接受的取舍。
Vue 的整體思想是擁抱經典的 Web 技術,并在其上進行擴展。我們下面會詳細分析一下。
#### JSX vs Templates
在 React 中,所有的組件的渲染功能都依靠 JSX。JSX 是使用 XML 語法編寫 JavaScript 的一種語法糖。
使用 JSX 的渲染函數有下面這些優勢:
- 你可以使用完整的編程語言 JavaScript 功能來構建你的視圖頁面。比如你可以使用臨時變量、JS 自帶的流程控制、以及直接引用當前 JS 作用域中的值等等。
- 開發工具對 JSX 的支持相比于現有可用的其他 Vue 模板還是比較先進的 (比如,linting、類型檢查、編輯器的自動完成)。
事實上 Vue 也提供了[渲染函數](render-function.html),甚至[支持 JSX](render-function.html#JSX)。然而,我們默認推薦的還是模板。任何合乎規范的 HTML 都是合法的 Vue 模板,這也帶來了一些特有的優勢:
- 對于很多習慣了 HTML 的開發者來說,模板比起 JSX 讀寫起來更自然。這里當然有主觀偏好的成分,但如果這種區別會導致開發效率的提升,那么它就有客觀的價值存在。
- 基于 HTML 的模板使得將已有的應用逐步遷移到 Vue 更為容易。
- 這也使得設計師和新人開發者更容易理解和參與到項目中。
- 你甚至可以使用其他模板預處理器,比如 Pug 來書寫 Vue 的模板。
有些開發者認為模板意味著需要學習額外的 DSL (Domain-Specific Language 領域特定語言) 才能進行開發——我們認為這種區別是比較膚淺的。首先,JSX 并不是免費的——它是基于 JS 之上的一套額外語法,因此也有它自己的學習成本。同時,正如同熟悉 JS 的人學習 JSX 會很容易一樣,熟悉 HTML 的人學習 Vue 的模板語法也是很容易的。最后,DSL 的存在使得我們可以讓開發者用更少的代碼做更多的事,比如 `v-on` 的各種修飾符,在 JSX 中實現對應的功能會需要多得多的代碼。
更抽象一點來看,我們可以把組件區分為兩類:一類是偏視圖表現的 (presentational),一類則是偏邏輯的 (logical)。我們推薦在前者中使用模板,在后者中使用 JSX 或渲染函數。這兩類組件的比例會根據應用類型的不同有所變化,但整體來說我們發現表現類的組件遠遠多于邏輯類組件。
#### 組件作用域內的 CSS
除非你把組件分布在多個文件上 (例如 [CSS Modules](https://github.com/gajus/react-css-modules)),CSS 作用域在 React 中是通過 CSS-in-JS 的方案實現的 (比如 [styled-components](https://github.com/styled-components/styled-components)、[glamorous](https://github.com/paypal/glamorous) 和 [emotion](https://github.com/emotion-js/emotion))。這引入了一個新的面向組件的樣式范例,它和普通的 CSS 撰寫過程是有區別的。另外,雖然在構建時將 CSS 提取到一個單獨的樣式表是支持的,但 bundle 里通常還是需要一個運行時程序來讓這些樣式生效。當你能夠利用 JavaScript 靈活處理樣式的同時,也需要權衡 bundle 的尺寸和運行時的開銷。
如果你是一個 CSS-in-JS 的愛好者,許多主流的 CSS-in-JS 庫也都支持 Vue (比如 [styled-components-vue](https://github.com/styled-components/vue-styled-components) 和 [vue-emotion](https://github.com/egoist/vue-emotion))。這里 React 和 Vue 主要的區別是,Vue 設置樣式的默認方法是[單文件組件](single-file-components.html)里類似 `style` 的標簽。
[單文件組件](single-file-components.html)讓你可以在同一個文件里完全控制 CSS,將其作為組件代碼的一部分。
```?html
<style scoped>
@media (min-width: 250px) {
.list-container:hover {
background: orange;
}
}
</style>
```
這個可選 `scoped` 屬性會自動添加一個唯一的屬性 (比如 `data-v-21e5b78`) 為組件內 CSS 指定作用域,編譯的時候 `.list-container:hover` 會被編譯成類似 `.list-container[data-v-21e5b78]:hover`。
最后,Vue 的單文件組件里的樣式設置是非常靈活的。通過 [vue-loader](https://github.com/vuejs/vue-loader),你可以使用任意預處理器、后處理器,甚至深度集成 [CSS Modules](https://vue-loader.vuejs.org/en/features/css-modules.html)——全部都在 `<style>` 標簽內。
### 規模
#### 向上擴展
Vue 和 React 都提供了強大的路由來應對大型應用。React 社區在狀態管理方面非常有創新精神 (比如 Flux、Redux),而這些狀態管理模式甚至 [Redux 本身](https://yarnpkg.com/en/packages?q=redux%20vue&p=1)也可以非常容易的集成在 Vue 應用中。實際上,Vue 更進一步地采用了這種模式 ([Vuex](https://github.com/vuejs/vuex)),更加深入集成 Vue 的狀態管理解決方案 Vuex 相信能為你帶來更好的開發體驗。
兩者另一個重要差異是,Vue 的路由庫和狀態管理庫都是由官方維護支持且與核心庫同步更新的。React 則是選擇把這些問題交給社區維護,因此創建了一個更分散的生態系統。但相對的,React 的生態系統相比 Vue 更加繁榮。
最后,Vue 提供了 [Vue-cli 腳手架](https://github.com/vuejs/vue-cli),能讓你非常容易地構建項目,包含了 [Webpack](https://github.com/vuejs-templates/webpack),[Browserify](https://github.com/vuejs-templates/browserify),甚至 [no build system](https://github.com/vuejs-templates/simple)。React 在這方面也提供了 [create-react-app](https://github.com/facebookincubator/create-react-app),但是現在還存在一些局限性:
- 它不允許在項目生成時進行任何配置,而 Vue 支持 [Yeoman](http://yeoman.io/)-like 定制。
- 它只提供一個構建單頁面應用的單一模板,而 Vue 提供了各種用途的模板。
- 它不能用用戶自建的模板構建項目,而自建模板對企業環境下預先建立協議是特別有用的。
而要注意的是這些限制是故意設計的,這有它的優勢。例如,如果你的項目需求非常簡單,你就不需要自定義生成過程。你能把它作為一個依賴來更新。如果閱讀更多關于[不同的設計理念](https://github.com/facebookincubator/create-react-app#philosophy)。
#### 向下擴展
React 學習曲線陡峭,在你開始學 React 前,你需要知道 JSX 和 ES2015,因為許多示例用的是這些語法。你需要學習構建系統,雖然你在技術上可以用 Babel 來實時編譯代碼,但是這并不推薦用于生產環境。
就像 Vue 向上擴展好比 React 一樣,Vue 向下擴展后就類似于 jQuery。你只要把如下標簽放到頁面就可以運行:
`<script src="https://cdn.jsdelivr.net/npm/vue"></script>`
然后你就可以編寫 Vue 代碼并應用到生產中,你只要用 min 版 Vue 文件替換掉就不用擔心其他的性能問題。
由于起步階段不需學 JSX,ES2015 以及構建系統,所以開發者只需不到一天的時間閱讀[指南](./)就可以建立簡單的應用程序。
### 原生渲染
React Native 能使你用相同的組件模型編寫有本地渲染能力的 APP (iOS 和 Android)。能同時跨多平臺開發,對開發者是非常棒的。相應地,Vue 和 [Weex](https://weex.apache.org/) 會進行官方合作,Weex 是阿里巴巴發起的跨平臺用戶界面開發框架,同時也正在 Apache 基金會進行項目孵化,Weex 允許你使用 Vue 語法開發不僅僅可以運行在瀏覽器端,還能被用于開發 iOS 和 Android 上的原生應用的組件。
在現在,Weex 還在積極發展,成熟度也不能和 React Native 相抗衡。但是,Weex 的發展是由世界上最大的電子商務企業的需求在驅動,Vue 團隊也會和 Weex 團隊積極合作確保為開發者帶來良好的開發體驗。
另一個 Vue 的開發者們很快就會擁有的選項是 [NativeScript](https://www.nativescript.org/),這是一個[社區驅動的插件](https://github.com/rigor789/nativescript-vue)。
### MobX
Mobx 在 React 社區很流行,實際上在 Vue 也采用了幾乎相同的反應系統。在有限程度上,React + Mobx 也可以被認為是更繁瑣的 Vue,所以如果你習慣組合使用它們,那么選擇 Vue 會更合理。
### Preact 和其它類 React 庫
類 React 的庫們往往盡可能地與 React 共享 API 和生態。因此上述比較對它們來說也同樣適用。它們和 React 的不同往往在于更小的生態。因為這些庫無法 100% 兼容 React 生態中的全部,部分工具和輔助庫也可能無法使用。或者即使看上去能工作,但也有可能隨時發生不兼容,除非你用的這個類 React 庫官方與 React 保持嚴格一致。
## AngularJS (Angular 1)
Vue 的一些語法和 AngularJS 的很相似 (例如 `v-if` vs `ng-if`)。因為 AngularJS 是 Vue 早期開發的靈感來源。然而,AngularJS 中存在的許多問題,在 Vue 中已經得到解決。
### 復雜性
在 API 與設計兩方面上 Vue.js 都比 AngularJS 簡單得多,因此你可以快速地掌握它的全部特性并投入開發。
### 靈活性和模塊化
Vue.js 是一個更加靈活開放的解決方案。它允許你以希望的方式組織應用程序,而不是在任何時候都必須遵循 AngularJS 制定的規則,這讓 Vue 能適用于各種項目。我們知道把決定權交給你是非常必要的。
這也就是為什么我們提供 [webpack template](https://github.com/vuejs-templates/webpack),讓你可以用幾分鐘,去選擇是否啟用高級特性,比如熱模塊加載、linting、CSS 提取等等。
### 數據綁定
AngularJS 使用雙向綁定,Vue 在不同組件間強制使用單向數據流。這使應用中的數據流更加清晰易懂。
### 指令與組件
在 Vue 中指令和組件分得更清晰。指令只封裝 DOM 操作,而組件代表一個自給自足的獨立單元——有自己的視圖和數據邏輯。在 AngularJS 中,每件事都由指令來做,而組件只是一種特殊的指令。
### 運行時性能
Vue 有更好的性能,并且非常非常容易優化,因為它不使用臟檢查。
在 AngularJS 中,當 watcher 越來越多時會變得越來越慢,因為作用域內的每一次變化,所有 watcher 都要重新計算。并且,如果一些 watcher 觸發另一個更新,臟檢查循環 (digest cycle) 可能要運行多次。AngularJS 用戶常常要使用深奧的技術,以解決臟檢查循環的問題。有時沒有簡單的辦法來優化有大量 watcher 的作用域。
Vue 則根本沒有這個問題,因為它使用基于依賴追蹤的觀察系統并且異步隊列更新,所有的數據變化都是獨立觸發,除非它們之間有明確的依賴關系。
有意思的是,Angular 和 Vue 用相似的設計解決了一些 AngularJS 中存在的問題。
## Angular (原本的 Angular 2)
我們將新的 Angular 獨立開來討論,因為它是一個和 AngularJS 完全不同的框架。例如:它具有優秀的組件系統,并且許多實現已經完全重寫,API 也完全改變了。
### TypeScript
Angular 事實上必須用 TypeScript 來開發,因為它的文檔和學習資源幾乎全部是面向 TS 的。TS 有很多好處——靜態類型檢查在大規模的應用中非常有用,同時對于 Java 和 C# 背景的開發者也是非常提升開發效率的。
然而,并不是所有人都想用 TS——在中小型規模的項目中,引入 TS 可能并不會帶來太多明顯的優勢。在這些情況下,用 Vue 會是更好的選擇,因為在不用 TS 的情況下使用 Angular 會很有挑戰性。
最后,雖然 Vue 和 TS 的整合可能不如 Angular 那么深入,我們也提供了官方的 [類型聲明](https://github.com/vuejs/vue/tree/dev/types) 和 [組件裝飾器](https://github.com/vuejs/vue-class-component),并且知道有大量用戶在生產環境中使用 Vue + TS 的組合。我們也和微軟的 TS / VSCode 團隊進行著積極的合作,目標是為 Vue + TS 用戶提供更好的類型檢查和 IDE 開發體驗。
### 運行時性能
這兩個框架都很快,有非常類似的 benchmark 數據。你可以[瀏覽具體的數據](https://stefankrause.net/js-frameworks-benchmark8/table.html)做更細粒度的對比,不過速度應該不是決定性的因素。
### 體積
在體積方面,最近的 Angular 版本中在使用了 [AOT](https://en.wikipedia.org/wiki/Ahead-of-time_compilation) 和 [tree-shaking](https://en.wikipedia.org/wiki/Tree_shaking) 技術后使得最終的代碼體積減小了許多。但即使如此,一個包含了 Vuex + Vue Router 的 Vue 項目 (gzip 之后 30kB) 相比使用了這些優化的 `angular-cli` 生成的默認項目尺寸 (~65KB) 還是要小得多。
### 靈活性
Vue 相比于 Angular 更加靈活,Vue 官方提供了構建工具來協助你構建項目,但它并不限制你去如何組織你的應用代碼。有人可能喜歡有嚴格的代碼組織規范,但也有開發者喜歡更靈活自由的方式。
### 學習曲線
要學習 Vue,你只需要有良好的 HTML 和 JavaScript 基礎。有了這些基本的技能,你就可以非常快速地通過閱讀 [指南](./) 投入開發。
Angular 的學習曲線是非常陡峭的——作為一個框架,它的 API 面積比起 Vue 要大得多,你也因此需要理解更多的概念才能開始有效率地工作。當然,Angular 本身的復雜度是因為它的設計目標就是只針對大型的復雜應用;但不可否認的是,這也使得它對于經驗不甚豐富的開發者相當的不友好。
## Ember
Ember 是一個全能框架。它提供了大量的約定,一旦你熟悉了它們,開發會變得很高效。不過,這也意味著學習曲線較高,而且并不靈活。這意味著在框架和庫 (加上一系列松散耦合的工具) 之間做權衡選擇。后者會更自由,但是也要求你做更多架構上的決定。
也就是說,我們最好比較的是 Vue 內核和 Ember 的[模板](https://guides.emberjs.com/v2.10.0/templates/handlebars-basics/)與[數據模型](https://guides.emberjs.com/v2.10.0/object-model/)層:
* Vue 在普通 JavaScript 對象上建立響應,提供自動化的計算屬性。在 Ember 中需要將所有東西放在 Ember 對象內,并且手工為計算屬性聲明依賴。
* Vue 的模板語法可以用全功能的 JavaScript 表達式,而 Handlebars 的語法和幫助函數相比來說非常受限。
* 在性能上,Vue 比 Ember [好很多](https://stefankrause.net/js-frameworks-benchmark8/table.html),即使是 Ember 3.x 的最新 Glimmer 引擎。Vue 能夠自動批量更新,而 Ember 在性能敏感的場景時需要手動管理。
## Knockout
Knockout 是 MVVM 領域內的先驅,并且追蹤依賴。它的響應系統和 Vue 也很相似。它在[瀏覽器支持](http://knockoutjs.com/documentation/browser-support.html)以及其他方面的表現也是讓人印象深刻的。它最低能支持到 IE6,而 Vue 最低只能支持到 IE9。
隨著時間的推移,Knockout 的發展已有所放緩,并且略顯有點老舊了。比如,它的組件系統缺少完備的生命周期事件方法,盡管這些在現在是非常常見的。以及相比于 [Vue](components.html#使用插槽分發內容) 調用子組件的接口它的方法顯得有點笨重。
如果你有興趣研究,你還會發現二者在接口設計的理念上是不同的。這可以通過各自創建的 [simple Todo List](https://gist.github.com/chrisvfritz/9e5f2d6826af00fcbace7be8f6dccb89) 體現出來。或許有點主觀,但是很多人認為 Vue 的 API 接口更簡單結構更優雅。
## Polymer
Polymer 是另一個由谷歌贊助的項目,事實上也是 Vue 的一個靈感來源。Vue 的組件可以粗略的類比于 Polymer 的自定義元素,并且兩者具有相似的開發風格。最大的不同之處在于,Polymer 是基于最新版的 Web Components 標準之上,并且需要重量級的 polyfills 來幫助工作 (性能下降),瀏覽器本身并不支持這些功能。相比而言,Vue 在支持到 IE9 的情況下并不需要依賴 polyfills 來工作。
在 Polymer 版本中,為了彌補性能,團隊非常有限的使用數據綁定系統。例如,在 Polymer 中唯一支持的表達式只有布爾值否定和單一的方法調用,它的 computed 方法的實現也并不是很靈活。
## Riot
Riot 3.0 提供了一個類似于基于組件的開發模型 (在 Riot 中稱之為 Tag),它提供了小巧精美的 API。Riot 和 Vue 在設計理念上可能有許多相似處。盡管相比 Riot ,Vue 要顯得重一點,Vue 還是有很多顯著優勢的:
- 更好的性能。Riot 使用了 [遍歷 DOM 樹](http://riotjs.com/compare/#virtual-dom-vs-expressions-binding) 而不是虛擬 DOM,但實際上用的還是臟檢查機制,因此和 AngularJS 患有相同的性能問題。
- 更多成熟工具的支持。Vue 提供官方支持 [webpack](https://github.com/vuejs/vue-loader) 和 [Browserify](https://github.com/vuejs/vueify),而 Riot 是依靠社區來建立集成系統。
- 寫在前面
- 基礎
- 安裝
- 介紹
- Vue實例
- 模板語法
- 計算屬性和偵聽器
- Class 與 Style 綁定
- 條件渲染
- 列表渲染
- 事件處理
- 表單輸入綁定
- 組件基礎
- 深入了解組件
- 組件注冊
- Prop
- 自定義事件
- 插槽
- 動態組件 & 異步組件
- 處理邊界情況
- 過渡 & 動畫
- 進入/離開 & 列表過渡
- 狀態過渡
- 可復用性 & 組合
- 混入
- 自定義指令
- 渲染函數 & JSX
- 插件
- 過濾器
- 工具
- 生產環境部署
- 單文件組件
- 單元測試
- TypeScript 支持
- 規模化
- 路由
- 狀態管理
- 服務端渲染
- 內在
- 深入響應式原理
- 遷移
- 從 Vue 1.x 遷移
- 從 Vue Router 0.7.x 遷移
- 從 Vuex 0.6.x 遷移到 1.0
- 更多
- 對比其他框架
- 加入 Vue.js 社區
- 開發團隊