前言
因爲沒有明確的界定, 這裏不討論正確與否, 只表達個人對前端 MV * 架構模式理解看法, 再比較 React 和 vue 兩種框架不同.
寫完之後我知道這文章好水, 特別是框架對比部分都是別人說爛的, 而我也是打算把這作爲長期文章來寫, 慢慢梳理深入, 每次有新的理解就更新文章, 我挺期待之後到了超過字數限制不得不寫成系列文章的那一天.
MVC
MVC 全名是 Model View Controller, 把應用程序分成三部分分別是:
Model(業務模型): 用于管理應用程序數據處理邏輯的部分, 通過觀察者模式 (Pub&Sub / Events) 發送消息給 View;
View(視圖界面): 用于處理數據顯示的部分, 注冊並接收 Model 的數據更新視圖, 通常視圖是依據模型數據創建的;
Controller(控制器): 用于連接模型和視圖控制應用程序的流程(事件綁定等), 通常控制器負責響應 View 的事件(路由, 鍵盤, 鼠標等), 調用 Model 的接口進行操作;
- (這些簡單的東西我就懶得特意畫圖了, 直接百度圖片找張清晰的拿來用的..)
- (更多內容請自行查閱, 本節到此爲止了.)
流程
1, 當用戶在視圖界面中發生交互事件, View 捕獲到這個操作會把處理的權利交移給 Controller;
2, Controller 會對來自 View 數據進行預處理並決定調用 Model 的相關暴露接口;
3, Model 執行相關的業務邏輯更改數據之後會通知有關的 View 重新渲染;
4, View 收到通知後從 Model 請求最新的數據, 然後重新渲染相關視圖界面;
還有一種情況: MVC 允許在不改變視圖外觀的情況下改變視圖對用戶輸入的響應方式, 只要用不同種類的 controller 實例替換即可. 例如改變 URL 觸發 hashChange 事件, 用戶不經過 View 直接到達 Controller 最後再影響回 View.
優點:
1, 耦合性低, MVC 分層有助于管理複雜的應用程序, 同時也讓應用程序的測試更加容易;
2, 重用性高, 多個視圖能共享一個模型, 可以做到多視圖同時更新;
3, 生命周期成本低, MVC 使開發和維護用戶接口的技術含量降低;
4, 部署快, 只需要部署對應部分代碼而不是完整項目;
5, 可維護性高, 分離視圖層和業務邏輯層也使得應用更易于維護和修改;
6, 有利軟件工程化管理, 可以使用控制器來聯接不同的模型和視圖去完成用戶的需求;
缺點:
1, 沒有明確的定義, 完全理解 MVC 並不是很容易, 現存就有很多對 MVC 不同解讀實現的方式;
2, 不適合小型, 中等規模的應用程序, 花費大量時間將 MVC 應用到規模並不是很大的應用程序通常會得不償失;
3, 增加系統結構和實現的複雜性, 對于簡單的界面, 會增加結構的複雜性, 並可能産生過多的更新操作, 降低運行效率;
4, 視圖與控制器間的過于緊密的連接, 視圖沒有控制器的存在, 其應用是很有限的, 反之亦然, 導致測試困難(依據模型數據創建部分);
5, 視圖對模型數據的低效率訪問, 依據模型操作接口的不同, 視圖可能需要多次調用才能獲得足夠的顯示數據;
6, 觀察者模式由于事件觸發的隱式行爲可能導致很難查找問題的來源並影響其解決;
MVP
MVP 全名是 Model-View-Presenter, 從經典的模式 MVC 演變而來, 分兩種情況:
Passive View(被動視圖)
Presenter 占據絕對主導地位, 掌控著 Model 和 View, 而後兩者之間互不聯系.
Model(業務模型): 用于管理應用程序數據處理邏輯的部分, 通過觀察者模式 (Pub&Sub / Events) 發送消息給 Presenter;
View(視圖界面): 用于處理數據顯示的部分, 傳遞事件和提供相關接口給 Presenter;
Presenter(派發器): 作爲中間層同步控制著 Model 數據修改和 View 視圖變化;
- (這些簡單的東西我就懶得特意畫圖了, 直接百度圖片找張清晰的拿來用的..)
- (更多內容請自行查閱, 本節到此爲止了.)
流程:
1, 當用戶在視圖界面中發生交互事件, View 捕獲到這個操作會把處理的權利交移給 Presenter 進行處理;
3, Presenter 需要時候可以獲取 Model 其中的數據, 並對 Model 進行操作更新;
4, Model 數據變化之後會通知 Presenter;
2, Presenter 收到通知後會執行 View 提供的相關接口重新渲染相關視圖界面;
MVC 和 MVP(Passive View)區別:
1, 後者 View 和 Model 完全解耦, 它們之間的通信是通過 Presenter (MVC 中的 Controller)來進行的, 所有的交互都發生在 Presenter 內部;
2, 前者 Controller 只能通過 Model 間接觸發 View 自行更新視圖, 後者 View 不再負責更新視圖, 而是提供接口給 Presenter 執行;
Supervising Controller(監督控制器)
Presenter 依舊占據主導地位, 但是會把一部分簡單的視圖邏輯 (如雙向綁定) 交還給 View 和 Model 進行處理, 自身負責其他複雜的視圖邏輯.
Model(業務模型): 用于管理應用程序數據處理邏輯的部分, 通過觀察者模式 (Pub&Sub / Events) 發送消息給 Presenter 或者 View;
View(視圖界面): 用于處理數據顯示的部分和接管部分簡單的視圖邏輯, 同步簡單的視圖和模型的狀態, 傳遞事件和提供相關接口給 Presenter;
Presenter(派發器): 作爲中間層同步控制著 Model 數據修改和 View 視圖變化;
MVC 和 MVP(Supervising Controller)區別:
1, 視圖支持 Presenter 和 View 兩種途徑更新;
優點:
1, 模型與視圖高度分離, 我們可以修改視圖而不影響模型;
2, 可以更高效地使用模型, 因爲所有的交互都發生在一個地方 --Presenter 內部;
3, 可以將一個 Presenter 用于多個視圖, 而不需要改變 Presenter 的邏輯;
4, 如果把邏輯放在 Presenter 中, 就可以脫離用戶接口來測試這些邏輯(單元測試);
缺點:
1, 由于對視圖的渲染放在了 Presenter 中, 所以 View 和 Presenter 的交互會過于頻繁並且難以維護;
MVVM
MVVM 全名是 Model-View-ViewModel, 本質上就是 MVC 的改進版, 也可以說是 MVP 的改良版, 把應用程序分成三部分分別是:
Model(業務模型): 用于管理應用程序數據;
View(視圖界面): 通過使用模板語法來聲明式的將數據渲染進 DOM;
ViewModel(視圖模型): 包含了領域模型 (Domain Model) 和視圖的狀態(State), 核心就是雙向綁定技術(Two-Way-Data-Binding),View 和 Model 之間數據同步操作交由給內部的 Binder/Data-binding engine 處理;
MVP 和 MVVM 區別: 它使用 數據綁定(Data Binding), 依賴屬性(Dependency Property), 命令(Command), 路由事件(Routed Event) 來搞定與 view 層的交互, 當 ViewModel 對 Model 進行更新的時候, 會通過數據綁定更新到 View.
- (這些簡單的東西我就懶得特意畫圖了, 直接百度圖片找張清晰的拿來用的..)
- (更多內容請自行查閱, 本節到此爲止了.)
優點:
1, 雙向綁定(data-binding):View 的變動, 自動反映在 ViewModel, 反之亦然;
2, 解放 MVP 大量手動同步狀態的問題, 提高了代碼的可維護性;
3, 簡化測試, Model 正確就能保證 View 輸出;
缺點:
1, 大型項目的綁定數據較多會提高維護成本;
2, View 裏的數據綁定無法檢測斷點, 只能從 Model 下手;
React VS Vue
兩個框架是現在最熱門的選擇之一, 它們既類似又不同.
使用 Virtual DOM
提供了響應式 (Reactive) 和組件化 (Composable) 的視圖組件.
將注意力集中保持在核心庫, 而將其他功能如路由和全局狀態管理交給相關的庫.
React 就是 MVC 裏的 V, 只專注視圖層, 而 Vue 算是 MVVM 框架, 雙向綁定是特色之一.
介紹
我們先看看它們自己的官方介紹:
React
React is a JavaScript library for building user interfaces.
- Declarative: React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes. Declarative views make your code more predictable, simpler to understand, and easier to debug.
- Component-Based: Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep state out of the DOM.
- Learn Once, Write Anywhere: We don't make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code. React can also render on the server using Node and power mobile apps using React Native.
翻譯:
React 是一個用于構建用戶界面的 Javascript 庫.
聲明式: React 讓你無痛創建交互式 UI 界面, 爲你的 App 應用程序裏的每個狀態設計簡單的視圖, 並且當你的數據改變之後會進行高效地更新和正確地渲染對應組件, 聲明式視圖讓你的代碼更可預測, 更易于理解和更容易調試.
組件化: 構建封裝組件管理它們自己的內部狀態, 然後組合它們去構建複雜 UI 界面. 因爲組件邏輯寫在 Javascript 而不是模板裏, 你能輕松注入豐富的數據到你的 App 並且狀態脫離在 Dom 之外.
只需學習一次, 就能用到任何地方, 我們不對你的其余技術棧作出假設, 所以你能在 React 裏開發新的特性而不需要重寫你的現有代碼. React 也能使用 Nodejs 進行服務器渲染和使用 React Native 進行移動端的豐富開發.
Vue
Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable. The core library is focused on the view layer only, and is easy to pick up and integrate with other libraries or existing projects. On the other hand, Vue is also perfectly capable of powering sophisticated Single-Page Applications when used in combination with modern tooling and supporting libraries.
翻譯:
vue.js (讀音 /vjuː/, 類似于 view) 是一套構建用戶界面的漸進式框架. 與其他重量級框架不同的是, Vue 采用自底向上增量開發的設計. Vue 的核心庫只關注視圖層, 它不僅易于上手, 還便于與第三方庫或既有項目整合. 另一方面, 當與單文件組件和 Vue 生態系統支持的庫結合使用時, Vue 也完全能夠爲複雜的單頁應用程序提供驅動.
React JSX
他是 JavaScrip 的一種擴展語法. React 官方推薦使用這種語法來描述 UI 信息. JSX 可能會讓你想起某種模板語言, 但是它具有 JavaScrip 的全部能力, 從本質上講, JSX 只是爲 React.createElement(component, props, ...children) 函數提供的語法糖.
JSX 執行更快, 因爲它在編譯爲 JavaScript 代碼後進行了優化.
它是類型安全的, 在編譯過程中就能發現錯誤.
使用 JSX 編寫模板更加簡單快速.
JSX 對使用 React 不是必須的.
Vue Templates
Vue.js 使用了基于 HTML 的模板語法, 允許開發者聲明式地將 DOM 綁定至底層 Vue 實例的數據. 所有 Vue.js 的模板都是合法的 HTML , 所以能被遵循規範的浏覽器和 HTML 解析器解析.
在底層的實現上, Vue 將模板編譯成虛擬 DOM 渲染函數. 結合響應系統, 在應用狀態改變時, Vue 能夠智能地計算出重新渲染組件的最小代價並應用到 DOM 操作上.
事實上 Vue 也提供了渲染函數, 甚至支持 JSX. 然而, 默認推薦的還是模板.
對于很多習慣了 HTML 的開發者來說, 模板比起 JSX 讀寫起來更自然. 這裏當然有主觀偏好的成分, 但如果這種區別會導致開發效率的提升, 那麽它就有客觀的價值存在.
基于 HTML 的模板使得將已有的應用逐步遷移到 Vue 更爲容易.
這也使得設計師和新人開發者更容易理解和參與到項目中.
你甚至可以使用其他模板預處理器, 比如 Pug 來書寫 Vue 的模板.
對比
個人感覺兩者其實上手速度都挺快, 相比之下 JSX 除了修改部分屬性名字跟普通 HTML 變化不算大, Templates 額外添加很多自定義功能幫助開發者做更多的事, 框架痕迹也比較重.
我們可以把組件區分爲兩類: 一類是偏視圖表現的 (presentational)推薦使用模板, 一類則是偏邏輯的 (logical)推薦使用 JSX 或渲染函數.
- //Jsx 寫法
- <div className="list">
- <ol>
- { todos.map(item =><li>{todo.text}</li>) }
- </ol>
- </div>
- //Templates 寫法
- <div class="list">
- <ol>
- <li v-for="todo in todos">
- {{ todo.text }}
- </li>
- </ol>
- </div>
- CSS
- React
React 中推薦通過 CSS-in-JS 的方案實現的 (比如 styled-components,glamorous 和 emotion), 雖然在構建時將 CSS 提取到一個單獨的樣式表是支持的, 但 bundle 裏通常還是需要一個運行時程序來讓這些樣式生效. 當你能夠利用 JavaScript 靈活處理樣式的同時, 也需要權衡 bundle 的尺寸和運行時的開銷
var styleObj = { color:"blue", fontSize:40, fontWeight:"normal" };
... 省略....
- <h1 style={styleObj} className="alert-text">Hello</h1>
- Vue
Vue 設置樣式的默認方法是單文件組件裏類似 style 的標簽. 讓你可以在同一個文件裏完全控制 CSS, 將其作爲組件代碼的一部分.
- <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, 你可以使用任意預處理器, 後處理器, 甚至深度集成 CSS Modules-- 全部都在 <style> 標簽內.
對比
各有好壞吧, React 侵入式做法不太喜歡, Vue 組件式做法倒也還行, 個人而言更傾向獨立 css 樣式外部引入易于管理.
再渲染性能
React
在 React 裏渲染機制是以組件單位更新的, 也就是說當數據發生改變, 當前視圖包括其中的組件子組件和底下的子組件都會一起更新, 這種違反性能的機制肯定是有問題的, 所以 React 提供了生命周期 shouldComponentUpdate 方法讓你決定當前組件是否更新, 還有一個 PureComponent 方法會自動檢測到 state 或者 props 發生變化時, 才會調用 render 方法. 但是只是淺比較, 如果搭配 ImmutableJs 持久化數據據說性能大大的提升. 除此之外還能節省大量的手動比較的代碼和時間,
Vue
在 Vue 應用中, 組件的依賴是在渲染過程中自動追蹤的, 所以系統能精確知曉哪個組件確實需要被重渲染, 因爲 Vue 是使用 Object.defineProperty 對綁定屬性進行數據劫持的, 所以比起 React 組件式更新它能夠精確接收到哪些組件才是需要渲染的.
路由
React-Router
這是 React-Router3 的模板寫法, 實際到了 React-Router4 的 API 和思想都有些大的差異
- import React from 'react'
- import { render } from 'react-dom'
- // 首先我們需要導入一些組件...
- import { Router, Route, Link } from 'react-router'
- // 然後我們從應用中刪除一堆代碼和
- // 增加一些 <Link> 元素...
- const App = React.createClass({
- render() {
- return (
- <div>
- <h1>App</h1>
- {/* 把 <a> 變成 <Link> */}
- <ul>
- <li><Link to="/about">About</Link></li>
- <li><Link to="/inbox">Inbox</Link></li>
- </ul>
- {/*
- 接著用 `this.props.children` 替換 `<Child>`
- router 會幫我們找到這個 children
- */}
- {this.props.children}
- </div>
- )
- }
- })
- // 最後, 我們用一些 <Route> 來渲染 <Router>.
- // 這些就是路由提供的我們想要的東西.
- React.render((
- <Router>
- <Route path="/" component={App}>
- <Route path="about" component={About} />
- <Route path="inbox" component={Inbox} />
- </Route>
- </Router>
- ), document.body)
Vue-Router
Vue-Router3 的模板寫法
- // 0. 如果使用模塊化機制編程, 導入 Vue 和 VueRouter, 要調用 Vue.use(VueRouter)
- // 1. 定義 (路由) 組件.
- // 可以從其他文件 import 進來
- const Foo = { template: '<div>foo</div>' }
- const Bar = { template: '<div>bar</div>' }
- // 2. 定義路由
- // 每個路由應該映射一個組件. 其中 "component" 可以是
- // 通過 Vue.extend() 創建的組件構造器,
- // 或者, 只是一個組件配置對象.
- // 我們晚點再討論嵌套路由.
- const routes = [
- { path: '/foo', component: Foo },
- { path: '/bar', component: Bar }
- ]
- // 3. 創建 router 實例, 然後傳 `routes` 配置
- // 你還可以傳別的配置參數, 不過先這麽簡單著吧.
- const router = new VueRouter({
- routes // (縮寫)相當于 routes: routes
- })
- // 4. 創建和挂載根實例.
- // 記得要通過 router 配置參數注入路由,
- // 從而讓整個應用都有路由功能
- const app = new Vue({
- router
- }).$mount('#app')
- // 現在, 應用已經啓動了!
官方腳手架
React 官方提供了 create-react-app, 诟病的地方比較多.
它不允許在項目生成時進行任何配置, 而 Vue 支持 Yeoman-like 定制.
它只提供一個構建單頁面應用的單一模板, 而 Vue 提供了各種用途的模板.
它不能用用戶自建的模板構建項目, 而自建模板對企業環境下預先建立協議是特別有用的.
更多人選擇自己搭建或者使用民間打包庫.
Vue 提供了 Vue-cli 腳手架, 能讓你非常容易地構建項目, 包含了 webpack,Browserify, 甚至 no build system, 但是有些設置例如 Scss 預處理器等自定義配置需要自己搞, 總的來說相當實用.
入門難度
React 正常來說需要搭配 Jsx 和 Es6 語法和構建環境;
Vue 可以直接引入 js 庫就能開發, 而且內置的功能屬性比 React 多得多
来源: http://www.qdfuns.com/article/40831/4e8bacfcc901a550ed10fe0a1d4c8c3c.html