2025-03-29 16:55:07 +08:00

10 KiB
Executable File
Raw Permalink Blame History

vuex

介绍

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

https://vuex.vuejs.org/zh/

image-20210127204118836|788x443

  1. 修改state状态必须通过 mutations
  2. mutations 只能执行同步代码,类似 ajax、定时器之类的代码不能在mutations中执行
  3. 执行异步代码,要通过 actions ,然后将数据提交给 mutations 才可以完成
  4. state 的状态即共享数据可以在组件中引用
  5. 组件中可以调用 action / mutations

使用场景

不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。如果您的应用够简单,您最好不要使用 Vuex

下载 安装

npm install vuex --save
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(vuex)
const store = new Vuex.Store({})
new Vue({
  el: '#app',
  store
})

==Vuex有五个最重要的构造器: state, mutations, actions, getters, modules==

state

state是放置所有公共状态的属性如果你有一个公共状态数据 你只需要定义在 state对象中

​几种使用方法:

原始调用

组件中可以使用 this.$store 获取到vuex中的store对象实例

<div> state的数据{{ $store.state.count }}</div>

结合计算属性

将state属性定义在计算属性中

computed: {
    count () {
        return this.$store.state.count
    }
}

辅助函数 mapState

方便获取多个状态, 像前面在 computed 里多次定义太啰嗦

// 第一步导入mapState
import { mapState } from 'vuex'
// 第二步采用数组形式引入state属性
// 第三步mapState函数返回的是对象, 利用展开运算符合并到计算属性里
computed: {
    ...mapState([
        'count',
        'count2',
        //...
    ])
}

// 如果计算属性的名称和state的子节点名称不同
computed: {
	...mapState({coutAlias: state => state.cout}),
}

// 使用
 <div> state的数据{{ count }}</div>

getters

除了state之外有时我们还需要从state中派生出一些状态这些状态是依赖state的此时会用到 getters 可以认为是 store 的计算属性

例如state中定义了list为1-10的数组组件中需要显示所有大于5的数据

state: {
    list: [1,2,3,4,5,6,7,8,9,10]
},
getters: {
// getters函数的第一个参数是 state
// 必须要有返回值
 filterList:  state =>  state.list.filter(item => item > 5)
}

===通过属性访问时会进行缓存===

getter 可以返回一个函数, 实现向 getter 传参

state: {
    list: [1,2,3,4,5,6,7,8,9,10]
},
getters: {
// getters函数的第一个参数是 state
// 必须要有返回值
 filterList:  state =>  (n)=>state.list.filter(item => item > n)
}

===通过函数每次都进行调用不会缓存===

原始调用

<div>{{ $store.getters.filterList }}</div>
<div>{{ $store.getters.filterList(5) }}</div>

结合 computed

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

辅助函数 mapGetters

computed: {
	...mapGetters(['filterList'])
}

// 重命名
computed: {
	...mapGetters({filterListAlias:'filterList'})
}

// ...
<div>{{ filterList }}</div>

mutations

state数据的修改只能通过mutations并且mutations必须是同步更新, 不能写异步代码 (比如axios)

mutations是一个对象对象中存放修改state的方法

mutations: {
    // 方法里参数 第一个参数是当前store的state属性
    // 第二个可选参数payload, 载荷 运输参数, 外部调用mutaiions的时候可以传递参数
    addCount (state, data) {
      state.count += data
    }
  },

this.$store.commit

// 调用方法
//...     
<button @click="addCount(666)">+</button>

//...
methods: {
    addCount(num){
        this.$store.commit('addCount', num) // commit 提交
    }
}

mapMutations

mapMutations和mapState很像它把位于mutations中的方法提取了出来我们可以将它导入

import  { mapMutations } from 'vuex'
methods: {
    ...mapMutations(['addCount']),
}
// 对像写法, 重命名  
methods: {
	...mapMutations({changeAllDistrictAlias:'changeAllDistrict'})
}

actions

state是存放数据的mutations是同步更新数据actions则负责进行异步操作(比如请求, 定时器)

// 定义actions
 actions: {
  // 第一个参数context表示当前的store的实例,可以通过 context.state 获取状态,也可以通过context.commit 来提交mutations,也可以 context.dispatch调用其他的action
  // 第二个参数data 可选
    getAsyncCount (context) {	// 这里可以用解构 getAsyncCount({ commit })
      setTimeout(function(){
        context.commit('addCount', 123)  // 对应的可以简写 commit('addCount', 123)
      }, 1000)
    },
    
    // 写法2 
      getAsyncCount ({commit}) {
        setTimeout(function(){
          commit('addCount', 123)
        }, 1000)
      },
    
 } 

原始调用

addAsyncCount () {
    this.$store.dispatch('getAsyncCount') // dispatch 委派
}
// 传参
addAsyncCount () {
    this.$store.dispatch('getAsyncCount', 123)
}

mapActions

actions也有辅助函数可以将action导入到组件中

import { mapActions } from 'vuex'
methods: {
    ...mapActions(['getAsyncCount'])
}

// 重命名
methods: {
	...mapActions({ initialDistrictAlias: 'initialDistrict' })
}

直接通过 this.方法就可以调用

<button @click="getAsyncCount(111)">+异步</button>

Module

每个子模块都是一个对象, 可以自己拥有state, mutations, actions, getters

const store  = new Vuex.Store({
  modules: {
    user: {
       state: {
         token: '12345'
       }
    },
    setting: {
		state: {
         name: 'Vuex实例'
      	}
    }
})

原始调用

// store.state.模块名.字段名
<template>
  <div>
      <div>用户token {{ $store.state.user.token }}</div>
      <div>网站名称 {{ $store.state.setting.name }}</div>
  </div>
</template>

配合 getters + mapGetters

// 配合getters简写
getters: {
    token: state => state.user.token,
    name: state => state.setting.name
} 

// 再配合mapGetters
computed: {
    ...mapGetters(['token', 'name'])
}

命名空间

==注意: 默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的==(简单的说不加模块名直接带上字段名就可以调用 state.token) , 为了保证内部模块的高封闭性采用namespaced来进行设置

user: {
    namespaced: true,	 // 命名空间
    state: {
        token: '12345'
    },
    mutations: {
    	//  这里的state表示的是user的state
    	updateToken (state) {
      		state.token = 678910
    	}
    }
},

方案1带上模块的属性名路径

// 对于有命名空间的action和mutation, 要带上 '命名空间/模块名'
methods: {
    ...mapMutations(['user/updateToken']),
    test () {
        this['user/updateToken']()
    }
}
<button @click="test">修改token</button>
// 调用模块里的mutatios/actions
this.$store.dispatch('user/getUserInfo')
this.$store.commit('user/getUserInfo')
computed: {
    // 把模块名字符串当成第一个参数传进去
  ...mapState('some/nested/module', {
    a: state => state.a,
    b: state => state.b
  })
},
methods: {
  ...mapActions('some/nested/module', [
    'foo',
    'bar'
  ])
}

方案2 createNamespacedHelpers 创建基于某个命名空间辅助函数

import { mapGetters, createNamespacedHelpers } from 'vuex'
// ...
const { mapMutations: mapMutationsUser } = createNamespacedHelpers('user') //创建出属于当前模块的辅助函数, 是一个对象, 里面包括mapGetters, mapState, mapMutations
// 解构并重命名
export default {
    computed: {
        ...mapGetters(['token', 'appName']) // 这里就是子模块里的
    },
    methods: {
         ...mapMutationsUser(['setUserInfo'])
    }
}
<button @click="updateToken">修改token2</button>

持久化

VuexPersistence

https://www.npmjs.com/package/vuex-persist

https://www.cnblogs.com/lemoncool/p/9645587.html

Steps

Import it

import VuexPersistence from 'vuex-persist'

NOTE: In browsers, you can directly use window.VuexPersistence

Create an object

const vuexLocal = new VuexPersistence({
  storage: window.localStorage
})

Use it as Vue plugin.

const store = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  plugins: [vuexLocal.plugin]
}

vuex-persist 的详细属性:

属性 类型 描述
key string 将状态存储在存储中的键。默认: 'vuex'
storage Storage (Web API) 可传localStorage, sessionStorage, localforage 或者你自定义的存储对象. 接口必须要有get和set. 默认是: window.localStorage
saveState function (key, state[, storage]) 如果不使用存储,这个自定义函数将保存状态保存为持久性。
restoreState function (key[, storage]) => state 如果不使用存储,这个自定义函数处理从存储中检索状态
reducer function (state) => object 将状态减少到只需要保存的值。默认情况下,保存整个状态。
filter function (mutation) => boolean 突变筛选。看mutation.type并返回true只有那些你想坚持写被触发。所有突变的默认返回值为true。
modules string[] 要持久化的模块列表。

总结

  • state 仓库状态对象
  • mutations 改变数据的函数, 同步
  • action 异步函数
  • getters 类似计算属性的数据获取
  • modules 子模块