Vuex初识

版权声明: https://blog.csdn.net/UtopiaOfArtoria/article/details/79630190

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),是将所有的组件摧毁然后再次重启。也就是告诉餐馆:“前面点的菜不算,我重新点。”这样的话,餐馆是不会多给你加菜(炖排骨的)。它是不可能做赔本买卖!!!

猜你喜欢

转载自blog.csdn.net/UtopiaOfArtoria/article/details/79630190