線上電影訂票系統 - Vue學習心得

chenzr9527發表於2017-06-12

在最近電影訂票系統的實現中,使用了Vue.js作為前端開發框架。

介紹

Vue是一個極簡的Javascript MVVM框架。它容易上手,便於整合。而且,它對於Web元件化開發的思考和設計,使其完全能夠為複雜的SPA(單頁應用)提供驅動。

這裡寫圖片描述

與AngularJS1.x對比

在此之前,我主要都是使用AngularJs1.x作為前端框架進行開發。Angular是一個Javascript MVM框架,它也是Vue早起開發的靈感來源。但是,在我的使用過程中,發現Angular1.x還是存在著不少問題,而Vue就很好的解決了這些問題。個人認為主要問題有:

  1. API複雜。對於新手來說,需要投入大量的時間去熟悉並理解相關API。
  2. 不夠靈活,模組化困難。在任何時候,都要遵循Angular制定的規則,這不是一個靈活的解決方案。
  3. 雙向繫結。由於Angular使用雙向繫結,導致應用中的資料流模糊複雜。在具體的實現過程中,常常會困在雙向繫結的問題上。
  4. 指令與元件的區分不明顯。Angular的指令中除了封裝DOM操作,有時還會有檢視和資料邏輯。但嚴格來說,指令應該只是封裝DOM操作,元件才會有自己的檢視和資料邏輯,並作為一個獨立單元。
  5. 效能。Angular1.x的效能問題是被許多人詬病已久的了,也是我個人棄用Angular1.x的主要原因。在 Angular 1 中,當 watcher 越來越多時會變得越來越慢,因為作用域內的每一次變化,所有 watcher 都要重新計算。並且,如果一些 watcher 觸發另一個更新,髒檢查迴圈(digest cycle)可能要執行多次。Angular 使用者常常要使用深奧的技術,以解決髒檢查迴圈的問題。有時沒有簡單的辦法來優化有大量 watcher 的作用域。

而以上問題,在Vue中已經得到了不錯的解決,尤其是效能問題。Vue使用基於依賴追蹤的觀察系統並且非同步佇列更新,所有的資料變化都是獨立觸發,除非它們之間有明確的依賴關係。

MVVM

由於專案使用Vue框架,天然的就是一個MVVM模型,這裡說明一下為什麼不使用MVC模型以及為什麼Vue是MVVM模型。

隨著現代網頁複雜度的增加,View 層所做的事,就不僅僅是簡單的資料展示了,它不僅要管理複雜的資料狀態,還要處理移動裝置上各種操作行為等等。因此,前端也需要工程化,也需要一個類似於MVC 的框架來管理這些複雜的邏輯,使開發更加高效
一個標準的Web應用程式由這三部分組成:

View:UI佈局,展示資料
Model:管理資料
Controller :響應使用者操作,並將Model更新大片View上

這種 MVC 架構模式對於簡單的應用來看起是可行的,也符合軟體架構的分層思想。但實際上,隨著H5 的不斷髮展,人們更希望使用H5 開發的應用能和Native 媲美,或者接近於原生App 的體驗效果,於是前端應用的複雜程度已不同往日。這時前端開發就暴露出了三個痛點問題:

1.開發者在程式碼中大量呼叫相同的 DOM API, 處理繁瑣 ,操作冗餘,使得程式碼難以維護。
2.大量的DOM 操作使頁面渲染效能降低,載入速度變慢,影響使用者體驗。
3.當 Model 頻繁發生變化,開發者需要主動更新到View ;當使用者的操作導致 Model 發生變化,開發者同樣需要將變化的資料同步到Model 中,這樣的工作不僅繁瑣,而且很難維護複雜多變的資料狀態。

於是MVVM模型誕生了,MVVM 由Model, View, ViewModel三部分構成

Model層代表資料模型,也可以在Model中定義資料修改和操作的業務邏輯;View 代表UI 元件,它負責將資料模型轉化成UI 展現出來;ViewModel 是一個同步View 和 Model的物件。

在MVVM架構下,View 和 Model 之間並沒有直接的聯絡,而是通過ViewModel進行互動,Model 和 ViewModel 之間的互動是雙向的, 因此View 資料的變化會同步到Model中,而Model 資料的變化也會立即反應到View 上。

ViewModel 通過雙向資料繫結把 View 層和 Model 層連線了起來,而View 和 Model 之間的同步工作完全是自動的,無需人為干涉,因此開發者只需關注業務邏輯,不需要手動操作DOM, 不需要關注資料狀態的同步問題,複雜的資料狀態維護完全由MVVM來統一管理。

既然專案使用Vue,那就說說其中MVVM實現的一些細節吧。
Vue.js 是採用 Object.defineProperty 的 getter 和 setter,並結合觀察者模式來實現資料繫結的。當把一個普通 Javascript 物件傳給 Vue 例項來作為它的 data 選項時,Vue 將遍歷它的屬性,用 Object.defineProperty 將它們轉為 getter/setter。使用者看不到 getter/setter,但是在內部它們讓 Vue 追蹤依賴,在屬性被訪問和修改時通知變化。

這裡寫圖片描述

Observer 資料監聽器,能夠對資料物件的所有屬性進行監聽,如有變動可拿到最新值並通知訂閱者,內部採用Object.defineProperty的getter和setter來實現。
Compile 指令解析器,它的作用對每個元素節點的指令進行掃描和解析,根據指令模板替換資料,以及繫結相應的更新函式。
Watcher 訂閱者, 作為連線 Observer 和 Compile 的橋樑,能夠訂閱並收到每個屬性變動的通知,執行指令繫結的相應回撥函式。
Dep 訊息訂閱器,內部維護了一個陣列,用來收集訂閱者(Watcher),資料變動觸發notify 函式,再呼叫訂閱者的 update 方法。

從圖中可以看出,當執行 new Vue() 時,Vue 就進入了初始化階段,一方面Vue 會遍歷 data 選項中的屬性,並用 Object.defineProperty 將它們轉為 getter/setter,實現資料變化監聽功能;另一方面,Vue 的指令編譯器Compile 對元素節點的指令進行掃描和解析,初始化檢視,並訂閱Watcher 來更新檢視, 此時Wather 會將自己新增到訊息訂閱器中(Dep),初始化完畢。
當資料發生變化時,Observer 中的 setter 方法被觸發,setter 會立即呼叫Dep.notify(),Dep 開始遍歷所有的訂閱者,並呼叫訂閱者的 update 方法,訂閱者收到通知後對檢視進行相應的更新。

相關文章