若是在簡歷上寫「XX電商系統」的實現,其實第一直覺是這我的必定是從培訓班出來的。而咱們「項目管理」課程正好就是作一個小型電商網站。開發時長一個月左右,包含買家端、賣家端、管理員端,雖然業務邏輯比較常見,可是此次開發仍有收穫,最重要的一點收穫就是 對Vuex有了真正的實踐和認識。 因此,本文大部分介紹Vuex在該項目上的實踐以及所踩的坑,另外的部分則是項目中一些其餘要點的總結。html
前面的幾回項目開發,拿到後端接口和需求以後,會按照如下的方式去實現功能:vue
Promise
的then
方法裏進行數據更新或者作更多的業務處理。第一、二、3步基本上是沒太大問題的,問題就出在第4步,其結果是致使一個Vue文件愈來愈大,到後面一個複雜的頁面vue文件將會包含以下內容:webpack
data
裏大量的數據字段,有控制是否展現元素的
,渲染用數據
,用於"上鎖"的變量
等。created
或mounted
裏包含了大量的請求
和回調處理
。template
裏使用的組件的屬性內,綁定了大量的props
。最後的結果就是vue文件變得臃腫。ios
文件越長,可讀難度會提升,可維護性會下降。web
誰也不喜歡看一個包含了邏輯處理、界面處理、數據處理的冗雜代碼文件。ajax
因此,爲了解決上述問題,引入 Vuex
是很是必要的。vuex
其實,以前也一直在使用Vuex,不過用的目的僅僅是爲了
「保存一點數據可以全局使用」
而已,根本沒有深刻使用Action
,Getters
,Mutations
等。 本文關於Vuex不會過多介紹其原理以及好處,主要關注實踐以及使用心得,Vuex介紹或入門請移步官方文檔。編程
筆者所作的,是將關於數據請求和更新,基本都放到了Vuex
裏,讓Vuex
成爲了整個項目的「數據集散中心」
,而vue
組件裏,僅僅是進行事件調度(dispatch)
和綁定來自Vuex的數據
。axios
咱們以商品詳情頁面舉例,其包含以下的功能:後端
如圖所示:
若是咱們不使用Vuex,代碼的結構可能以下:
<template> <template> <script> export default { data() { detail: { name: '', shopId: '', id: '', pic: '', description: '', price: '', updateTime: '', categoryId: '', stock: 0, createTime: '', attributeList: {}, collectId: 0, }, // 一大堆商品的字段數據 【MARK】 }, created(){ this.$http.get('/product/:id') .then() // 以及一端更新其餘數據的請求 【MARK】 }, methods(){ clickCart(){ this.$http.get('xxx') .then('xxx') this.$emit('xxx'); // 與上層組件通訊更新購物車的紅點 } // 一堆用戶事件的觸發方法,每一個方法內都是一堆http請求和回調處理 【MARK】 }, computed:{ // 一些基於商品數據判斷狀態的數據 【MARK】 } } </script> <style> <!-- 忽略相關樣式代碼--> <style> 複製代碼
若是按照上述的方式來寫,雖然能夠保證關於這個頁面的邏輯處理都保留在這個vue文件內,可是卻顯得十分臃腫,若是後續要加更多的功能抑或是修改,其須要讀的代碼可能更多。
因此,以上代碼示例中的被【MARK】
標記的部分,將是Vuex
能夠優化的。 最後的代碼以下圖所示:
代碼的可讀性提升了很多:
data
裏不含任何業務數據字段,僅保留控制頁面的字段【觸發事件】-【回調】
這樣簡單的邏輯。關於數據處理的代碼,所有封裝到了Vuex
上了:
咱們在Vuex層,不只請求了數據,同時對返回的數據作了判斷以及不一樣的邏輯處理,同時設置Getters
使的頁面可以基於Getters
提供的數據作各種二元判斷
。
Vuex層帶來了以下的好處:
Actions
,就這個例子,我只要寫了一次加入購物車
的函數,在各個頁面均可以使用了。添加商品進購物車的同時更新商品數據並更新購物車數據
,這樣須要寫三次HTTP
請求的業務邏輯,此時只須要將三個Actions進行組合便可,而這幾個Actions還能夠在其餘地方單獨使用。數據倉庫
帶來的好處就是減小了數據層層傳遞的操做,按照之前的編碼習慣,我會大量使用$emit
和props
來實現父子或兄弟組件通訊,而如今,只須要在組件中觸發相應的事件綁定相應的數據便可。直觀體驗來講,完全使用Vuex
後,編碼思路清晰很多,由於寫完總體的一個功能須要2~3天,而Vuex對於「間斷性編程」
很是有幫助,可以迅速撿起上一次開發的進度。
使用Vuex以後就是按照以下的步驟進行開發了:
(第一、二、3步不變,如前文) 4.構建Vuex的Store模型,定義所需的方法。 5.編寫組件並綁定在Vuex上的相關數據和方法。 6.編寫觸發dispatch
後的回調。
使用Vuex
存在必定的規範,在官網上已經陳列了諸如表單處理
,測試
,項目結構
的規範,而下面的一些原則僅僅是筆者的一些經驗之談,不必定正確,有所幫助即是最好的。
dispatch
的回調裏進行處理。最初個人設計是在Action
請求數據以後同時也負責全部的跳轉邏輯
和彈窗邏輯
,不過,這樣作又讓視圖層
和數據層
耦合了,使得我抽象出來的Action
的複用性變得極差,同時,在vue
文件看到關於視圖層的處理纔算是比較正常的編寫邏輯。
mutation
和action
儘可能保持只作一件事原則。正如上一條原則中提到的要提升action
的複用性,那麼就要保證須要複用的action
只作一個功能,如更新A數據
和更新B數據
不要直接融合成一個action
,而是分別定義兩個action
,並經過組合的方式來實現一個更復雜的功能,有點相似精簡指令集的思想。
如:
actions:{ updateA(){}, // A 可能在其餘地方被單獨使用 updateB(){}, // B 可能在其餘地方被單獨使用 updateAandB({dispatch}){ dispatch("updateA"); dispatch("updateB"); }, // 同時觸發 A B 的複雜action } 複製代碼
爲了讓dispatch
函數擁有Promise風格
的處理回調的能力,可讓action
的返回值做爲一個Promise
對象,如:
// store.js actions:{ updateA(){ return Promise.resolve() } } 複製代碼
在組件內就可使用.then
:
... created(){ this.$store.dispatch('updateA') .then(() => { ... }) } ... 複製代碼
而Vuex
通常建議在actions
進行異步操做,因此爲了讓代碼更加優雅,能夠用AA
以下編寫:
// store.js actions:{ async updateA(){ const result = await ajax('/**/**'); if(result){ return Promise.resolve() } } } 複製代碼
因此,在實踐中的代碼如圖:
通常使用vuex,會根據實體或者頁面來拆分state造成module,一個module裏包含其所需的全部actions,states,mutation
等。如電商裏,通常有商品
,訂單
,用戶
這幾個實體能夠拆成module,拆分出來以後如圖:
拆分的好處是更加獨立直觀了,壞處是若是不使用命名空間,可能形成actions
,mutations
衝突,正好Vuex
也提供namespace
的配置,參考官方文檔便可。
雖然總結到了原則裏,不過此次並無使用namespace
,算是此次比較大的不足了,解決的辦法是」手動namespace「,如圖:
將actions
的方法名前綴加上該實體名用於區分不一樣的方法,實在是比較拙劣的手段了。
狀況發生在獲取到異步數據以後的代碼,通常以下這段代碼會大量重複:
if (result.code){ return Promise.resolve(data); } return Promise.reject(msg); 複製代碼
雖然不算多,可是這邏輯仍然有可抽象出來的可能性,下次打算在RootState
裏添加一個action
,用於處理這樣的後端返回數據,指望結果以下:
actions: { parseResult({}, result){ if (result.code){ return Promise.resolve(data); } return Promise.reject(msg); }, async getA({dispatch}){ const result = await http.get('xx/xx'); return dispatch('parseResult', result); // One line , it's clean } } 複製代碼
3.0 基本在配置上作到極簡化
了。好久沒開發Vue
的項目了,記得上一個Vue
項目裏,仍然有一大堆xxx.congfig.js
,而如今,基本集成到了CLI內部了,經過一個vue.config.js
可知足大部分開發需求。本項目配置以下圖:
比之前的配置更加直觀了,更多請參考:cli.vuejs.org/zh/,至於插件機制,本次開發未用上,只是在安裝第三方包的時候能夠用vue add
了,有GUI能夠查看安裝了哪些插件。
Vue.use 和 Vue.install
使用的地方彙總到plugins
目錄下本項目是一個多頁面應用,總共有3個Vue實例,因此但願可以按需注入想要的第三方依賴如axios
,qrcode
,lazyload
等一些工具庫或第三方組件。因而都將其彙總到plugins
目錄下了,以下圖:
這樣封裝的好處是,我能夠對每一個Vue實例按需導入第三方依賴,一行import就能夠,以下圖:
一個大型的web app 打包壓縮後都不超過500kb,因此就以此做爲Benchmark
來優化該項目打包後的大小,按需引入
第三方依賴(特別是Element
和lodash
)減小了很多項目體積。不過最主要的仍是得學會用webpack analyse tool
來分析。
總之,本次項目主要是刷新了對Vuex
的認知,其可以讓咱們編寫的vue
組件可讀性和可維護性更高。同時,也可以讓數據更新這塊的代碼複用性更高。經過Vuex
來構建一個中心化的數據集散中心
還能讓開發的思路更順暢,值得學習。
參考: