MVC && MVVM
前端框架前端 MV*框架的意義
被誤解的MVC和被神化的MVVM
Vue.js新手入門指南
單頁應用SPA的路由
單頁面應用的路由問題html
本文是在本身總結時,看了許多篇文章有了些體會,而後把我認爲有意義的摘抄下來,文中很大部分摘錄以上參考的文章,再結合一點點本身的觀點,總的來講這篇文章是一個彙總文。前端
在前端搞 MV有什麼意義?也有人提出這樣的疑問:以 AngularJS,Knockout,BackBone 爲表明的 MV*框架,它跟 jQuery 這樣的框架有什麼區別?我 jQuery 用得好好的,有什麼必要再引入這種框架?vue
庫和框架是有一些區別的:庫是一種工具,我提供了,你能夠不用,即便你用了,也沒影響你自 己的代碼結構。框架則是面向一個領域,提供一套解決方案,若是你用我,就得按照個人方式辦事。html5
jQuery 的思惟方式是:以 DOM 操做爲中心
MV*框架的思惟方式是:以模型爲中心,DOM 操做只是附加git
因爲前端功能的加強、代碼的膨脹,致使不得不作「前端的架構」這個事情了。github
因此回到那個問題上,jQuery 知足了你的業務須要,你還有什麼必要引入 MV*框架?
這個是要看產品類型的,若是是頁面型產品,多數確實不太須要它,由於頁面中的 JavaScript 代碼,處理交互的絕對遠遠超過處理模型的,可是若是是應用軟件類產品,這就太須要了。 ajax
MV框架的理念是把前端按照職責分層,每一層都相對比較獨立,有本身的價值,也有各自發揮的餘地。vuex
這種邏輯的好處在於,業務邏輯與用戶界面分離以後,後期對於界面的改版以及對於用戶交互的處理變化,僅僅須要改動View層便可,不在須要對業務邏輯層進行多大的改動。後期的維護成本會減小不少。segmentfault
將開發重心從DOM操做,轉移到數據操做,將DOM操做與程序邏輯解耦。
指望提高開發效率、單位時間產出、後期代碼擴展性,下降維護成本設計模式
MVC
Model 數據模型
View 用戶界面
Controller 業務邏輯
不一樣的框架對Model、View的數據同步有不一樣的處理
MVC開發模式的原則:咱們來看看 MVC 這種架構的特色。其實設計模式不少時候是爲了 Don't repeat yourself 原則來作的,該原則要求可以複用的代碼要儘可能複用,來保證重用。在 MVC 這種設計模式中,咱們發現 View 和 Model 都是符合這種原則的。在Controller層儘可能寫不可以複用的。
開發人員只要考慮和處理Model(數據模型)的變化便可,不用考慮Model和View之間的數據綁定同步,更不用花精力用大量的代碼獲取DOM元素改變DOM元素的值來完成界面數據的變化。全部工做交給VM(View-Model)來處理。
MVVM並無業務邏輯的控制器,它經過數據雙向綁定,實時更新View和Model層,當數據模型發生變化的時候,用戶界面(DOM)的內容會即時更新。反之若是用戶操做致使某些DOM內容變化(如input),ViewModel也會即時的將Model數據模型更新。
數據雙向綁定,開發人員不用再把精力放在DOM的修改和更新,只要經過模板引擎將數據模型和用戶界面綁定,框架會實時同步雙方數據的變化。減輕了開發人員的負擔,也減小了DOM操做邏輯致使業務邏輯混亂的可能性。
調用 Backbone.history.start() 開始監控 hashchange 事件並分配路由
View:視圖
Model:數據
Router:路由,因爲Controller層主要負責了路由,而業務邏輯都在View中寫了。
backbone事件:訂閱發佈者模式
Vue.js(讀音 /vjuː/, 相似於 view) 是一套構建用戶界面的 漸進式框架。與其餘重量級框架不一樣的是,Vue 採用自底向上增量開發的設計。Vue 的核心庫只關注視圖層,而且很是容易學習,很是容易與其它庫或已有項目整合。另外一方面,Vue 徹底有能力驅動採用單文件組件和 Vue 生態系統支持的庫開發的複雜單頁應用。
Vue.js 的目標是經過儘量簡單的 API 實現響應的數據綁定和組合的視圖組件。
Vue.js就是一個用於搭建相似於網頁版知乎這種表單項繁多,且內容須要根據用戶的操做進行修改的網頁版應用。
vue 不支持IE8如下瀏覽器的緣由?由於 Vue.js 使用了 IE8 不能模擬的 ECMAScript 5 特性
經過js對象。。。。。。。。。
beforeCreate
observe Data / init Events
組件實例被建立,組件屬性計算以前
應用:beforeCreate 給個loading加載界面
created
1.組件實例建立完成,屬性已經綁定,但DOM還未生成,$el屬性還不存在
2.在實例建立以後同步調用。此時實例已經結束解析選項,這意味着已創建:數據綁定,計算屬性,方法,watcher/事件回調。
3.可是尚未開始 DOM 編譯,$el 還不存在,可是實例存在,即this.a存在,可打印出來 。
應用:created階段作一些初始化,實現函數自執行,例如:created撤銷loading
el / template
beforeMounted
模板編譯、掛載以前
replace el
mounted
1.模板編譯、掛載以後不保證組件已在document中
2.在編譯結束後調用。此時全部的指令已生效,於是數據的變化將觸發 DOM 更新。可是不擔保 $el 已插入文檔。
應用:mounted階段作ajax,或者配合路由鉤子作一些事情;此時DOM已經獲取到,能夠對DOM進行操做
data changed
beforeUpdated
1.數據更新時調用,發生在虛擬 DOM 從新渲染和打補丁以前。
2.你能夠在這個鉤子中進一步地更改狀態,這不會觸發附加的重渲染過程。
3.該鉤子在服務器端渲染期間不被調用。
virtual dom re-render / patch
updated
因爲數據更改致使的虛擬 DOM 從新渲染和打補丁,在這以後會調用該鉤子。當這個鉤子被調用時,組件 DOM 已經更新,因此你如今能夠執行依賴於 DOM 的操做。
然而在大多數狀況下,你應該避免在此期間更改狀態,由於這可能會致使更新無限循環。
vm.$destroyed
beforeDestroy
dsetroyed
還好發佈檢查了一次,發現本身把本身亂七八糟說的都寫進來了。
這篇文章我覺還不錯,跟着本身寫一遍,就會比較瞭解了。全部纔有個人亂七八糟之說。本身理解最重要。
1.實例MVVM對象時,會生成觀察者observe去觀察實例中的data的每個屬性。
2.observe對象會遍歷每個key、value。若是value也是對象,也會經過observe來觀察其中的key、value。
3.在每一個observe對象中會建立一個訂閱者,而後再設置屬性的內置get、set函數。
4.經過內置get函數:在裏面會給data的屬性添加訂閱者。
5.經過內置set函數:會將value值更改,而且若是新的value值是object,那麼則建立一個observe觀察者觀察它。最後會通知訂閱者。
6.compile主要作的事情是解析模板指令,將模板中的變量替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變更,收到通知,更新視圖。
7.觀察者Watcher是observe與compile的橋樑,在解析vue的自定義指令時,會爲每個指令建立一個Watcher觀察者對象。watcher會將每一個指令的當前狀態設定,並添加到每一個data的訂閱者數組中,當data的數值發生改變時,會通知其綁定的訂閱者,觸發每個訂閱者更新函數。
第一點:數據綁定使得 Bug 很難被調試。你看到界面異常了,有多是你 View 的代碼有 Bug,也多是 Model 的代碼有問題。數據綁定使得一個位置的 Bug 被快速傳遞到別的位置,要定位原始出問題的地方就變得不那麼容易了。
第二點:對於過大的項目,數據綁定須要花費更多的內存。
咱們能夠將同一函數定義爲一個 method 而不是一個計算屬性。對於最終的結果,兩種方式確實是相同的。然而,不一樣的是計算屬性是基於它們的依賴進行緩存的。計算屬性只有在它的相關依賴發生改變時纔會從新求值。這就意味着只要 message 尚未發生改變,屢次訪問 reversedMessage 計算屬性會當即返回以前的計算結果,而沒必要再次執行函數。
僅是觀察變量的變化能夠不用watch,直接用計算屬性
可是,當在數據發生變化時,你但願執行開銷較大的操做時,用watch比較有用。
watch能夠限制咱們執行的頻率,在最終結果前,能夠設置中間狀態。計算屬性沒法作到。
state:驅動應用的數據源
view:以聲明方式將state映射到視圖
action:響應在view上的用戶輸入致使的狀態變化。
當咱們的應用遇到多個組件共享狀態時,單向數據流的簡潔性很容易被破壞:
多個視圖依賴於同一狀態。
來自不一樣視圖的行爲須要變動同一狀態。
對於問題一,傳參的方法對於多層嵌套的組件將會很是繁瑣,而且對於兄弟組件間的狀態傳遞無能爲力。對於問題二,咱們常常會採用父子組件直接引用或者經過事件來變動和同步狀態的多份拷貝。以上的這些模式很是脆弱,一般會致使沒法維護的代碼。
把組件的共享狀態抽取出來,以一個全局單例模式管理。
Vuex 是一個專爲Vue.js應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
因爲 Vuex 的狀態存儲是響應式的,從 store 實例中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態
State:狀態
Getters:從State中派生出來的一些狀態
Mutations:更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation,不能直接調用,須要觸發store.commit(type,[payload])。mutation必須時同步函數。異步函數不能捕捉到改變的狀態
Actions:
Action 提交的是 mutation,而不是直接變動狀態
Action 能夠包含任意異步操做。
Action 函數接受一個與 store 實例具備相同方法和屬性的 context 對象。
Action 經過 store.dispatch 方法觸發:store.dispatch('increment')
store.dispatch 能夠處理被觸發的action的回調函數返回的Promise,而且store.dispatch仍舊返回Promise
Modules
因爲使用單一狀態樹,應用的全部狀態會集中到一個比較大的對象。當應用變得很是複雜時,store 對象就有可能變得至關臃腫。
爲了解決以上問題,Vuex 容許咱們將 store 分割成模塊(module)。每一個模塊擁有本身的 state、mutation、action、getter、甚至是嵌套子模塊——從上至下進行一樣方式的分割
單頁面應用(Single Page Application)簡稱SPA,使用SPA構建的應用優勢有用戶體驗好、速度快,內容的改變不須要從新加載整個頁面,避免了沒必要要的跳轉和重複渲染,從而相對減輕了服務器壓力,SPA在WEB移動端應用很是普遍。
單頁應用路由
HTML5在History裏增長了pushState方法,這個方法會將當前的url添加到歷史記錄中,而後修改當前url爲新url。固然這個方法只會修改地址欄的Url顯示,但並不會發出任何請求。所以咱們能夠利用這個方法結合ajax實現單頁面應用SPA,就是PushState+Ajax,人稱Pjax。
location.hash更改了,頁面也不會變化 hashchange hash值的改變也會加入歷史記錄中
總的來講,基於Hash的路由,兼容性更好;基於History API的路由,更加直觀和正式。可是,有一點很大的區別是,基於Hash的路由不須要對服務器作改動,基於History API的路由須要對服務器作一些改造。
pushstate的使用方法:
history.pushState(state, title, url)
state: 能夠聽任意你想放的數據,它將附加到新url上,做爲該頁面信息的一個補充。 該對象可在onpopstate事件中獲取,也可在history對象中獲取。
title: 顧名思義,就是document.title。
url: 新url,也就是你要顯示在地址欄上的url。
history.replaceState(state, title, url)
replaceState方法與pushState大同小異,區別只在於pushState會將當前url添加到歷史記錄,以後再修改url,而replaceState只是修改url,不添加歷史記錄。
window.onpopstate
通常來講,每當url變更時,popstate事件都會被觸發。所以,咱們能夠把它用做瀏覽器的前進後退事件。該事件有一個參數,就是上文pushState方法的第一個參數state。
Pjax能作什麼
Pjax是一個優秀的解決方案,它能夠作:
能夠在頁面切換間平滑過渡,增長Loading動畫。
能夠在各個頁面間傳遞數據,不依賴URL。
能夠選擇性的保留狀態,如音樂網站,切換頁面時不會中止播放歌曲。
全部的標籤均可以用來跳轉,不只僅是a標籤。
避免了公共JS的反覆執行,減小了請求體積,節省流量,加快頁面響應速度。
對SEO也不會有影響,對於不支持HTML5的瀏覽器以及搜索引擎爬蟲,則能夠跳轉真實的頁面。
支持瀏覽器前進和後退按鈕。
Pjax ajax請求,經過html5pushState來修改歷史記錄,若是不支持html5則重寫url 每次修改location的屬性(hash除外),頁面都會以新URL從新加載