前言
本文将介绍Vuex的用法。
Vuex
介绍
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。(官方解释)
- 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
- Vuex也集成到Vue的官方调试工具
devtools
、extension
,提供了诸如零配置的time-travel
调试、状态快照导入导出等高级调试功能。
简单理解:不同的组件需要访问一些同一状态量,如果把这些状态量随意定义到任意组件中都不合适,我们希望能够有一个对象对这些共享状态量进行统一封装,而Vuex就是这样一个提供在多个组件间共享状态的插件。
举例一些共享状态量:用户的登陆状态、用户名称、头像、地理位置信息等。
安装
打开终端,进入项目目录,键入如下命令(注意版本号):
基本使用
共享状态量会统一放一起管理,在项目的src
文件夹下新建一个名为store
的文件夹,在其中新建index.js
文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { counter: 1 }, mutations:{}, actions:{}, getters:{}, modules:{} })
export default store
|
这里在store对象中的state
属性中定义了一个counter
(之后用于其他组件的访问)
注意:
- Vuex专门提供了一个
Store
类,初始化应创建store对象
- Store对象中有五种常用属性:
state
、mutations
、actions
、getters
、modules
(之后会详细介绍)
接着在项目的main.js
文件中导入并注册store组件:
1 2 3 4 5 6 7 8 9 10 11
| import Vue from 'vue' import App from './App' import store from './store'
Vue.config.productionTip = false
new Vue({ el: '#app', store, render: h => h(App) })
|
一切准备完成之后就可以在组件中直接访问定义的共享状态量counter
了,这里以App.vue
为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <template> <div id="app"> <h2>我是App标题</h2> <h2>{{$store.state.counter}}</h2> <button @click="$store.state.counter++">+</button> <button @click="$store.state.counter--">-</button> </div> </template>
<script>
export default { name: 'App', data() { return { message: '我是App页面内容' } }, } </script>
<style>
</style>
|
说明:
可以直接通过$store.state.xxx
的形式访问,但是一般不会直接访问并随意修改其状态。
Vuex的状态管理
Vue官方提供了一个Vuex状态管理图例:
当然可以直接在组件中修改状态量,但是官方并不建议这么做。因为在最初介绍的时候提到过一些调试工具,如接下来要讲的devtools
,当多个组件实例对同一状态量进行修改时,它可以对该状态量进行跟踪,方便调试。如果跨过Mutations
直接对状态量进行修改,则调试工具就不能够跟踪。
在浏览器的扩展中查找Vue.js devtools
插件:
可以看到提供方就是Vue官方。
下载完成之后就可以看到在有Vue项目页面的情况下,开发者工具中就会多出一个Vue的选项。
注意:安装完插件后需要重新启动浏览器才可以看到。
利用该插件就可以对Vue项目中的内容做一些跟踪查看:
mutations用法
正常想要改变状态量的值需要通过mutations(Store对象中的一个属性),可以在其中定义方法:
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { counter: 1 }, mutations:{ increase(state) { state.counter++ }, decrease(state) { state.counter-- } }, actions:{}, getters:{}, modules:{} })
export default store
|
说明:
在mutations
属性中可以定义方法,其中传入的参数就是state
对象,通过在其中定义方法去修改状态量。
接着就是在组件中调用定义的方法:
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <template> <div id="app"> <h2>我是App标题</h2> <h2>{{$store.state.counter}}</h2> <button @click="add">+</button> <button @click="reduce">-</button> </div> </template>
<script>
export default { name: 'App', methods: { add() { this.$store.commit('increase') }, reduce() { this.$store.commit('decrease') } } } </script>
<style>
</style>
|
说明:
实例中需要再在methods
属性中定义对应的方法去调用mutations
中的方法,语法如下:
$store.commit('方法名')
最后就可以使用Devtools调试工具跟踪状态量的变化情况。
Getters
getters
是Store对对象中的五个属性之一。
基本使用
getters的一个用法类似于组件中的computed计算属性。
例如,要多次获取state属性中的counter值乘100,不必在每次调用时都去计算,而是在getters中定义一个计算属性:
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { counter: 1 }, mutations:{ increase(state) { state.counter++ }, decrease(state) { state.counter-- } }, actions:{}, getters:{ mul(state) { return state.counter*100 } }, modules:{} })
export default store
|
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <template> <div id="app"> <h2>我是App标题</h2> <h2>{{$store.state.counter}}</h2> <button @click="add">+</button> <button @click="reduce">-</button> <h2>获取mul的值:{{$store.getters.mul}}</h2> </div> </template>
<script>
export default { name: 'App', methods: { add() { this.$store.commit('increase') }, reduce() { this.$store.commit('decrease') } } } </script>
<style>
</style>
|
说明:
调用语法:$store.getters.xxx
参数传递
getters中也可以使用一些高阶函数来实现一些功能。
以过滤器filter
为例,现在在state
属性中定义了students
数组,里面存放了一些学生信息,希望通过getter实现一些信息过滤(获取年龄大于20岁的学生信息):
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { students: [ {id: 110, name: '张三', age: 18}, {id: 111, name: '李四', age: 24}, {id: 112, name: '王五', age: 30}, {id: 113, name: '赵六', age: 10} ], }, mutations:{}, actions:{}, getters:{ studentsShow(state) { return state.students.filter(s => s.age > 20) } }, modules:{} })
export default store
|
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <template> <div id="app"> <h2>我是App标题</h2> <h2>获取学生信息:{{$store.getters.studentsShow}}</h2> </div> </template>
<script>
export default { name: 'App', } </script>
<style>
</style>
|
如果想要获取年龄大于20岁的学生人数,可以如下操作:
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { students: [ {id: 110, name: '张三', age: 18}, {id: 111, name: '李四', age: 24}, {id: 112, name: '王五', age: 30}, {id: 113, name: '赵六', age: 10} ], }, mutations:{}, actions:{}, getters:{ studentsShow(state) { return state.students.filter(s => s.age > 20) }, studentsNumber(state,getters) { return getters.studentsShow.length } }, modules:{} })
export default store
|
说明:
- 方式一:仍使用state属性,但是返回值书写过于繁杂
- 方式二:可以在参数中传递getters属性,利用
studentsShow
获取列表长度
App.vue
:
1 2 3 4 5 6 7
| <template> <div id="app"> <h2>我是App标题</h2> <h2>获取学生信息:{{$store.getters.studentsShow}}</h2> <h2>获取学生人数:{{$store.getters.studentsNumber}}</h2> </div> </template>
|
如果学生过滤的条件想让前端用户输入而不是在index.js
中写死,那么getters中定义的计算属性可以返回函数:
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { students: [ {id: 110, name: '张三', age: 18}, {id: 111, name: '李四', age: 24}, {id: 112, name: '王五', age: 30}, {id: 113, name: '赵六', age: 10} ], }, mutations:{}, actions:{}, getters:{ studentsShow(state) { return function(age) { return state.students.filter(s => s.age > age) } }, }, modules:{} })
export default store
|
还可以使用箭头函数简写:
1 2 3 4 5
| studentsShow(state) { return age => { return state.students.filter(s => s.age > age) } },
|
可以在App.vue
中动态接收参数:
1 2 3 4 5 6
| <template> <div id="app"> <h2>我是App标题</h2> <h2>获取学生信息:{{$store.getters.studentsShow(25)}}</h2> </div> </template>
|
Mutations
基本使用
前面也提到过Mutations是为了更新store的状态(且官方也指出这是Vuex更新状态量的唯一方式)。
Mutation主要包括两部分:
参数传递
参数唯一
在通过mutation更新数据的时候,有时希望附带一些额外的参数。
仍然以计数器案例展示效果,现在希望在Vue模板中仅调用一个方法就实现不同的计数按钮:
首先就需要在index.js
文件中的mutation内定义该方法(含参):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { counter: 1 }, mutations:{ increase(state, num) { state.counter += num }, decrease(state, num) { state.counter -= num }, }, actions:{}, getters:{}, modules:{} })
export default store
|
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <template> <div id="app"> <h2>我是App标题</h2> <h2>{{$store.state.counter}}</h2> <button @click="add(5)">+5</button> <button @click="reduce(5)">-5</button> </div> </template>
<script>
export default { name: 'App', methods: { add(number) { this.$store.commit('increase',number) }, reduce(number) { this.$store.commit('decrease',number) } } } </script>
<style>
</style>
|
说明:
仅依次案例展示mutation的参数传递,该参数可以为其他类型(如:对象)。
payload(多个参数)
实际上通过mutation更新状态量时,被传递的参数称为mutation的载荷(Payload,是一个对象)。在传递参数的数量仅为一个的时候,可以用上面的方法。如果要传递多个参数,建议使用Payload。
案例:在上一个计数器的基础上多增加一个描述信息传递:
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { counter: 1 }, mutations:{ increase(state, payload) { state.counter += payload.number console.log(payload.desc) }, decrease(state, payload) { state.counter -= payload.number console.log(payload.desc) }, }, actions:{}, getters:{}, modules:{} })
export default store
|
说明:
Vue对象传递过来的对象类型的参数用payload接收,在使用的时候也从payload中调用多个参数。
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <template> <div id="app"> <h2>我是App标题</h2> <h2>{{$store.state.counter}}</h2> <button @click="add(5)">+5</button> <button @click="reduce(5)">-5</button> </div> </template>
<script>
export default { name: 'App', methods: { add(number) { this.$store.commit({ type: 'increase', number, desc: '执行计数器加法' }) }, reduce(number) { this.$store.commit({ type: 'decrease', number, desc: '执行计数器减法' }) } } } </script>
<style>
</style>
|
说明:
commit的参数为一个对象,其中包含有type用于指明提交的事件类型,以及其他参数。
响应式规则
注意:vue4版本已更新该规则。
如果是在state中已经定义并且初始化的数据,则这些数据都是响应式的(即对数据做修改后会在页面实时显示),但是未在state中定义的数据,并且想要在方法中进行增添或删除的操作,则该操作就是非响应式的(虽然数据被已修改,但是并不会在页面实时显示)。
以学生信息增添为例:
定义在state的学生对象中共有id
、name
、age
三种属性,如果想要增添一个address
的信息,有可能会出现非响应式的情况:
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { studetInfo: { id: 110, name: '张三', age: 18} }, mutations:{ updateInfo(state) { state.studetInfo['address'] = '北京' } }, actions:{}, getters:{}, modules:{} })
export default store
|
说明:
这里使用的更新数据的方式为:state.studetInfo['address'] = '北京'
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <template> <div id="app"> <h2>我是App标题</h2> <h2>{{$store.state.studetInfo}}</h2> <button @click="updateInfo">更新</button> </div> </template>
<script>
export default { name: 'App', methods: { updateInfo() { return this.$store.commit('updateInfo') } } } </script>
<style>
</style>
|
效果如下:
可以看到右侧确实显示有添加了address
的信息,但是左侧页面并无显示。
如果想要做到响应式,则需要使用Vue.set
方法:
1 2 3
| updateInfo(state) { Vue.set(state.studetInfo, 'address', '北京') }
|
Vue.set
参数说明:
Vue.set(状态量名, 属性名, 属性值)
如果要删除的话,类似的可以使用Vue.delete
方法:
Vue.delete(状态量名, 属性名)
例如删除学生age
属性:
1 2 3
| updateInfo(state) { Vue.delete(state.studetInfo, 'age') }
|
常量类型
在修改状态量时规定需要经过mutations,但是在实际开发中会定义许多事件类型(方法名称),相应的在vue对象中也需要提交不同的commit参数。不便于后期的管理,也容易出错。因此官方给出了一种方案:使用常量代替Mutations中的事件类型。
(仍以计数器案例展示)
首先在store文件夹中创建mutations-types.js
,在其中定义常量:
1 2
| export const INCREASE = 'increase' export const DECREASE = 'decrease'
|
然后在index.js
中导入并使用这些常量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import Vue from 'vue' import Vuex from 'vuex' import * as types from './mutations-types'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { counter: 1 }, mutations:{ [types.INCREASE](state) { state.counter++ }, [types.DECREASE](state) { state.counter-- } }, actions:{}, getters:{ }, modules:{} })
export default store
|
注意:
此时的事件类型需要用中括号包裹常量使用。
在App.vue
中导入并使用这些常量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <template> <div id="app"> <h2>我是App标题</h2> <h2>{{$store.state.counter}}</h2> <button @click="add">+</button> <button @click="reduce">-</button> </div> </template>
<script> import {INCREASE,DECREASE} from './store/mutations-types'
export default { name: 'App', methods: { add() { this.$store.commit(INCREASE) }, reduce() { this.$store.commit(DECREASE) } } } </script>
<style>
</style>
|
Actions
Mutations同步说明
Vuex要求Mutation中更新状态量的方法必须是同步方法,如果在其中实现异步方法,那么Devtools检测工具就会失效,无法跟踪状态量的变化。
下面仍以setTimeout()
代替实现异步方法,做一个信息打印案例:
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { message: '原始信息' }, mutations:{ showMessage(state) { setTimeout(() => { state.message = '更新信息' },1000) } }, actions:{}, getters:{ }, modules:{} })
export default store
|
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <template> <div id="app"> <h2>我是App标题</h2> <h2>{{$store.state.message}}</h2> <button @click="update">更新</button> </div> </template>
<script>
export default { name: 'App', methods: { update() { return this.$store.commit('showMessage') } } } </script>
<style>
</style>
|
效果如下:
可以看到页面信息进行了更新,但是检测工具并未捕捉到状态量的变化。(实际状态量确实发生了改变)
说明:插件已开启自动更新状态量设置。
官方规定如果要定义异步方法(请求),需要经过Actions。
基本使用
操作
说明:
Actions仍然可以像Mutations一样在方法名处用常量类型调用方法,使用格式不变。
(出于演示方便,以下的代码中并未使用常量类型的形式)
Actions类似于Mutations,只是用来实现异步方法,使用的方式也类似。
接下来使用Actions完成上一个案例实现:
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { message: '原始信息' }, mutations:{ showMessage(state) { state.message = '更新信息' } }, actions:{ updateMessage(context) { setTimeout(() => { context.commit('showMessage') }, 1000) } }, getters:{ }, modules:{} })
export default store
|
说明:
-
context
:上下文。是actions定义异步方法中的参数,是和state对象具有相同的方法和属性的对象。所以可以通过context去进行commit
相关的操作, 也可以获取context.state
等。
-
异步方法(请求)的实现思路如下:
在actions中定义方法去实现异步请求,如果需要改变状态量,则仍需要调用mutations中的同步方法,在同步方法中实现对状态量的更新。
注意:如果跳过mutations直接改变状态量是没有效果的。
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <template> <div id="app"> <h2>我是App标题</h2> <h2>{{$store.state.message}}</h2> <button @click="update">更新</button> </div> </template>
<script>
export default { name: 'App', methods: { update() { return this.$store.dispatch('updateMessage') } } } </script>
<style>
</style>
|
说明:
在Vue实例中通过$store.dispatch('方法名')
去调用actions中定义的异步方法。
效果如下:
可以看到插件可以正常跟踪到状态量的变化情况。
payload
同样的,actions中也支持payload对象的参数传递。
案例:vue实例传递一条消息(以对象的形式),actions进行接收并传递给mutations,最后由mutations中的方法执行控制台打印。
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { message: '原始信息' }, mutations:{ showMessage(state, payload) { state.message = '更新信息' console.log(payload.message) } }, actions:{ updateMessage(context, payload) { setTimeout(() => { context.commit('showMessage', payload) }, 1000) } }, getters:{ }, modules:{} })
export default store
|
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <template> <div id="app"> <h2>我是App标题</h2> <h2>{{$store.state.message}}</h2> <button @click="update">更新</button> </div> </template>
<script>
export default { name: 'App', methods: { update() { return this.$store.dispatch({ type: 'updateMessage', message: '原始信息已被修改' }) } } } </script>
<style>
</style>
|
(效果展示省略)
Promise的应用
如果希望Vue实例在调用异步方法(请求)时返回一些执行结果(用以判断请求是否成功)可以结合Promise使用。
案例需求同上:
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { message: '原始信息' }, mutations:{ showMessage(state) { state.message = '更新信息' } }, actions:{ updateMessage(context) { return new Promise((resolve, reject) => { setTimeout(() => { context.commit('showMessage') resolve('信息已完成更新') }, 1000) }) } }, getters:{ }, modules:{} })
export default store
|
说明:
在updateMessage方法中返回一个新的Promise
对象,内部实现异步请求的操作,并通过resolve
将数据传递给then
进一步处理。但是then
会在Vue实例中实现。
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <template> <div id="app"> <h2>我是App标题</h2> <h2>{{$store.state.message}}</h2> <button @click="update">更新</button> </div> </template>
<script>
export default { name: 'App', methods: { update() { return this.$store.dispatch('updateMessage').then((data) => { console.log(data) }) } } } </script>
<style>
</style>
|
重点理解:
update方法返回了actions中定义的updateMessage方法,而该方法返回了一个新的Promise
对象,所以在这里this.$store.dispatch('updateMessage')
就是一个Promise
对象,因而可以在其后直接链接一个then
函数,内部的data
参数就接收了来自actions中利用Promise异步请求来的数据。
效果展示:
modules
Vue实例中很多状态量都是交由Vuex中的store来保管,但是在当应用非常复杂时,store对象就会变得非常臃肿,这时就可以使用modules对store对象中的状态量进行分模块进行抽离。
每个模块都有自己的state
、mutations
、actions
、getters
,也有modules
(但一般不会再进行模块抽离)
基本使用
可以直接在store中定义各类modules,但是建议将其抽离出来单独写,然后在store中注册,格式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const moduleA = { state: {...}, mutations: {...}, actions: {...}, getters: {...}, }
const moduleB = { state: {...}, mutations: {...}, actions: {...}, getters: {...}, }
const store = new Vuex.store({ modules: { a: moduleA, b: moduleB, } })
|
state使用
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const ModuleTest = { state: { message: '我是模块信息' }, mutations:{}, actions:{}, getters:{}, }
const store = new Vuex.Store({ state: {}, mutations:{}, actions:{}, getters:{}, modules:{ ModuleTest: ModuleTest } })
export default store
|
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <template> <div id="app"> <h2>我是App标题</h2> <h2>{{$store.state.ModuleTest.message}}</h2> </div> </template>
<script>
export default { name: 'App', } </script>
<style>
</style>
|
说明:
用法:$store.state.模块名.属性名
效果如下:
getters使用
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const ModuleTest = { state: { counter: 1 }, mutations:{}, actions:{}, getters:{ mulModule(state) { return state.counter*100 }, mulRoot(state, mulModule, rootState) { return rootState.counter*100 } }, }
const store = new Vuex.Store({ state: { counter: 2 }, mutations:{}, actions:{}, getters:{}, modules:{ ModuleTest: ModuleTest } })
export default store
|
说明:
模块中getters方法内参数的定义:方法名(state, 其他方法名, rootState)
注意参数位置不能颠倒。
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <template> <div id="app"> <h2>我是App标题</h2> <h2>Modules原始数据:{{$store.state.ModuleTest.counter}}</h2> <h2>修改Modules数据:{{$store.getters.mulModule}}</h2> <h2>Root原始数据:{{$store.state.counter}}</h2> <h2>修改Root数据:{{$store.getters.mulRoot}}</h2> </div> </template>
<script>
export default { name: 'App', } </script>
<style>
</style>
|
说明:
在访问模块中的getters方法时不用特意指明模块,直接指出方法名就好,格式:
$store.getters.方法名
效果如下:
mutations使用
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const ModuleTest = { state: { counter: 1 }, mutations:{ increase(state, payload) { console.log(payload.message) return state.counter += 1 }, decrease(state, payload) { console.log(payload.message) return state.counter -= 1 } }, actions:{}, getters:{}, }
const store = new Vuex.Store({ state: {}, mutations:{}, actions:{}, getters:{}, modules:{ ModuleTest: ModuleTest } })
export default store
|
说明:
操作与store中的mutations一致。
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <template> <div id="app"> <h2>我是App标题</h2> <h2>Modules数据:{{$store.state.ModuleTest.counter}}</h2> <button @click="add">+</button> <button @click="reduce">-</button> </div> </template>
<script>
export default { name: 'App', methods: { add() { return this.$store.commit({ type: 'increase', message: '数据已增加' }) }, reduce() { return this.$store.commit({ type: 'decrease', message: '数据已减少' }) } } } </script>
<style>
</style>
|
说明:
在访问模块中的mutations方法时不用特意指明模块,直接指出方法名就好,格式:
$store.commit('方法名')
$store.commit(payload对象)
效果如下:
actions使用
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const ModuleTest = { state: { message: 'Module原始信息' }, mutations:{ updateMessage(state) { state.message = 'Module信息已被修改' } }, actions:{ update(context) { return new Promise((resolve, reject) => { setTimeout(() => { context.commit('updateMessage') resolve('信息修改已完成') }, 1000) }) } }, getters:{}, }
const store = new Vuex.Store({ state: {}, mutations:{}, actions:{}, getters:{}, modules:{ ModuleTest: ModuleTest } })
export default store
|
说明:
操作与store中的actions一致。
App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <template> <div id="app"> <h2>我是App标题</h2> <h2>{{$store.state.ModuleTest.message}}</h2> <button @click="updateM">更新</button> </div> </template>
<script>
export default { name: 'App', methods: { updateM() { return this.$store.dispatch('update').then((data) => { console.log(data) }) } } } </script>
<style>
</style>
|
说明:
在访问模块中的actions方法时不用特意指明模块,直接指出方法名就好,格式:
$store.dispatch('方法名')
效果展示:
项目结构
为了更清晰明了的编写项目,以及后期方便维护,建议将Vuex.Store对象中的mutations
、actions
、getters
、modules
进行抽离,建立新的文件(state
状态量仍然在index.js
文件中):
index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import Vue from 'vue' import Vuex from 'vuex'
import mutations from './mutations' import actions from './actions' import getters from './getters' import ModuleA from './modules/ModuleA' import ModuleB from './modules/ModuleB'
Vue.use(Vuex)
const state = { message: '项目结构' }
const store = new Vuex.Store({ state, mutations, actions, getters, modules:{ ModuleA: ModuleA, ModuleB: ModuleB, } })
export default store
|
mutations.js
:
1 2 3 4
| export default { Mmethod1(state, payload) {...}, Mmethod2(state, payload) {...}, }
|
actions.js
:
1 2 3 4
| export default { Amethod1(context) {...}, Amethod2(context) {...}, }
|
getters.js
:
1 2 3 4 5
| export default { Gmethod1(state) {...}, Gmethod2(state, Gmethod1) {...}, Gmethod3(state, Gmethod2, rootState) {...}, }
|
模块会再新建一个文件夹:
./modules/ModuleA
:
1 2 3 4 5 6
| export default { state: {...}, mutations: {...}, actions: {...}, getters: {...}, }
|
./modules/ModuleB
:
1 2 3 4 5 6
| export default { state: {...}, mutations: {...}, actions: {...}, getters: {...}, }
|
后记
在做项目的时候也需要注意一些代码结构的细节,到后期代码量增加的时候便于维护。