Skip to content
On this page

核心概念

首先得引入vuex,然后通过 vue.use(Vuex)来 注册插件

javascript
const store = new Vuex.Store({
  //vuex的配置
})
javascript
new Vue ({
  el:'#app',
  store, // store:store
})

一个vue Store 里边包括state(状态)getters(派生状态)mutations(提交修改)actions(提交修改数据)module

State

state 是用来存储状态,也就是变量;

store.js 中的写入

javascript
state: {
  count: 22,
  list:[1,5,6,4,3,56,20]
},

在Vue中获取Vuex的状态

从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态:

javascript
const tpl = {
  template: `<div>Your number of likes is: {{count}}</div>`,
  computed: {
    count() { 
      //store 为注册的全局
      return this.$store.state.count
    }
  }
}

state 只是读取数据,他不会修改数据

Getters

getters 表示派生状态。也就是setget中的get,有两个可选参数:stategetters分别可以获取state中的变量和其他的getters。外部调用方式:store.getters.personInfo()。就和vuecomputed差不多

javascript
 getters: {
    getInfo(state) {
      return `our number of likes is: ${state.count}`;
    },
    filterdList (state, getters) {
      // return this.$store.list.filter (item => item > 10);
      return state.list.filter (item => item > 10);
    }
  }

getters中可以通过 参数getters来相互依赖引用其他的getters(getters.getInfo)

Mutations

mutations 是对state中的数据修改; 也就是setget中的set,这是vuex中唯一修改state的方式,但不支持异步操作。
vue中的methods事件注册类似:每个mutaion都有一个字符串的事件类型(type)和一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方,并且他会接受state作为第一个参数。 类似于js 的观察者模式,页面提交修改,然后这边做改变处理

提交载荷(payload)

可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload)

javascript
mutations: {
  increment(state,n = 1) {
    // 第一个参数是 state,第二个参数叫额外的参数,这里是n
    state.count += n;
  },
  decresement(state) {
    state.count -- ;
  }
}
// 回调函数 increment 和参数10,后者是作为额外参数传入,n 就是10
store.commit('increment', 3)

在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:

javascript
mutations: {
  increment (state, payload) {
	  // payload 作为一个对象,更加可读,统一对象形式调用
    state.count += payload.amount
  }
}
// 传入的是对象(即将额外的 mutation 参数以对象的方式传入)
store.commit('increment', {
  amount: 10
})

对象风格提交方式

提交 mutation 的另一种方式是直接使用包含 type 属性的对象:

javascript
// 这里也是传入一个对象,不过这个对象包含了 type 属性
store.commit({
  type: 'increment',
  amount: 10
})

这里只是一种提交 mutations 的方式,不必深究。 当使用这种对象风格的提交方式,整个对象都作为载荷传给 mutation 函数,因此 handler 保持不变:

javascript
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
// vuex 会将这个对象分解,除了 type 之外的,依然会是作为额外参数传入
store.commit({
  type: 'increment',
  amount: 10
})

将整个对象传给 mutation后,vuex 会根据 type 参数识别到这是一个mutation 的载荷参数,然后自动填充 state 参数为第一位,第二位参数为传入的这个对象的第二位参数。

mutations中尽量不要操作异步数据,操作的话 数据不会立即改变,我们一般情况下都是在actions中操作异步数据

Actions

mutation 中混合异步调用会导致你的程序很难调试。例如,当你调用了两个包含异步回调的 mutation 来改变状态,你怎么知道什么时候回调和哪个先回调呢?这就是为什么我们要区分这两个概念。在 Vuex 中,mutation 都是同步事务:

Action 类似于 mutation,不同在于:

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

第一个参数默认是和store具有相同参数属性的对象。外部调用方式:store.dispatch('nameAsyn')。 操作

javascript
actions: {
  increment (context) { //context表示上线问
    context.commit('increment');
  }
}

触发actions 的方法是在template中我们通过diapatch()来提交

html
 <button @click="$store.dispatch('increment')">add</button>

我们通过actions来执行异步操作

javascript
actions: {
  increment (context) {
    return new Promise((resolve,reject) => {
      setTimeout(() => {
        context.commit('increment');
        resolve();
      },2000);
    });
  }
}

组件中这样实现

javascript
  methods: {
    handleActionAdd () {
      this.$state.dispatch('increment').then( () => {
        console.log(111);
      })
    }
  }

会发现 在两秒后才会状态才会发生改变

store 上注册 action。处理函数总是接受 context 作为第一个参数,payload 作为第二个参数(可选)。

context 对象包含以下属性:

javascript
{
  state,      // 等同于 `store.state`,若在模块中则为局部状态
  rootState,  // 等同于 `store.state`,只存在于模块中
  commit,     // 等同于 `store.commit`
  dispatch,   // 等同于 `store.dispatch`
  getters,    // 等同于 `store.getters`
  rootGetters // 等同于 `store.getters`,只存在于模块中
}

同时如果有第二个参数 payload 的话也能够接收

Modules

如果项目比较大的时候,项目全部放到一个store.js 或者 main.js 中 ,感觉比较乱,不太友好, 所以我们需要按模块分开,
store的子模块,内容就相当于是store的一个实例。调用方式和前面介绍的相似,只是要加上当前子模块名,如:store.a.getters.xxx() 每个模块拥有自己的 statemutationactiongetter、甚至是嵌套子模块——从上至下进行同样方式的分割:

javascript
const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

项目结构

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

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

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

├── index.html
├── main.js
├── api
│   └── ... # 抽取出API请求
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 我们组装模块并导出 store 的地方
    ├── state.js          # 跟级别的 state
    ├── getters.js        # 跟级别的 getter
    ├── mutation-types.js # 根级别的mutations名称(官方推荐mutions方法名使用大写)
    ├── mutations.js      # 根级别的 mutation
    ├── actions.js        # 根级别的 action
    └── modules
        ├── m1.js         # 模块1
        └── m2.js         # 模块2

参考

vuex
关于 mutation
【vuex入门系列02】mutation接收单个参数和多个参数
vuex中mutation/action的传参方式