Vue 2.0已經正式發佈好長時間了。想找一個Vue.js Vuex vue-route的學習項目來練手。作個電商App吧,上gitHub搜索了一下搜到一大堆,不過基本上都不是使用單文件組件開發的,更不用說基於Vue.js全家桶了。本項目不同的地方在於使用vue-cli + webpack template人開發模式,還要求Web和移動端一體化,也就是響應式Web,並且不能Mock數據,額外須要有一個提供restful web api的後端應用。哈哈,就是搞全棧呀。css
採用的是Express + mLab + Mongoose的技術棧。http模塊加上Express自帶路由利用中間件思想能夠很方便地基於Node開發提供restful web api的Web應用。考慮到方便在線演示部署,數據庫選用了MongoDB的雲服務mLab。固然,提交數據到數據庫時通常要選用便捷操做的對象模型工具(ORM)。在node.js和MongoDB數據庫環境下,Mongoose做爲就是不二之選了。具體實現請看https://github.com/szriafan/v...。另外,我將node.js代碼免費託管到了https://heroku.com/(主機數據庫都免費,爽呀)。如今直接在瀏覽器訪問https://vue-shop-api.herokuap...就能夠返回商品列表所須要的數據了,固然更好的選擇是使用Postman之類的HTTP請求調試工具。前端
若是咱們不瞭解後端和mLab,只要在ations.js手動將axios的baseURL改成https://vue-shop-api.herokuap...就能夠了。或者對mLab數據API足夠了解,也能夠不寫Node.js應用的。爲了方便你們全面學習測試,建議你們最好訪問本地的restful應用。vue
注意,訪問不一樣端口的本地服務或不一樣域名的遠程服務都有跨域問題,使用CORS能夠很好解決這個問題。node
app.all('/*', function(req, res, next) { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-type,Accept,X-Access-Token,X-Key'); if (req.method == 'OPTIONS') { res.status(200).end(); } else { next(); } });
好了,接下來集中精力開發前端。webpack
一、運行vue-cli + webpack template就獲得了一個Vue.js Vuex vue-route全家桶腳手架項目。咱們要完成兩個部分:前臺展現和後臺管理。ios
二、前臺展現有兩個功能:展現商品列表和詳情的功能、添加商品到購物車的功能。商品列表和詳情頁面都能添加商品到購物車,商品列表頁只能經過點擊按鈕一次添加一件商品,但詳情頁面能夠經過+-按鈕或文本框輸入來改變商品數量(不能大於庫存),再經過點擊添加按鈕一次性添加多件商品。購物車列表頁也能夠能夠經過+-按鈕或文本框輸入來改變商品數量,與詳情頁面操做不同的是購物車列表頁改變商品數量時會同步保存數據,即便從新刷新頁面或關閉瀏覽器,都會顯示已保存的數據。而但詳情頁面若是改變數量後沒有按添加按鈕就不會添加商品到購物車。git
三、後臺管理有的功能就是實現商品及品牌的CRUD操做。在新增修改商品時,會經過下拉框選擇品牌,而下拉框用品牌數據來填充的。所以商品數據是依賴品牌數據的,所以後臺管理時先應該添加商品數據。github
四、明確了上述需求後,先看到一下最終效果吧。源碼在這裏下載。web
五、咱們來講一說具體實現。SPA通常都有路由,複雜Vue.js應用頁面之間的導航都要用到vue-route。vue-rout使用JavaScript動態初始化配置全局對象,將組件(components)映射到路由(routes),而後告訴vue-router在哪裏渲染它們。經過注入路由器,咱們還能夠在任何組件內經過this.$router訪問路由器,也能夠經過 this.$route訪問當前路由。好比說當添加或修改商品成功後咱們就是經過this.$router回到商品列表頁的。模板中的組件讓用戶在具備路由功能的應用中(點擊)導航,其中to表示目標路由的連接,這個值能夠是一個字符串或者是描述目標位置的對象,對應路由配置對象的path屬性值或name對象。好比說App模板中的組件to屬性設置爲{name: 'Home'},經過路由映射會導航到Home組件所在的頁面。建議設置to的屬性值爲name對象,由於這個對象通常不多改動,而首頁連接設置成'/',一樣是由於這個值不多改動。另外首頁連接還得添加exact屬性來精確匹配連接,你們都知道,其它path值確定包含/,不設置該屬性會形成導航連接樣式都添加激活連接類名。vue-router
六、以下面的文件路徑樹所示,本項目使用了大量的嵌套單文件組件,下面的項目components和pages文件夾包含了大量的單文件組件。嵌套單文件組件提升了代碼複用性,讓分模塊團隊開發變得容易,這對於開發大型Vue.js應用尤其重要。不過Vue組件使用單向數據流向下進行組件數據通訊,大量的會讓代碼難以維護,此時咱們就應該考慮用Vuex來實現多個組件共享狀態。
├─components │ ├─cart │ │ CartControl.vue │ │ CartItem.vue │ ├─common │ │ Loading.vue │ ├─manufacturer │ │ ManufacturerForm.vue │ └─product │ AddToCartButton.vue │ ProductDetails.vue │ ProductForm.vue │ ProductItem.vue │ ProductList.vue ├─pages │ │ Cart.vue │ │ Details.vue │ │ Home.vue │ └─admin │ │ Index.vue │ ├─manufacturer │ │ Edit.vue │ │ Manufacturers.vue │ │ New.vue │ └─product │ Edit.vue │ New.vue │ Products.vue
以下面的文件路徑樹所示,本項目Vuex代碼集中store文件夾中。Vuex應用的核心store(倉庫),包含應用中大部分的狀態,如商品、品牌、購物車數組, 咱們是在index.js中定義的; Action函數接受一個與store實例具備相同方法和屬性的context對象,能夠包含任意異步操做,如對後臺數據訪問商品和品牌數據的異步操做,咱們是在action.js中定義的;Vuex中的Mutation很是相似於事件:每一個Mutation都有一個字符串的事件類型 (type) 和一個回調函數(handler)。如對異步回調函數和添加商品到購物車時的同步函數,咱們是在mutations.js中定義的;Vuex容許定義getter從store中的state中派生出一些狀態(計算屬性),如從商品和品牌數組狀態中派生出根據id查詢到的狀態,咱們是在getters.js中定義的;另外,咱們的mutation-types.js中使用常量替代mutation事件類型以方便多人協做。
├─store │ actions.js │ getters.js │ index.js │ mutation-types.js │ mutations.js
在任意組件中訪問store的計算屬性時可以使用mapState和mapGetters輔助函數,分發Action、Mutation時使用mapAction、mapMutation輔助函數。它們本質是都是語法糖,將store中的state、getter映射到局部計算屬性,或將mutations和actions映射到局部方法,從而避免使用this.$store的方式來訪問相應的函數。固然,並非全部狀況下都能使用輔助函數,如created生命週期鉤子函數中或條件語句中。
請注意,使用Vuex並不意味着咱們須要將全部的狀態放入Vuex。若是有些狀態嚴格屬於單個組件,最好仍是做爲組件的局部狀態。咱們應該根據應用開發須要進行權衡和肯定。如CartControl組件中的count狀態和每一個cart組件綁定不能單例化,所以不須要用放入Vuex來管理。
七、以下面的文件路徑樹所示,本項目plugins文件夾中有兩個插件。插件會爲Vue.js添加全局功能,本質上就是封裝更好,複用性更強的組件,Vuex和vue-route就是這樣兩個優秀的插件。若是咱們想在任意組件中彈出模態框和信息提示、控制加載動畫等,怎麼辦?每一個組件都加一個布爾控制變量確定致使代碼冗餘難以維護。用Vuex集中在根組件中處理也好不到哪裏去,由於要寫不少代碼來判斷事件類型。因此咱們得本身開發插件,感興趣的話可參考vue-dialog和vue-toast的代碼自行開發一個Loading插件。那樣就能夠在任意組件中控制加載動畫了。
├─plugins │ ├─vue-dialog │ │ │ index.js │ │ │ VueDialog.vue │ │ └─themes │ │ default.css │ │ ios.css │ └─vue-toast │ │ index.js │ └─components │ Notification.vue │ VueToast.vue
八、當咱們build好代碼,在IE或手機自帶的Android瀏覽器上運行時,發現添加商品到購物車的功能用不了。報錯:Vuex requires a Promise polyfill in this browser,原來Vuex依賴Promise。若是瀏覽器並無實現Promise,那麼可使用一個 polyfill的庫,例如babel-polyfill。
第一步: 安裝
npm install --save babel-polyfill
第二步:在webpack.config.js文件中,將entry的代碼改成以下:
entry: { app: ["babel-polyfill", "./src/main.js"] }
或者將下列代碼添加到使用Vuex以前的一個地方:
import 'babel-polyfill'
Vue.js devtools是一個很好的測試Vue.js應用的工具,對Vuex也支持得很好,值得擁有。