使用Vue.js和Vuex實現購物車場景

vue-demo-collection已升級爲2.x版本,
本文是基於vue全家桶1.x和webpack1.x寫的demo,
查看2.x源碼移步shopping-cart2.x
查看1.x和2.x代碼對比移步shopping-cart源碼比較javascript

本文是上篇文章的序章,一直想有機會再次實踐下Vuex。寫下這篇總結,See Demohtml

什麼是Vuex?

Flux-inspired Application Architecture for Vue.jsvue

Vuex其實是類Flux的數據管理架構。它主要幫咱們更好的組織代碼,更好的讓Vue中的狀態更好的經過狀態管理維護起來。在實際項目運用中咱們須要對組件的 組件本地狀態(component local state)應用層級狀態(application level state) 進行區分。
Vuex的做用就是聚集應用層級的狀態到一處,方便管理。java

說狀態其實有些同窗可能不太理解,那麼在剛上手Vue的時候作過的例子中,一個Vue實例中都會有data,那麼這個data中保存的屬性其實就是能夠理解爲狀態。webpack

試想這樣的場景,好比一個Vue根實例下面有一個根組件名爲App.vue,它下面有兩個子組件A.vueB.vue,父組件和子組件之間使用Props通信是沒問題的,經過綁定Props輕鬆的實現。git

可是若是咱們須要A.vue組件和B.vue組件之間通信呢?由於組件實例的做用域是孤立的,它們之間是不能直接通信的。那麼只能藉助共有的父組件經過自定義事件實現。github

A組件想要和B組件通信每每是這樣的:web

  • A小弟說:「報告老大,可否幫我捎個信給你的小弟B組件?」,它須要dispatch一個事件給Appvuex

  • App老大說:「包在我身上」,它須要監聽A組件dispatch的事件,同時須要broadcast一個事件給B組件。架構

  • B小弟說:「信息已收到。」,它須要on監聽App組件分發的事件。

圖片描述

這只是一條通信路徑,那麼若是父組件下有多個子組件,子組件之間通信的路徑就會變的很繁瑣,父組件須要監聽大量的事件,還須要負責分發給不一樣的子組件。很顯然這並非咱們想要的組件化開發體驗。

Vuex就是爲了解決這一問題出現的。

Vuex是如何工做的?

下面這張圖很好的詮釋了Vuex和組件之間的通信關係。

圖片描述

這張圖描述的很棒,完整的數據流閉環,整個應用的數據流是單向的。對咱們理解Vuex和Vue的組件間的通信關係頗有幫助。

須要掌握的:

  • 用戶在組件中的輸入操做觸發 action 調用;

  • Actions 經過分發 mutations 來修改 store 實例的狀態;

  • Store 實例的狀態變化反過來又經過 getters 被組件獲知。


使用Vuex

進入正題。一個購物車咱們都須要完成哪些功能?先看看Demo的樣子。

圖片描述

需求分析

  • 顯示商品的文字描述、圖片描述、類型、價格信息;

  • 改變商品顏色的時候圖片切換;

  • 改變商品類型的時候價格變化;

  • 加入/移除購物車;

  • 購物車中商品數量統計以及總價的統計;

目錄結構

我參考了中型到大型項目的目錄結構說明構建的購物車,把Vuex相關的代碼分割到多個模塊(module),我認爲這樣更清晰明瞭。

圖片描述

配置vuex

每個 Vuex 應用的核心就是 store(倉庫)。"store" 基本上就是一個容器,它包含着你應用裏大部分的 狀態(即 state),咱們建立store.js導入各個模塊的初始狀態和 mutations。

store.js

// vuex/store.js
import Vue from 'vue'
import Vuex from 'vuex'
import index from './modules/index'

Vue.use(Vuex)

export default new Vuex.Store({
  // 組合各個模塊
  modules: {
    index
  }
})

經過在根實例中註冊 store 選項,該 store 實例會注入到根組件下的全部子組件中。

App.vue

import Nav from './components/Nav.vue'
import store from './vuex/store'

export default {
  name: 'App',

  store,

  data() {
    return {
      // note: changing this line won't causes changes
      // with hot-reload because the reloaded component
      // preserves its current state and we are modifying
      // its initial state.
    }
  },

  components: {
    'cart-nav': Nav
  }
}

組件中經過getters讀取狀態

配合ES6的箭頭函數真的很簡潔的。

vuex: {
  getters: {
    iPhone6S: ({ index }) => index.iPhone6S
  }
}

理解數據流閉環

好比咱們須要根據更改外觀來改變商品的圖片這樣的需求。咱們該怎樣完成一個數據流閉環呢?

從組件開始:

一(Vue components)、首先子組件Index.vue須要一個點擊事件來觸發action:

Index.vue

<li v-for="styleUrl in iPhone6S.style"
    @click="changeStyle($key, styleUrl)"
    :class="{active: iPhone6S.activeStyleUrl == styleUrl}"><span v-text="$key"></span></li>

二(Actions)、聲明一個名爲changeStyle的action

actions.js

export const changeStyle = makeAction('CHANGE_STYLE')

並分發mutations,用統一的函數處理。

function makeAction (type) {
  return ({ dispatch }, ...args) => dispatch(type, ...args)
}

三(Mutations)、咱們用常量聲明mutation,並把它放到單獨的地方。mutation常量習慣性大寫的,區分於actions。

mutation-types.js

export const CHANGE_STYLE = 'CHANGE_STYLE'

四(State)、在模塊中導入mutation改變狀態:

index.js

[CHANGE_STYLE] (state, styleName, styleUrl) {
  state.iPhone6S.activeStyle = styleName
  state.iPhone6S.activeStyleUrl = styleUrl
}

因爲 Vuex store 內部的 state 對象被 Vue 改形成了響應式對象,當咱們對 state 進行修改時,任何觀測着 state 的 Vue 組件都會自動地進行相應地更新。

使用Vuex管理狀態並非須要把全部的狀態都放在Vuex裏。如上所述,組件本地狀態是不須要寫在Vuex裏的。

組件不容許直接修改 store 實例的狀態

在使用vuex的過程當中你有可能會對從vuex.getters獲取的數據進行再次操做。這是不容許的。改變 store 中的狀態的惟一途徑就是顯式地分發 狀態變動事件

組件永遠都不該該直接改變 Vuex store 的狀態。由於咱們想要讓狀態的每次改變都很明確且可追蹤,Vuex 狀態的全部改變都必須在 store 的 mutation handler (變動句柄)中管理。

使用Vue Tools調試vuex

使用Vue Tools調試vuex是一個很是愉快的體驗,能夠在Components
中清楚的看到哪些數據是從vuex.getters中獲取來的。

圖片描述

它記錄了每次mutation的狀態變化,保存了狀態變化後的快照,咱們能夠定位到你想檢查的快照觀察數據的變化。

圖片描述

原文: 使用Vue.js和Vuex實現購物車場景

相關文章
相關標籤/搜索