多组件数据共享: Vuex

我们知道每一个组件都有自己的 data,那么多个组件如何共享数据?这就引出了 state 的概念,可以把多个组件共有的属性统一由state进行管理。但是组件并不能直接访问或操作state里的数据源,而是通过 mutations 来对数据源进行操作。而改变数据的行为触发由 Actions 来完成,Vue 为 actions的触发提供了一个 commit 的概念,由action 触发通过 mutations 对数据进行操作,从而改变 state 数据源。
那么 vue 的组件(components)如何操作 state 数据源呢?components 通过鼠标、键盘等交互行为触发 (Dispatch) Vuex 的Actions,Actions 对操作进行提交,找到对应的 mutations,进而对 state进行改变。这就是 Vuex 的完整数据流。上代码:
首先,安装 vuex
npm i vuex
新建 store.js
touch src/store.js
Vue中可以存放数据的有组件的 data、computed、props,而state就是放在 computed里。
// store.js
import Vue from 'vue' //引入 vue
import Vuex from 'vuex' // 引入vuex
Vue.use(Vuex) // 将Vue 的全局组件 Vuex 加入到 Vue 的运行框架中
const state = { //数据源
count: 1
}
const mutations = { //定义数据操作方法
increment(state) { // 传入数据源
state.count++ // 操作数据源
},
decrement(state) { // 同上
state.count--
}
}
// actions 不能直接修改数据, 它会接收 vue 组件的用户行为,进一步触发(commit)操作,由mutations 对数据源state进行修改。补充说明:commit 携带一个参数,这个参数就是 mutations 里的某一个行为,这个行为会对数据源state进行操作,并使vue组件重新render数据变化
const actions = { // 定义数据源操作行为
increment: ({
commit
}) => { // 解构赋值
commit('increment') // 对应 mutations里的increment,告诉mutations 进行increment 操作
},
decrement: ({
commit
}) => { // 解构赋值
commit('decrement') // 对应 mutations里的decrement,告诉mutations 进行decrement 操作
}
}
// 导出 vuex 的实例
export default new Vuex.Store({
state,
mutations,
actions
})
项目入口文件:
import Vue from 'vue'
import App from './App'
import store from './store' // 引入 store 文件
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store
// 通过在根实例中注册 store 选项,把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件,子组件可以通过 this.$store 访问
}).$mount('#app')
vue组件(component):
在组件中分发 Actions:
在组件中使用 this.$store.dispatch('xxx') 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用(需要先在根节点注入 store):
// vuex.vue
<template>
<div class="vuex">
vuex {{$store.state.count}}
<!-- 用 $store 取 store 的state数据源 -->
<button @click="increment">增加</button>
<button @click="decrement">删减</button>
</div>
</template>
<script>
import { mapActions } from 'vuex' // 引入 vuex的 actions
export default {
methods: mapActions([ // 将methods 映射为 vuex 的 actions
'increment',
'decrement'
])
}
</script>
延伸:Vuex 模块化
先创建好模块目录及模块文件
mkdir src/store // 创建 store 目录
mkdir src/store/modules // 创建store 模块目录
touch src/store/modules/a.js // 创建 a 模块
touch src/store/modules/b.js // 创建 b 模块
touch src/store/index.js // 创建 store 模块入口文件
touch src/components/a.vue // 创建子组件a
touch src/components/b.vue // 创建子组件b
// a.js
const state = {
money: 10
}
const mutations = {
add(state) {
state.money++
},
reduce(state) {
state.money--
}
}
const actions = {
add: ({
commit
}) => {
commit('add')
},
reduce: ({
commit
}) => {
commit('reduce')
}
}
export default {
namespaced: true, //开启命名空间
state,
mutations,
actions
}
// b.js
const state = {
count: 1
}
const mutations = {
add(state, param) { // mutations 从 actions 上接收 param 参数并且使用
state.count += param
},
reduce(state) {
state.count--
}
}
const actions = {
add: ({
commit
}, param) => { // 这里param参数是从用户交互action行为上接收的参数
commit('add', param)
},
reduce: ({
commit
}) => {
commit('reduce')
}
}
export default {
namespaced: true, //开启命名空间
state,
mutations,
actions
}
// index.js store 入口文件
import Vue from 'vue' // 引入 vue
import Vuex from 'vuex' // 引入 vuex
import money from './modules/a' // 引入模块a
import count from './modules/b' // 引入模块b
Vue.use(Vuex) // 引入Vue的全局模块 Vuex
export default new Vuex.Store({
modules: { // 导出模块
money, // 子模块a
count // 子模块b
}
})
// a.vue
<template>
<div class="a">
<!-- 注意:这里从money模块下取state数据 money -->
page a{{$store.state.money.money}}
<button @click="add">添加</button>
<button @click="reduce">删减</button>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods: mapActions('money', ['add', 'reduce'])
// 这里mapActions 接收两个参数,第一个参数是store 子模块名,第二个参数是actions的行为
}
</script>
// b.vue
<template>
<div class="b">
<!-- 注意:这里从count模块下取state数据 count-->
page b{{$store.state.count.count}}
<!-- 想要mutation 对数据的操作可控,可以在用户交互的 action上传参,在b.js 的actions 接收参数 -->
<button @click="add(2)">添加</button>
<button @click="reduce">删减</button>
</div>
</template>
<script>
import { mapActions } from 'vuex';
export default {
methods: mapActions('count', ['add', 'reduce'])
// 这里mapActions 接收两个参数,第一个参数是store 子模块名,第二个参数是actions的行为
}
</script>
// App.vue
<template>
<div id="app">
<!--在dom里引入组件a和b-->
<pagea />
<pageb />
</div>
</template>
<script>
import pagea from './components/a' // 引入组件a
import pageb from './components/b' // 引入组件b
export default {
name: 'app',
components: {
pagea, // 注册组件 a
pageb //注册组件 b
}
}
</script>
// 项目主入口文件 main.js
import Vue from 'vue'
import App from './App'
import store from './store/index' // 引入 store 模块入口文件
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store // 把Vuex的实例引入Vue实例中
}).$mount('#app')
本文深入探讨了Vue.js中状态管理库Vuex的工作原理和使用方法,包括如何通过state、mutations、actions和getters实现多组件间的数据共享,以及如何在实际项目中应用这些概念。
493

被折叠的 条评论
为什么被折叠?



