墨龙吟 2020-04-24
Vuex 允许我们将 store 分割成模块(module)。
每个模块拥有自己的 state、mutation、action、getter、
甚至是嵌套子模块——从上至下进行同样方式的分割:
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象。
const moduleA = {
state: { count: 0 },
mutations: {
increment (state) {
// 这里的 `state` 对象是模块的局部状态
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}同样,对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState:
const moduleA = {
// ...
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit(‘increment‘)
}
}
}
}对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:
const moduleA = {
// ...
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}默认情况下 注册在全局命名空间的 这样使得多个模块能够对同一 mutation 或 action 作出响应。
可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。
将 { root: true } 作为第三参数传给 dispatch 或 commit 即可
dispatch(‘someOtherAction‘) // -> ‘foo/someOtherAction‘
dispatch(‘someOtherAction‘, null, { root: true }) // -> ‘someOtherAction‘
commit(‘someMutation‘) // -> ‘foo/someMutation‘
commit(‘someMutation‘, null, { root: true }) // -> ‘someMutation‘若需要在带命名空间的模块注册全局 action,你可添加 root: true,并将这个 action 的定义放在函数 handler 中。例如:
{
actions: {
someOtherAction ({dispatch}) {
dispatch(‘someAction‘)
}
},
modules: {
foo: {
namespaced: true,
actions: {
someAction: {
root: true,
handler (namespacedContext, payload) { ... } // -> ‘someAction‘
}
}
}
}
}computed: {
...mapState({
a: state => state.some.nested.module.a,
b: state => state.some.nested.module.b
})
},
methods: {
...mapActions([
‘some/nested/module/foo‘, // -> this[‘some/nested/module/foo‘]()
‘some/nested/module/bar‘ // -> this[‘some/nested/module/bar‘]()
])
}上面的例子可以简化为【如果有的方法在全局里,有的在模块中,则使用上面未简化版本】
computed: { ...mapState(‘some/nested/module‘, { a: state => state.a, b: state => state.b }) }, methods: { ...mapActions(‘some/nested/module‘, [ ‘foo‘, // -> this.foo() ‘bar‘ // -> this.bar() ]) }可以通过使用
createNamespacedHelpers创建基于某个命名空间辅助函数import { createNamespacedHelpers } from ‘vuex‘ const { mapState, mapActions } = createNamespacedHelpers(‘some/nested/module‘) export default { computed: { // 在 `some/nested/module` 中查找 ...mapState({ a: state => state.a, b: state => state.b }) }, methods: { // 在 `some/nested/module` 中查找 ...mapActions([ ‘foo‘, ‘bar‘ ]) } }
在 store 创建之后,你可以使用 store.registerModule 方法注册模块:
import Vuex from ‘vuex‘
const store = new Vuex.Store({ /* 选项 */ })
// 注册模块 `myModule`
store.registerModule(‘myModule‘, {
// ...
})
// 注册嵌套模块 `nested/myModule`
store.registerModule([‘nested‘, ‘myModule‘], {
// ...
})当你设置
preserveState: true时,该模块会被注册,action、mutation 和 getter 会被添加到 store 中,但是 state 不会。这里假设 store 的 state 已经包含了这个 module 的 state 并且你不希望将其覆写。
如果我们使用一个纯对象来声明模块的状态,那么这个状态对象会通过引用被共享,导致状态对象被修改时 store 或模块间数据互相污染的问题。
实际上这和 Vue 组件内的
data是同样的问题
使用一个函数来声明模块状态(仅 2.3.0+ 支持):
const MyReusableModule = {
state () {
return {
foo: ‘bar‘
}
},
// mutation, action 和 getter 等等...
}module.js
import Vue from ‘vue‘;
import ‘es6-promise/auto‘
import Vuex from ‘vuex‘;
Vue.use(Vuex);
const moduleA = {
namespaced: true,
state: {
name: ‘ModuleA‘,
count: 0,
price: 0,
total: 0,
},
getters: {
//計算moduleA中的count狀態值與root store中的count狀態值 之間的差值
countDistanceWithRootCount(state, getters, rootState) {
return state.count - rootState.count;
},
},
mutations: {
increment(state) {
state.count++;
state.total = state.price * state.count;
},
setName(state, payload) {
state.name = payload.name;
},
calculate(state, payload) {
state.total = state.price * payload;
},
},
actions: {
//儅大於主節點的count值時,使用主節點的count
useRootCountIfCountOverClocked({state, commit, rootState}) {
if (state.count > rootState.count) {
commit(‘calculate‘, rootState.count);
}
},
},
};
const moduleStore = new Vuex.Store({
state: {
count: 10,
},
modules: {
accountA: moduleA,
},
mutations: {
calculate(state, payload) {
//root store中同名的calculate方法
console.log(‘called!‘);
},
},
});
export default moduleStore;app.js
/**
* First we will load all of this project‘s JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require(‘./bootstrap‘);
window.Vue = require(‘vue‘);
// import store from ‘./Vuex/index‘;
import store from ‘./Vuex/module.js‘;
/**
*
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
// const files = require.context(‘./‘, true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split(‘/‘).pop().split(‘.‘)[0], files(key).default))
Vue.component(‘example-component‘, require(‘./components/ExampleComponent.vue‘).default);
Vue.component(‘store-component‘, require(‘./components/StoreComponent.vue‘).default);
Vue.component(‘module‘, require(‘./components/ModuleStore.vue‘).default);
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
const app = new Vue({
el: ‘#app‘,
store,
});ModuleStore.vue:
<template>
<div>
<table>
<tr>
<th>name</th>
<th>count</th>
<th>price</th>
<th>total</th>
</tr>
<tr>
<td>{{name}}</td>
<td>{{count}}</td>
<td>{{price}}</td>
<td>{{total}}</td>
</tr>
</table>
</div>
</template>
<script>
// import {mapState, mapActions, mapMutations, mapGetters} from ‘vuex‘;
import {createNamespacedHelpers} from ‘vuex‘;
const {mapState, mapActions, mapMutations, mapGetters} = createNamespacedHelpers(‘accountA‘);
export default {
name: "ModuleStore",
data: function () {
return {
pName: ‘‘,
pCount: 0,
pPrice: 0,
pTotal: 0,
}
},
computed: {
// ...mapState(‘accountA‘, [
// ‘name‘,
// ‘count‘,
// ‘price‘,
// ‘total‘,
// ]),
...mapState([
‘name‘,
‘count‘,
‘price‘,
‘total‘,
]),
...mapActions([
‘useRootCountIfCountOverClocked‘,
]),
},
}
</script>
<style scoped>
</style>web.php:
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get(‘/‘, function () {
return view(‘welcome‘);
});
Auth::routes();
Route::get(‘/home‘, ‘‘)->name(‘home‘);
Route::get(‘/store-test‘, function (Request $request) {
return view(‘store‘);
});
Route::get(‘/module‘, function (Request $request) {
return view(‘module‘);
});