VUE

Vuex学习笔记及Vuex中module的简单使用

2019-08-10  本文已影响164人  彼得潘北北
Image [2].png

vuex其实就是一个大的全局管理容器/仓库,你可以在你项目的任何地方用到它,并且store的状态是响应式的,也就是说在某一个组件里修改store,则可以得到全局的响应变更。

不能直接更改store中的状态,改变store中的状态唯一途径就是显示的提交(commit)

例如:

// 如果在模块化构建系统中,请确保在开头调用了 Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }})
  
  // 不要直接改变store.state.count
store.commit('increment') // 提交
console.log(store.state.count) //  1

由于store中的状态是响应式的,在组件中调用store只需在计算属性中返回即可,触发变化也仅仅是在组件methods中提交mutation。

在组件中获取store中的状态

① 通过组件中计算属性返回

Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中(需调用 Vue.use(Vuex)):

const app = new Vue({
  el: '#app',
  // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
  store,
  components: { Counter },
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `})
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count
    }
  }}

② 使用getter

getter其实就相当于是store的计算属性,来实时监听state值的变化(最新状态)

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
 
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)
    }
  }})

通过属性访问getter

store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]

getter也可以接受其他getter作为第二个参数

getters: {
  // ...
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }}
  
store.getters.doneTodosCount // -> 1
通过方法访问

让getter返回一个函数,以函数的参数给getter传参

getters: {
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
    // 也可以采用下面这种写法
    getTodoById(state) {
        return (id) => {
         return state.todos.find(todo => todo.id === id)
    }
  }}
  
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。

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

上例中的increment是事件类型type,后面是回调函数handler,要调用一个mutation的handler,必须以相应的type调用store.commit

store.commit('increment');

当然,也可以向store.commit传入额外的参数

mutations: {
  increment (state, payload) {
    state.count += payload.count
  }
}

// 可以这样传参
store.commit('increment', {
    count: 10
})

// 也可以这样传参
store.commit({
    type: 'increment',
    count: 10
})

其实更建议使用常量命名 Mutation 事件类型

mutations: {
    SOME_MUTATION: (state, payload) =>  {
         state.count += payload.count
  }
}

action

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
    // 也可以这样
    increment ({ commit }) {
      commit('increment')
    }
  }
 })

context是一个与 store 实例具有相同方法和属性的 对象, 因此可以context.commit 或者 context.state、context.getter来获取

在action中执行异步操作

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

action是通过store.dispatch触发

store.dispatch('incrementAsync')

// 也可以传参

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

mapState、mapGetter、mapMutation、mapAction辅助函数

这些辅助函数,其实都是帮我们在组件中映射相应的状态,减少不必要的代码

例如:

//  store文件中
const store = new Vuex.Store({
    state: {
        count: 0
    },
     mutations: {
        increment (state) {
            state.count++
    }
  },
      actions: {
        increment (context) {
            context.commit('increment')
        }
    },
    getters: {
        getCount(state) {
            return state.count
        }
    }
})

//  组件中
import { mapState,mapGetter,mapMutation,mapAction} from 'vuex'

export default {

    computed: {
        ...mapState({
            count: state => state.count
        }),
        ...mapState([
            'count', // 将this.count映射为this.$store.state.count
        ]),
        
        ...mapGetters([
             'getCount', // 将this.getCount映射为this.$store.getters.getCount
        ]),
         ...mapGetters({
             getCount: getCount, 
        })
    },
    methods: {
        ...mapAction([
            'increment', // 将 `this.increment()` 映射为`this.$store.dispatch('increment')`
        ]),
        
        ...mapActions({
              add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
            }),
            
         
        ...mapMutations({
              add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
            }),
        ...mapMutations([
            'increment', // 将 `this.increment()` 映射为`this.$store.commit('increment')`
        ]),
     }
}

vuex中的module模块化

当一个项目过于复杂需要共享的状态过多时,store对象就会变得非常臃肿且不好管理,这时我们就可以使用vuex提供的将store分割成一个个module

如何使用?
首先在store文件夹下新建module文件夹,里面就是管理状态的js文件,既然要把不同状态分开,那就建立不同的文件

Image.png

此时store文件夹下的index文件就要改成如下所示:


import Vue from 'vue';
import Vuex from 'vuex';
import a1 from './modules/a1';
import a2 from './modules/a2';
Vue.use(Vuex);

export default new Vuex.Store({
    modules:{
         a1,
         a2
    }
});

默认情况下,模块内部的action等是注册在全局命名空间的,如果你希望你的文件具有更高的封装性和复用性,可以通过添加namespaced:true使其成为带命名空间的模块。

而我们如何在组件中使用带有命名空间的模块?
举个栗子:

// a1.module.js
const a1 = {
  namespaced: true,
  state: {
    flag: false
  },
  mutations: {
    CHANGE_FLAG: (state) => {
      state.flag = true;
    }
  },
  actions: {
    changeFlag({commit}) {
      commit('CHANGE_FLAG');
    }
  } 
}
export default a1;
// 组件中
<tempalte>
    <div>
        <div v-if="flag"> 显示 </div>
        <div v-else> 隐藏 </div>
    </div>
</tempalte>
import {mapState , mapActions} from 'vuex';
export default {
    name: 'A1',
    data() {
        return {}
    },
    computed: {
        // a1 表示指的是modules文件夹下的a1.module.js文件
        ...mapState('a1', { 
            flag: state => state.flag
        }),

        // 也可以这样写
        ...mapState({
            flag: state => state.a1.flag
        }),

        // 不使用mapState
        flag() {
            return this.$store.state.a1.flag
        }
    },
    methods: {
        ...mapActions('a1', ['changeFlag'])  
        // 此时将this.changeFlag映射为 this.$store.dispatch('a1/changeFlag')
    }
}

至此,简单的使用vuex你学会了吗?

上一篇下一篇

猜你喜欢

热点阅读