基于Vue2使用Vuex3

一、介绍

Vuex是专为Vue.js应用程序开发的状态管理模式(state management pattern)。本文针对Vue2版本简单介绍如何配置Vuex3对项目进行项目管理。

简单理解为可以把多个组件共享的变量(状态)全部存储在一个对象里面,将该对象放在顶层的Vue实例中,让其他组件使用并响应式刷新。

基于Vue2使用Vuex3_第1张图片

 如上图所示,Vuex主要包含Actions、Mutations、State,将在稍后详细介绍。Devtools是能够记录vuex中state修改记录的浏览器插件,可以在chrome插件商店中下载。

二、Vuex的初步使用

1.安装

sudo npm install vuex@3

2.在src目录下新建store文件夹,文件夹内添加index.js

import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)

const store = new Vuex.Store(
  {
    state:{
      count:0
    },
    mutations:{
      ADD(state){
        state.count++
      } 
    },
    actions:{},
    getters:{},
    modules:{},
  }
)

export default store

3.在main.js中给根实例引入并绑定store

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

Vue.config.productionTip = false


new Vue({
  render: h => h(App),
  store,
}).$mount('#app')

三、Vuex核心概念

1.state

Vuex使用单一状态树,用一个对象包含全部应用层级的状态,这意味着每个Vue应用将仅仅包含一个store实例。我们可以在注入vuex的子组件中通过一下方式访问存储在state中的变量:

 

{{$store.state.count}}

2.Getter

在使用state中的属性时,我们往往需要使用属性的派生状态,如过滤等操作,getter可以认为是store中的计算属性,就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。getter接受state作为第一个参数,也可以接受getters作为第二个参数:

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    },
    doneTodosCount: (state, getters) => {
      return getters.doneTodos.length
    }
  }
})

我们可以在组件中通过以下方式使用getter

this.$store.getters.doneTodosCount

getter 还可以返回一个函数,来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用。

getters: {
  // ...
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

3.Mutations

更改Vuex中store的唯一方法是提交mutation。每格mutation都有一个字符串的事件类型(type)和一个回调函数(handler),这个回调函数就是进行state更改的地方,且接受state作为第一个参数。

const store = createStore({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 变更状态
      state.count++
    }
  }
})

当我们在组件中调用mutation时,可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用

普通提交:

store.commit('increment')

mapMutations提交:

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`

      // `mapMutations` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
  }
}

store.commit可以传入额外的参数,即mutaion的载荷payload,payload通常是一个对象;

// ...
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
store.commit('increment', {
  amount: 10
})

* mutation必须是同步函数,不然devtools将无法追踪vuex状态的改变

4.Action

Action类似于mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作
const store = createStore({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      setTimeout(()=>{
      context.commit('increment')
      },1000)
    }
  }
})

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters,context对象并不是实例本身。

可以使用ES6语法来简写代码:

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

action通过store.dispatch方法触发,且同样支持载荷对象分发:

store.dispatch('increment')
// 以载荷形式分发
store.dispatch('incrementAsync', {
  amount: 10
})

// 以对象形式分发
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

在组件中奋发actions(需在根结点注入$store):

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }
}

store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}
store.dispatch('actionA').then(() => {
  // ...
})

并且 store.dispatch 仍旧返回 Promise,所以可以将actions组合:

actions: {
  // ...
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}

5. Module

由于使用单一状态树,应用的所有状态集中到一个对象中肯能会变的相当臃肿。module允许我们将store分割成模块,每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。

const store = createStore({
  state:{},
  getters:{},  
  modules: {
    //...
    a:{
      state:{},
      getters:{},
    },
    b:{
      state:{},
      getters:{},
    }
  }
})

对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象,模块内部的 getter,根节点状态会作为第三个参数暴露出来:

const moduleA = {
  state: () => ({
    count: 0
  }),
  mutations: {
    increment (state) {
      // 这里的 `state` 对象是模块的局部状态
      state.count++
    }
  },
  getters: {
    sumWithRootCount (state, getters, rootState) {
      return state.count + rootState.count
    }
  }
}

 对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState

const moduleA = {
  // ...
  actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}

你可能感兴趣的:(vue学习笔记,vue.js,前端)