MonkeyEye電影售票系統--前端技術要點總結
案例來源:SYSU SE305 課程大作業。網際網路售票軟體是比較常見的軟體系統。通常由多個零售系統和多個供給系統系統。 機票、酒店房間、電影票似乎是風馬牛大相關的系統,但它們之間存在極其相似的業務模型。 以電影票為例,格瓦拉、蜘蛛網、騰訊等等都做類似的電影票分銷、推廣業務,但票是由各大院線排期提供的。 分銷-院線-影院形成了一個完整的生態體系。 本課程以大家熟悉的訂票為例,學習分析、設計、開發的方法。
我所在的小組做的是一個叫做MonkeyEye的專案,實現一個簡單的電影購票系統,並在專案完成過程中學習系統分析與設計,學習UML建模等技能。本系列文章將會以此專案為案例,總結整個專案的設計、建模與開發過程。
關於專案的功能和專案結構的介紹請檢視上一篇部落格。
【前端技術框架】
- vue
- vue-router
- vuex
- vue-material
- axios
【構建工具】
- webpack
一、預編譯語言(預處理語言)
專案中使用pug預處理語言來編寫前端的HTML,非常簡潔和方便。用pug來編寫HTML結構,編寫完後經過處理器處理之後會變成標準的HTML,程式碼上少了很多閉合標籤顯得更加簡潔,而且結構也很清晰。類名和id的寫法或者其他HTML標籤屬性的寫法也很簡潔。
至於編寫樣式的CSS,則是使用了sass。縮排巢狀選擇器,不用打花括號等特性用起來都特別爽。
pug和sass支援的功能還有很多,例如pug的mixin,sass的模組化樣式等等,此處不作介紹,官方文件已經有了詳細的描述。
二、Vue 元件化
Vue支援前端元件化,可以將前端介面或者介面中的某些模組劃分為元件,每個元件可以使用一個Vue檔案來實現,也可以將程式碼分散在html/css/js檔案中。我們這裡都是採取Vue檔案的方式,每個Vue檔案實現一個元件。Vue檔案通過template、script、style三種標籤將HTML、js、css三種類型的程式碼進行劃分,三种放在同一個檔案裡,根據元件定位到程式碼,很方便進行程式碼管理。通過在標籤中指定lang屬性,可以指定預編譯語言。
專案將每個介面抽象為一個Vue元件來進行開發和管理,雖然每個介面上可以根據介面內容繼續細分元件,例如頂欄元件、表單元件、標籤頁元件。但是由於本應用的介面並不是非常複雜,而且每個頁面的業務邏輯都是連貫的,我們認為一個元件包含一個介面這種把握剛剛好,一個介面元件的HTML結構、js邏輯和css樣式全部程式碼加起來一般在100到200+行之間,加上有template、script、style三個標籤進一步將程式碼分塊,每一個Vue檔案裡面的每一大塊程式碼(html/js/css)的程式碼量基本都在100行以內,可讀性還是很強的,很有利於進行開發和維護。
三、前端路由
由於本應用是一個單頁應用,所以需要配置前端的路由。利用vue-router庫來實現前端路由控制。下面是部分程式碼截圖,主要配置URL路徑和與之繫結的元件,當瀏覽器位址列中的路由變成相應的路徑時候,就跟渲染與之繫結的元件,然後更新介面內容。
由於部分介面需要許可權才能進入,例如,需要登入後才能檢視和修改使用者資訊、需要登入後才能下單購票。這裡可以利用vue-router提供的鉤子(hook)進行許可權控制,實現方式如下。
首先在配置路由的時候,給需要許可權的介面加一個meta欄位,即元資料,裡面的requireAuth設定為true,表示這個介面需要許可權才能進入(這裡的許可權指的是已登入使用者才具備的許可權)。
vue-router提供了一個beforeEach鉤子,如果給這個鉤子繫結一個處理函式,那麼在進入任何一個路由之前,都會先呼叫這個鉤子所繫結的處理函式。在處理函式中,引數to表示要進入的路由,通過檢查要進入的路由的元資料便可以知道該路由是否需要許可權。如果需要許可權則檢查store裡面的使用者狀態(後面將介紹store,使用者的登入狀態會儲存在store中)。如果使用者未登入則將它重定向到登入介面。
四、非同步通訊
前端介面經常需要跟伺服器進行通訊,傳送GET、POST等HTTP請求獲取資料或者提交資料。為了提高使用者體驗,不阻塞頁面流程,一般都是採取ajax方式來非同步傳送請求。本專案使用了axios這個庫來發送HTTP請求。如官方文件介紹,“Promise based HTTP client for the browser and node.js”,這個庫有一個很大的優點,基於Promise。其次,他還封裝好了多種HTTP方法,直接通過get、post、delete等API即可傳送一個對應HTTP方法的請求。promise的寫法使得程式碼可以通過.then和.catch的方式來處理非同步請求得到的結果或者處理異常,相對於巢狀回撥函式的方式,程式碼更加簡潔優雅。
五、資料狀態管理
應用的資料狀態管理使用的是vuex這個庫。下面先簡單總結一下vuex的思想。Vue使用Vuex實現狀態管理,從概念上來看Vuex遵從Flux,即將應用的資料視為狀態,放在一個全域性的store裡面進行管理,所有元件共享同一個store的資料,元件無法直接對資料進行修改,要更新store裡面的資料需要發起一個action才能對store裡面的資料進行更新,當store裡面的資料更新之後會反饋所有使用到store裡面的資料的元件,使得其他元件也進行更新。
Vuex基本按照Flux的概念來,唯一不同之處就是Vuex除了action之外還有mutation。mutation對store裡面的資料進行同步更新,所有操作都必須是同步的。當需要非同步操作的時候就才會用到action,在action裡面進行非同步操作之後再通過mutation來對store裡面的資料進行更新。
使用vuex可以更好地管理應用的資料和介面,下面以電影資料為例子進行說明。電影的資料包括正在熱映和即將上映的電影列表以及對應的推薦列表,將這些資料存放在store的state裡面,電影列表介面和電影詳情介面都會共享這一份資料,這份資料改變的時候,兩個介面的內容都會更新。除了資料是存在全域性的單例可以節省記憶體之外,介面的更新同步也變得非常容易。
下面則是電影模組的actions部分,可以將所有與服務端API通訊的非同步操作介面封裝在這裡,介面不會分散在各個介面的程式碼中,非常方便我們對介面進行管理和調整。
最後則是mutations,這裡面封裝了對資料進行同步修改的程式碼,在派發action獲取資料之後,如果需要對資料進行分類,例如獲取全部電影列表然後分成正在熱映和即將上映兩類,都可以將相應的程式碼封裝在這裡。
六、資料狀態模組化
vuex資料狀態管理,可以理解為是把整個應用的資料抽象出來,形成一棵狀態樹。這棵狀態樹位於一個全域性的位置並且是單例的,所有介面都引用這棵樹上的某一部分的資料。但是,當應用介面較多,資料模型變得複雜的時候,這棵狀態樹也會變得很龐大。如果將所有程式碼都放在一個位置,那麼將很不利於程式碼的管理。所以,可以根據資料模型來對這棵樹進行劃分,變成多棵子樹,每棵子樹代表一個數據模型,並且將對應的API介面和操作封裝到一起。這就是vuex的modules。
我們根據應用的資料模型將資料分為以下幾個module,然後在頂層將所有module組裝起來形成完整的資料狀態樹。
每個module裡面都有相應的state、mutations、actions,將各模組的資料變數、介面等都封裝到一起。這樣每個module的程式碼都是完整的,管理起來很方便。並且每個module的程式碼量都很小,可讀性可維護性大大提高。
七、HTTP代理與前後端分離
這個專案是一個前端開發專案,因此沒有服務端的程式碼。前端的程式碼和服務端的程式碼執行在不同的位置。例如,開發的時候,服務端可能執行在伺服器上,而前端的程式碼是跑一個本地靜態伺服器(dev-server)來提供。靜態伺服器只能提供HTML/JS/CSS/圖片等資源給瀏覽器使用,但是應用中還有不少地方需要訪問伺服器的API介面,這裡可以通過HTTP代理來實現。
前端傳送/api請求到dev-server,通過配置HTTP代理,dev-server將這個/api請求代理到真正的API服務端,等拿到資料後再給回前端。這樣,除了可以解決訪問API的問題,還可以讓我們不用去處理跨域的問題,非常方便。
HTTP代理使用http-proxy-middleware中介軟體來實現,dev-server中的程式碼已經寫好,只需要在config中配置一下代理規則即可。寫好真正的API伺服器和靜態資源伺服器的地址,然後在代理規則表中寫好代理規則。例如下面圖中的/api,表示所有/api開頭的請求都會被代理到apiServer。這時候在應用裡面請求localhost:8080/api/movies的效果就跟請求[apiServer]/api/movies的效果時一樣的。
dev-server在這裡充當了代理的角色,前端並不知道代理的存在,響應報文裡面的伺服器主機依然是localhost,所以也不會造成前端的跨域問題。
有了代理之後,前後端分離的實踐也變得容易起來。後端和前端可以分離開發,也不用管對方寫了什麼程式碼,甚至不需要執行對方的程式碼。後端把程式碼寫好部署好介面,前端只要知道伺服器地址即可。前後端之間的互動通過RESTful API。