Vuex
vuex 是终极的组件之间的数据共享方案,在企业级的 vue 项目开发中,vuex 可以让组件之间的数据共享变得高效、清晰且易于维护
小范围的数据共享还是建议使用之前父向子等传值
一般情况下,只有组件之间共享的数据才有必要存储到 vuex 中,对于组件中的私有数据,依旧存储在组件自身的 data 中即可
优点
- 能够在
vuex中集中管理共享的数据,易于开发和后期的维护 - 能够高效地实现组件之间的数据共享,提高开发效率
- 存储在
vuex中的数据都是响应式的,能够实时保持数据与页面的同步
安装和配置
npm i vuex -S
在 src 目录中创建一个 store 文件夹,在 store 文件夹中的 index.js 中配置
import Vue from 'vue'
import Vuex from 'vuex'
// 需要使用插件一次
Vue.use(Vuex)
// state: 窗口存储数据的地方
const state = {}
// mutations: 修改 state 的唯一手段
const mutations = {}
// action: 处理 action 可以书写自己的业务逻辑,也可以处理异步
const actions = {}
// getters: 理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
const getters = {}
// 对外暴露 Store 类的一个实例
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
在到 main.js 中注册
import Vue from 'vue'
import App from './App.vue'
// 引入路由
import router from '@/router'
// 引入仓库
import store from '@/store'
// productionTip设置为 false ,可以阻止 vue 在启动时生成生产提示
// 开发环境下,Vue 会提供很多警告来帮你对付常见的错误与陷阱。而在生产环境下,这些警告语句却没有用,反而会增加应用的体积。此外,有些警告检查还有一些小的运行时开销,这在生产环境模式下是可以避免的
Vue.config.productionTip = false
new Vue({
// 注册路由:当这里书写 router 的时候,组件身上都有 $route,$router 属性
router,
// 注册仓库:组件实例的身上会多一个属性 $store
store,
render: h => h(App),
}).$mount('#app')
核心概念
State
示例1
state 提供唯一的公共数据源,所有共享的数据都要统一放到 store 文件夹的 state 中进行存储
export default new Vuex.Store({
state: {
count: 0
},
})
// 或者
const store = new Vuex.store({
state: { count: 0 }
})
组件访问 state 中数据的第一种方式
this.$store.state.全局数据名称
<template>
<div>
<h3>当前最新的count值为:{{ $store.state.count }}</h3>
</div>
</template>
示例2
第二种方式
// 1.从 vuex 中按需导入 mapState 函数
import { mapState } from 'vuex'
通过导入的 mapState 函数,将当前组件需要的全局数据映射为当前组件的 computed 计算属性
computed: {
// mapState 函数返回的是一个对象,使用对象展开运算符将它展开
...mapState(['count'])
}
如下
<template>
<div>
<h3>当前最新的count值为:{{ count }}</h3>
<button>-1</button>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
data () {
return {}
},
computed: {
// 里面的 count 相当于一个计算属性
...mapState(['count'])
}
}
</script>
<style></style>
注意: 在组件中这样写没有报错,但是
vuex中是不允许在组件中直接修改store中的数据,需要使用Mutation
Mutation
Mutation 用于变更 Store 中的数据
- 只能通过
mutation变更Store数据,不可以直接操作Store中的数据 - 通过这种方式虽然操作繁琐,但是可以集中监控所有数据的变化
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
add (state) {
// 变更状态
state.count++
}
}
})
示例1
第一种调用方式
store 文件夹的 index.js 中
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
add (state) {
state.count++
},
addn (state, n) {
state.count += n
}
}
})
组件中
<template>
<div>
<h3>当前最新的count值为:{{ $store.state.count }}</h3>
<button @click="btnHandler1">+1</button>
<button @click="btnHandler2">+n</button>
</div>
</template>
<script>
export default {
...
methods: {
btnHandler1 () {
this.$store.commit('add')
},
btnHandler2 () {
// commit 的作用就是调用某个 mutation 函数
this.$store.commit('addn', 10)
}
}
}
</script>
示例2
第二种调用方式
store 文件夹的 index.js 中
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
sub (state) {
state.count--
},
subn (state, n) {
state.count -= n
}
}
})
组件中
<template>
<div>
<h3>当前最新的count值为:{{ count }}</h3>
<button @click="btnHander1">-1</button>
<button @click="btnHander2">-n</button>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
export default {
...
computed: {
...mapState(['count'])
},
methods: {
...mapMutations(['sub', 'subn']),
btnHander1 () {
this.sub()
},
btnHander2 () {
this.subn(10)
}
}
}
</script>
注意:在
mutation不能进行异步操作(setTimeout,Ajax,文件操作,promise,回调函数等等)
Action
Action 用于处理异步任务
如果通过异步操作变更数据,必须通过 Action,而不能使用 mutation ,但是 Action 中还是要通过触发 mutation 的方式间接变更数据
示例1
触发 action 的第一种方式
store 文件夹中的 index.js
export default new Vuex.Store({
...
mutations: {
add (state) {
state.count++
},
addn (state, n) {
state.count += n
}
},
actions: {
addAsync (context) {
setTimeout(() => {
context.commit('add')
}, 1000)
},
addnAsync (context, n) {
setTimeout(() => {
context.commit('addn', n)
}, 1000)
}
}
})
组件中调用
<template>
<div>
<h3>当前最新的count值为:{{ $store.state.count }}</h3>
<button @click="btnHandler3">+1 Async</button>
<button @click="btnHandler4">+n Async</button>
</div>
</template>
<script>
export default {
...
methods: {
// 异步的自增加1
btnHandler3 () {
// 这里的 dispatch 专门用来触发 action
this.$store.dispatch('addAsync')
},
btnHandler4 () {
this.$store.dispatch('addnAsync', 10)
}
}
}
</script>
示例2
触发 action 的第二种方式
在 store 文件夹的 index.js 中
export default new Vuex.Store({
...
mutations: {
sub (state) {
state.count--
},
subn (state, n) {
state.count -= n
}
},
actions: {
subAsync (context) {
setTimeout(() => {
context.commit('sub')
})
},
subnAsync (context, n) {
setTimeout(() => {
context.commit('subn', n)
})
}
}
})
在组件中使用
<template>
<div>
<h3>当前最新的count值为:{{ count }}</h3>
<button @click="subAsync">-1 Async</button>
<button @click="subnAsync(10)">-n Async</button>
</div>
</template>
<script>
import { mapState,mapActions } from 'vuex'
export default {
...
computed: {
...mapState(['count'])
},
methods: {
...mapActions(['subAsync', 'subnAsync']),
btnHander1 () {
this.sub()
}
}
}
</script>
Getter
Getter 用于对 store 中的数据进行加工处理形成新的数据
Getter可以对Store中已有的数据加工之后形成新的数据,类似于Vue的计算属性store中数据发生变化,Getter的数据也会跟着变化
示例1
使用 getters 的的使用方式与 state 差不多
第一种方式
在 store 文件夹中
export default new Vuex.Store({
state: {
count: 0
},
...
getters: {
showNum (state) {
return '当前最新的数据是: ' + state.count
}
}
})
组件中使用
<h3>{{ $store.getters.showNum }}</h3>
示例2
第二种使用方式
组件中使用
<h3>{{ showNum }}</h3>
<script>
import { mapGetters } from 'vuex'
export default {
...
computed: {
...mapGetters(['showNum'])
}
}
</script>