VueX


VueX简介

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension (opens new window),提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。

简单来说就是,VueX是将所有的组件需要共同进行请求与修改的数据统一放在一个对象内,再将这个对象放入顶层容器,这样在请求数据时便可直接到该容器中取得

听起来我们自己也可以实现这个功能,只需要在Vue的全局对象中添加一个属性,这个属性的数据类型时一个类,类里面包含了我们所需要的数据

例如:

const shareObj = {
  name: 'justin'
};

Vue.prototype.shareObj = shareObj;

之后我们便可以在任意组件中使用该属性,但是这样有一个弊端,它不是响应式的

所以我们需要VueX来实现该功能,VueX已经集成了响应式操作

Vue初使用

安装

npm install vuex --save

注册store

创建一个store文件夹用于专门放置store文件

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    counter: 1000
  }
});

export default store;//记得导出

然后在main.js文件里注册store

import Vue from 'vue'
import App from './App'
import store from './store'

Vue.config.productionTip = false

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

Vuex状态管理

vuex共有5个属性,分别为:

  • State
  • Getters
  • Mutations
  • Actions
  • Modules

各个属性的意义如下:

State:

vue唯一数据源,通常全部共享数据都存储于此

Getters:

类似于computed,可以看作State的计算属性

Mutations:

虽然可以通过直接修改state的值来达到响应式,但是这样改变的值无法被监听

vuex建议通过mutations来改变值,从而达到监听的效果

使用方法

定义mutations

mutations: {
    add(state) {
      state.counter++;
    }
  }

在组件方法中调用mutations

methods: {
    add() {
      this.$store.commit('add');
    }
  }

同时,mutations的方法还可以添加参数,通常添加一个对象

mutations: {
  addMore(state, payload) {
      state.counter += payload.num;
    }
}
methods: {
    addMore() {
      this.$store.commit('addMore', {
        num: 5
      });
    }
  }

使用一种更加规范的提交方式

methods: {
  addMore() {
    this.$store.commit({
      type: 'addMore',
      num: 5
    });
  }
}

由于是用对象传递的参数,所以mutations不需要更改

mutations: {
  addMore(state, payload) {
      state.counter += payload.num;
    }
}

tips:如果需要新增或者删除属性,可以通过Vue.set()方法与Vue.delete()方法来实现

Actions:

Actions与Mutations类似,不同的是Actions是执行异步操作的,由最上面的图可知,最终都是要执行Mutations操作的,所以Actions是在异步操作后进行调用Mutations的

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,类似于Mutations的state参数

例如

actions: {
    addApi(context) {
      setTimeout(() => {
        context.commit('add');
      }, 1000);
    }
  }
addApi() {
      this.$store.dispatch('addApi')
}

同样的,Actions也可以接收一个payload,用法与Mutations类似

这样我们可以执行一个更复杂一点的操作

actions: {
  addApi(context, payload) {
    return new Promise((resolve, reject) => {    //返回值为一个Promise对象
      setTimeout(() => {
        context.commit('add');
        console.log(payload);
        resolve('done!');
      }, 1000)
    })
  }
}
addApi() {
  this.$store.dispatch('addApi', {
    name: 'justin',
    sex: 'men'
  }).then((message) => {    //因为调用这个函数的返回值为一个Promise对象,所以可以直接then
    console.log(message)
  })
}

Module

Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

module实际上就是又一个Store实例,但是因为我们需要单一状态管理,所以不允许有多个Store,这样Module就给予了极大的方便

总结

mutations主要是用于对state储存的值进行修改,所有在进行对vuex中的状态值进行函数修改的时候,比较好的方法是将函数的逻辑方面交给actions进行操作,而值的操作交给mutations进行操作

例如以下代码:

// actions
  addProductToCart ({ state, commit }, product) {
    commit('setCheckoutStatus', null)
    if (product.inventory > 0) {
      const cartItem = state.items.find(item => item.id === product.id)
      if (!cartItem) {
        commit('pushProductToCart', { id: product.id })
      } else {
        commit('incrementItemQuantity', cartItem)
      }
      // remove 1 item from stock
      commit('products/decrementProductInventory', { id: product.id }, { root: true })
    }
  }
}

// mutations
const mutations = {
  pushProductToCart (state, { id }) {
    state.items.push({
      id,
      quantity: 1
    })
  },

  incrementItemQuantity (state, { id }) {
    const cartItem = state.items.find(item => item.id === id)
    cartItem.quantity++
  },

  setCartItems (state, { items }) {
    state.items = items
  },

  setCheckoutStatus (state, status) {
    state.checkoutStatus = status
  }
}

Vuex目录

Vuex以一种更加优雅的方式来存放文件

Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:

  1. 应用层级的状态应该集中到单个 store 对象中。
  2. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
  3. 异步逻辑都应该封装到 action 里面。

只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。

对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:

├── index.html
├── main.js
├── api
│   └── ... # 抽取出API请求
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 我们组装模块并导出 store 的地方
    ├── actions.js        # 根级别的 action
    ├── mutations.js      # 根级别的 mutation
    └── modules
        ├── cart.js       # 购物车模块
        └── products.js   # 产品模块