Vuex

99 阅读2分钟

Vuex

QQ图片20220324082716.png

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

原理:

使用state数据的组件可以对其共享数据状态进行改变,通过改变状态更新数据从而重新渲染页面

  1. state: vuex的共享数据源,其为一个对象以属性的方式存储公共数据

    1.2 Getters

    当多个使用组件使用state共享数据需要进行过滤时,可以使用Getters添加对应的计算方法; 其效果类似Vue计算属性,getters的结果像计算属性一样会被缓存起来,直到state中对应的数据发生改变。

// Getter 接受 state 作为其第一个参数
const store = createStore({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: (state) => {
      return state.todos.filter(todo => todo.done)
    }
  }
})

我们可以通过this.$store.getters,以属性的形式获取getters的结果。在使用时可以通过插值表达式直接引入,也可以使用一个计算属性。

<h1>{{$store.getters.doneTodos}}</h1>

computed: {
  doneTodos () {
    return this.$store.getters.doneTodos
  }
}

使用 mapGetters 辅助函数生成计算属性
同样的,我们可以使用 mapGetters 辅助函数帮助我们生成计算属性。

import { mapGetters } from 'vuex'
export default {
  computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
}
...mapGetters({
  // 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
  doneCount: 'doneTodosCount'
})
如果你想将一个 `getter` 属性另取一个名字,使用对象形式:
export default { methods:{ add(){ this.$store.dispatch('addnum',2) } } }
  1. dispatch:派遣

    组件可以过dispatch向action提交状态和携带的值。

  2. actions:动作

    Actions里设置Dispath对应状态的应对方法。

    多数情况actions为一个预备确定状态机制,当dispatch携带的值不确定,需要进行异步操作才能获取时actions为其进行与后台请求的异步操作,在得到参数后使用Commit向Mutation进行提交最终的请求状态。 因为 mutation 必须同步执行所以我们在actions内部执行异步操作:

actions: {
// 回调的第一个参数为上下文state,可以直接结构出Commit
    addnum({commit},value){
      setTimeout(() => {
        commit('ADDNUM',value)
      }, 1000);
    },
    delnum({commit},value){
      setTimeout(() => {
        commit('DELNUM',value)
      }, 1000);
    }
  }
  1. Commit :提交

    Commit为提交状态机制,当提交的状态无需进行异步操作时可直接通过CommitMutation提交状态

    1. 直接触发:
  this.$store.commit('DEL',this.shuzi)

当需要异步操作时,以Actions触发

    addajax: function ({ commit }, data) {
      setTimeout(() => {
        state中的值 */
        commit('ADD', data)
      }, 500)
    }
  },
  1. Mutation :改变

想要更改 state 中的数据,我们必须通过commit提交一个mutation,每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler),回调函数接受 state作为第一个参数,也可以传入额外的参数作为第二个参数。

const store = createStore({
  state: {
    count: 1
  },
  mutations: {
    // 每个mutation的回调函数名一般大写,用以和actions里的回调函数名作区分
    INCREMENT (state) {
      // 变更状态
      state.count++
    }
  }
})

// 组件内的方法。通过一个事件调用`commit`方法去调用 `mutation` 处理函数
methods:{
    add(){
        this.$store.commit('INCREMENT')
    }
}
  1. Modules:块化化

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

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

// modeA.js
const state = ()=>({
    modeAMsg:'模块A的msg'
})

const getters = {
    getMsgOfA:(state)=> state.modeAMsg+'--getters'
}

const mutations = {
    CHANGEMSGOFA(state,value){
        state.modeAMsg = value
    }
}

const actions = {
    changemsgAwait({commit},value){
        setTimeout(() => {
            commit('CHANGEMSGOFA',value)
        }, 3000);
    }
}

export default {
    // 如果希望你的模块具有更高的封装度和复用性,你可以通过添加 `namespaced: true` 的方式使其成为带命名空间的模块。
    namespaced:true,
    state,
    getters,
    mutations,
    actions
}
// index.js
import Vue from 'vue'
import Vuex from 'vuex'
// 导入
import modeA from '@/store/modules/modeA'

Vue.use(Vuex)

export default new Vuex.Store({
// 注册
  modules: {
    modeA
  }
})

使用modulesa 在组件中使用modeA
通过this.$store.state.modeA.modeAMsg可以访问modeA中的modeAMsg
通过this.$store.getters['modeA/getMsgOfA']可以访问modeA中的getMsgOfA
调用commit方法调用modeA中的mutation

changeFn1(){
      this.$store.commit('modeA/CHANGEMSGOFA',prompt('请输入改变后的值'))
    },
复制代码
复制代码

调用dispatch方法调用modeA中的action

changeFn2(){
      this.$store.dispatch('modeA/changemsgAwait',prompt('请输入改变后的值'))
    },
复制代码
复制代码

使用辅助函数

当使用 mapStatemapGettersmapActions 和 mapMutations 这些函数来绑定带命名空间的模块时,写起来可能比较繁琐,可以将模块的空间名称字符串作为第一个参数传递给上述函数,这样所有绑定都会自动将该模块作为上下文。

import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'

export default {
  computed:{
    ...mapState('modeA',['modeAMsg']),
    // 使用都对象的写法重命名属性
    ...mapState(a:state=>state.modeA.modeAMsg)
    ...mapGetters('modeA',['getMsgOfA'])
  },
  methods:{
    ...mapMutations('modeA',['CHANGEMSGOFA']),
      // 使用都对象的写法重命名属性
     ...MapMutations('modeA',{changemsg:'HANGEMSGOFA'})
    ...mapActions('modeA',['changemsgAwait'])

  }
}
  1. Mixins:混入

Vue为需要使用相同功能的组件提供的便捷方式。

1.局部混入,导出后在所需的应用以插件的方式使用。(导入加注册)

/* 把公共的内容放在mixinsA js文件中 */
export default {
    data: function () {
        return {
            msg: 'vue初始化已完毕!'
        }
    },
    created: function () {
        console.log(this.msg)
    },
    methods: {
        fn: function () {
            alert(this.msg)
        }
    }
}
<template>
  <div class="about">
    <h1>This is an about page</h1>
    <h1 @click="fn">{{msg}}</h1>
  </div>
</template>
<script>
import mixinsA from '@/mixins/mixinsA.js'
export default {
  name:"AboutView",
  /* 以下内容每个vue页面都需要使用 */
  mixins:[mixinsA]
  
}
</script>

  1. 全局混入

    使用时格外小心!一旦使用全局混入,它将影响每一个之后创建的 Vue 实例

    (包括第三方组件)。

//# main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

Vue.config.productionTip = false

/* 
请谨慎使用全局混入,因为它会影响每个单独创建的 Vue 实例 (包括第三方组件)。
大多数情况下,只应当应用于自定义选项。
推荐将其作为插件发布,以避免重复应用混入。
*/
/* 全局混入 */
Vue.mixin({
  created:function(){
    console.log('全局init....')
  }
})

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

选项合并★

当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。

比如,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。

同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。

值为对象的选项,例如 methodscomponents 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。