Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式
可以实现Vue不同组件之间的状态共享 (解决了不同组件之间的数据共享)
可以实现组件里面数据的持久化
Vuex挂载
// vuex文件夹下新建store.js
import { createStore } from 'vuex'
const store = createStore({
state () {
return {
count: 1
}
},
mutations: {
increment (state) {
state.count++
}
}
})
export default store;
//在main.ts中进行挂载
import { createApp } from 'vue'
import App from './App.vue'
import route from './routes'
import store from './vuex/store'
let app=createApp(App);
//挂载路由
app.use(route)
//挂载vuex
app.use(store)
app.mount('#app')
Vuex的属性
State
State在Vuex中主要用于存储数据,State是存储在 Vuex 中的数据和 Vue 实例中的 data 类似
在vuex中定义state
import { createStore } from 'vuex'
const store = createStore({
state () {
return {
count: 1,
list:['a','b','c']
}
},
mutations: {
increment (state) {
state.count++
}
}
})
export default store;
// 可以在组件中直接修改 但是不能这样做 在开发调试工具中不能完整的记录变化的过程
this.$store.state.count = 456
组件中获取status
方式1 (不推荐)
// 在使用到的组件中引入store 然后在计算属性中获得
computed: {
count () {
return store.state.count
}
}
方式2
// 由于在全局挂载了vuex 通过this.$store.state就能获取到state
computed: {
count () {
return this.$store.state.count
}
}
方式3
// 通过mapstate获取
// 当变量名相同时可以简写
import { defineComponent } from "vue";
import { mapState } from "vuex";
export default defineComponent({
data() {
return {};
},
methods: {},
computed: {
// 如果遇到了组件本身声明的状态时相同名称时会有冲突
...mapState([
"count",
"list"
]),
},
});
// 当变量需要重新命名时
import { defineComponent } from "vue";
import { mapState } from "vuex";
export default defineComponent({
data() {
return {};
},
methods: {},
computed: {
// 这种方式可以避免与组件原有的状态冲突
...mapState({
count: (state) => state.count,
list: (state) => state.list,
}),
},
});
注:
当vuex属性与组件本身的状态命名相同时,优先组件本身的状态
Getter
Vuex 在 store 中定义“getter”类似计算属性,getter 的返回值会根据它的依赖被缓存起来
且只有当它的依赖值发生了改变才会被重新计算
在vuex中定义getter
const store = createStore({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
// 接收的第二个参数为getters自身的对象 可以对计算属性进行二次封装
doneTodos: state => {
return state.todos.filter(todo => todo.done)
},
doneTodosCount: (state, getters) => {
return getters.doneTodos.length
}
}
})
组件中获取getter
方式1
// 通过 this.$store.getters可以获取到getter对象
console.log(this.$store.getters.doneTodos)
方式2
// 通过计算属性获取
computed: {
doneTodosCount () {
return this.$store.getters.doneTodosCount
}
方式3
// 通过mapGetters获取
// 当变量名相同时可以简写
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
// 当变量需要重新命名时
...mapGetters({
// 把 `this.$store.getters.doneTodosCount` 映射为 `this.doneCount`
doneCount: 'doneTodosCount'
})
Mutations
Vuex 中的 mutation 类似事件,都有一个字符串的 事件类型 (type) 和 一个回调函数 (handler)
这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
是修改state全局状态的唯一途径
在调试工具中能完整的记录变化的细节 时间 触发函数 已经传递的参数
在vuex中定义Mutations
const store = createStore({
state: {
count: 1
},
// 没有传参时
mutations: {
increment (state) {
// mutate state
state.count++
}
}
// 有传参时 第二个形参就是要传递的参数
mutations: {
increment (state, n) {
state.count += n
}
}
})
组件中触发Mutations
// 没有传参时
this.$store.commit('increment')
// 有传参时
this.$store.commit('increment', 10)
组件中引入Mutations
import { mapMutations } from 'vuex'
export default {
methods: {
// 写法一 数组 会与组件原有的方法重名
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
]),
// 写法二 对象写法 当没有传参时可以简写 也可以写成函数调用函数的写法
// 第一个参数为Mutations的触发commit 第二个参数为传递的参数
...mapMutations({
add: 'increment', // 将 `this.add()` 映射为 `this.$store.commit('increment')`
fn(commit,payload){
commit('increment',payload)
}
}),
// 写法三 数组模块 会映射出响应模块中的方法
// mapMutations接收的第一个参数为需要映射的模块
...mapMutations('moduleA', [
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
]),
// 写法四 对象模块
// 第一个参数为Mutations的触发commit 第二个参数为传递的参数 在触发时指定对应的模块
...mapMutations({
fn(commit,payload){
commit('moduleA/increment',payload)
}
}),
}
}
Actions
Action 类似于 mutation,都是定义方法,不同的是Action 提交的是 mutation,而不是直接变更状态
mutation中可以进行异步操作但没有意义,不能调用自身的方法
状态可以修改但是调试工具无法正确的追踪状态的变化的细节流程
Action 可以包含任意异步操作 传入参数context为上下文,第二个参数为调用时传递的参数
在vuex中定义Actions
const store = createStore({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
// 方式1:传入参数为上下文 调用commit触发mutations中的方法
actions: {
increment (context) { // 通过actions中的increment调用mutations中的increment
context.commit('increment')
}
}
// 方式2:从context中解构出commit直接调用
actions: {
increment ({ commit }) {
commit('increment')
}
}
// 方式3:调用时传递参数 第一个参数为上下文对象store 第二个参数为传参
actions: {
increment ({ commit }, payload) {
commit('increment')
}
}
})
在组件中触发Actions
this.$store.dispatch('increment')
actions里的异步操作
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
组件中引入Actions
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // map `this.increment()` to `this.$store.dispatch('increment')`
]),
...mapActions({
add: 'increment' // map `this.add()` to `this.$store.dispatch('increment')`
})
}
}
组合actions
store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise
并且 store.dispatch 仍旧返回 Promise
// assuming `getData()` and `getOtherData()` return Promises
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // wait for `actionA` to finish
commit('gotOtherData', await getOtherData())
}
}
Modules
Vuex 允许将 store 分割成模块(module)
每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块
modules相当于广播 会触发所有同名方法
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> `moduleA`'s state
store.state.b // -> `moduleB`'s state
模块的命名空间
由于this.$store.commit()会触发所有模块中的同名方法
为了进行区分 需要命名空间namespaced,默认的值为false
const moduleA = {
namespaced: true,
state: () => ({
count: 0
}),
mutations: {
increment (state) {
// `state` is the local module state
state.count++
}
}
}
当需要触发对应模块的方法时需要加上命名空间
this.$store.commit('moduleA/increment')
模块的局部状态
对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象
const moduleA = {
state: () => ({
count: 0
}),
mutations: {
increment (state) {
// `state` is the local module state
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
Vuex数据持久化
使用vuex-persistedstate来进行数据持久化
import createPersistedState from 'vuex-persistedstate'
引入后再store配置项中声明
plugins: [createPersistedState()]
即可将vuex的数据同步到localStorage中