Vuex初識

Vuex初識

Vuex的介紹

Vuex是一個專爲Vue.js應用程序開發的狀態管理模式官網給出Vuex的流程圖如下:

Vuex流程圖

這個流程圖我的解讀如下:

  • Components: 頁面中的組件
  • Actions: 頁面中要改變數據狀態的動作
  • Mutations: vuex中執行數據狀態更改的行爲
  • State: 數據倉庫(由vuex來管理狀態的數據組成集合)

我對Vuex這幾個模塊的解讀如下圖所示:

vuex-defintion-mine

組件(Components)只做頁面的展示,數據全部交給vuex來處理可以將vuex的state看成前端自己的持久層—數據倉庫。Actions/Mutations監測到組件中執行了對數據(如:msg)進行更改的動作後,去數據倉庫State中保存的數據(msg)進行相應的更改操作。而組件展示數據(msg),均是通過Getters從數據倉庫State中取出相應的數據(msg)。

結合案例說明如下:

項目的完整源碼在我的GitHub項目—learn-vuex中,在git的命令行工具運行如下命令,可以將該項目克隆到本地。

# 在git命令行工具中執行,克隆到本地
git clone https://github.com/zhenye163/learn-vuex
# 加載依賴包
npm install
# 運行該項目
npm run dev

搭建Vue腳手架

搭建Vue腳手架的準備工作詳見: 歡迎入坑

# 生成名稱爲learn-vuex的項目
vue init webpack learn-vuex
cd learn-vuex
# 拉取國內淘寶鏡像,安裝腳手架需要的依賴環境
npm install --registry=https://registry.npm.taobao.org
# 啓動項目
npm run dev

生成的項目結構說明如下:

vue-cli-desc

項目啓動後,訪問http://localhost:8080/#/,如果出現如下頁面,說明vue腳手架搭建成功

vue-HelloWorld

模擬的場景闡明

腳手架已經搭建成功,接下來我們就可以開始折騰了。爲了能夠理解Vuex到底給Vue帶來了什麼好處,我想用本項目模擬一個點餐吃飯(呃,一不小心就暴露了我這吃貨本性)的場景。

場景一 :在家吃飯

在家吃飯

場景二:在餐館吃飯

在餐館吃飯

場景再現的準備工作

  • 將項目的目錄結構調整如下:
- src
  - assets
    - logo.png
  - components
    - HelloWorld.vue
  - router
    - index.js
  - store
    - actions.js
    - getters.js
    - index.js
    - mutations.js
    - rootState.js
  - views
    - family.vue
    - restaurant.vue
  - App.vue
  - main.js
  • 在src/router/index.js中配置路由如下
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Family from '@/views/family'
import Restaurant from '@/views/Restaurant'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {
      path: '/family',
      name: 'Family',
      component: Family
    },
    {
      path: '/restaurant',
      name: 'Restaurant',
      component: Restaurant
    }
  ]
})
  • 在src/main.js中導入Element-UI
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui'

Vue.use(ElementUI)
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

不用Vuex的場景再現—在家吃飯

  • 直接在src/views/family.vue中實現
<template>
  <div>
    在家吃飯
    <div>
      <br/><br/>
      <div>
        <div>此時桌子上的菜有:</div>
        <br/><br/>
        <div v-for="food in foodList" :key="food.id">
          <div>菜名:{{food.name}} ,價格:{{food.price}}</div>
        </div>
      </div>
      <br/><br/>
      <el-button @click.native.once="addFood()">加個燉排骨</el-button>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      foodList: [],
      menu: []
    }
  },
  created () {
    this.initData()
  },
  methods: {
    initData () {
      this.foodList = [
        {id: 1, name: '酸辣土豆絲', price: 12},
        {id: 2, name: '手撕包菜', price: 12}
      ]
      this.menu = [
        {id: 1, name: '酸辣土豆絲', price: 12},
        {id: 2, name: '手撕包菜', price: 12},
        {id: 3, name: '燉排骨', price: 48},
        {id: 4, name: '麻婆豆腐', price: 12},
        {id: 5, name: '武昌魚', price: 12}
      ]
    },
    addFood () {
      this.foodList.push(this.menu[2])
    }
  }
}
</script>

<style>

</style>

在家吃飯

點擊點單按鈕可以看到相應的點菜效果。

用Vuex後的場景再現—在餐館吃飯

  • 首先在src/main.js中引入vuex的數據倉庫store
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui'
import store from './store/index'

Vue.use(ElementUI)
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})
  • 在src/views/restaurant.vue中定義頁面內容如下:
<template>
  <div>
    在餐館吃飯
    <div>
      <br/><br/>
      <div>
        <div>此時桌子上的菜有:</div>
        <br/><br/>
        <div v-for="food in foodList" :key="food.id">
          <div>菜名:{{food.name}} ,價格:{{food.price}}</div>
        </div>
      </div>
      <br/><br/>
      <el-button @click.native.once="addFood('燉排骨')">加個燉排骨</el-button>
    </div>
  </div>
</template>

<script>
import {mapGetters} from 'vuex'
export default {
  data () {
    return {}
  },
  computed: {
    ...mapGetters(['foodList'])
  },
  methods: {
    addFood(food){
      this.$store.dispatch('addFood', '燉排骨')
    }
  }
}
</script>

<style scoped>

</style>

頁面中需要展示的數據foodList是從state中通過getters獲取

  • 在src/store/rootState.js中定義需要vuex進行管理的數據如下
const state = {
  // 點單即將上菜的食物
  food: {id: -1, name: '', price: -1},
  // 飯桌上已經有哪些食物
  foodList: [
    {id: 0, name: '酸辣土豆絲', price: 12},
    {id: 1, name: '手撕包菜', price: 12}
  ]
}

export default state
  • 在src/store/getters.js中定義如何獲取state中的數據
export const foodList = state => state.foodList

export const menuList = state => state.menuList
  • 頁面中有點單(燉排骨)的行爲,由src/store/action.js檢測到
export const addFood = ({commit}, payload) => {
  commit({
    type: 'cookFood',
    // payload告訴我們點的菜是什麼
    msg: payload
  })
}
  • 點菜後,讓後廚做菜上菜(src/store/mutations.js)
export const cookFood = (state, payload) => {
  state.food.id = state.foodList.length
  state.food.name = payload.msg
  // 菜的價格由餐館決定爲28
  state.food.price = 28
  // 菜做好了,push方法進行上菜
  state.foodList.push(state.food)
  // 方法執行完,需要將state中的food清零
  state.food = {id: -1, name: '', price: -1}
}
  • 將vuex的所有部分彙總到(src/store/index.js)中,然後頁面就會知道菜(燉排骨)已經做好並給顧客上菜
import Vue from 'vue'
import Vuex from 'vuex'
import * as actions from './actions'
import * as getters from './getters'
import * as mutations from './mutations'
import state from './rootState'

Vue.use(Vuex)

const store = new Vuex.Store({
  actions,
  getters,
  mutations,
  state
})

export default store
  • 項目啓動需要先導入vuex依賴包
# 導入vuex需要的依賴包
npm install --save vuex
# 啓動項目
npm run dev

在餐館吃飯

通過瀏覽器的返回/前進,多次測試發現以下幾個現象:

  • 每次進入/family頁面,燉排骨這道菜就消失了。
  • 如果沒有強制刷新頁面(F5),每次進入/restaurant頁面,點的燉排骨這道菜還在。
  • 強制刷新(F5),進入/restaurant頁面,燉排骨這道菜也消失了。

總結:

vuex在前臺進行了數據的持久化處理,即保存了foodList中的值。這樣是更符合實際情況的。總不能我點菜後,菜已經上桌了,我回家拿個手機,再回到餐館發現桌上的菜(燉排骨)就不見了!!!。而強制刷新頁面(F5),是將所有的組件摧毀然後再次重啓。也就是告訴餐館:“前面點的菜不算,我重新點。”這樣的話,餐館是不會多給你加菜(燉排骨的)。它是不可能做賠本買賣!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章