uniapp中vuex的应用使用步骤
本文详细讲解在uniapp项目中集成和使用Vuex状态管理的完整流程。涵盖从store目录初始化、state数据存取、getters计算属性、mutations同步修改到actions异步处理的各项核心API。同时深入解析Module模块化拆分方案,通过mapState/mapGetters等辅助函数优化组件代码,帮助开发者高效管理复杂应用的全局状态。
一、Vuex 概述
Vuex 是专为 Vue.js 应用设计的状态管理模式,采用集中式存储管理所有组件状态,并依据特定规则确保状态以可预测方式变更。
从理解层面看,它是公共数据管理模块。若应用数据量大建议使用,数据量小则建议直接使用缓存。
二、使用步骤
准备工作:在项目中新建 store 目录,并在该目录下创建 index.js 文件。
1. 引入
由于 uniapp 内置了 Vuex,只需按规范引入即可:
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);//vue的插件机制
//Vuex.Store 构造器选项
const store = new Vuex.Store({
state:{//存放状态
"username":"foo",
"age":18
}
})
export default store
// 页面路径:main.js
import Vue from 'vue'
import App from './App'
import store from './store'
Vue.prototype.$store = store
App.mpType = 'app'
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
const app = new Vue({
store,
...App
})
app.$mount()
2. state 属性,主要用于存储数据
方法一:通过属性访问,需在根节点注入 store。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<text>用户名:{{username}}</text>
</view>
</template>
<script>
import store from '@/store/index.js';//需要引入store
export default {
data() {
return {}
},
computed: {
username() {
return store.state.username
}
}
}
</script>
方法二:在组件中通过 this.$store 访问 state 中的数据。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<text>用户名:{{username}}</text>
</view>
</template>
<script>
export default {
data() {
return {}
},
computed: {
username() {
return this.$store.state.username
}
}
}
</script>
进阶方法:利用 mapState 辅助函数获取。当组件需获取多个状态时,将其全部声明为计算属性会导致重复和冗余。使用 mapState 辅助函数可生成计算属性,减少按键操作(即简写,避免逐个声明导致代码臃肿)。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view>用户名:{{username}}</view>
<view>年龄:{{age}}</view>
</view>
</template>
<script>
import { mapState } from 'vuex'//引入mapState
export default {
data() {
return {}
},
computed: mapState({
// 从state中拿到数据 箭头函数可使代码更简练(就是简写)
username: state => state.username,
age: state => state.age,
})
}
</script>
3. Getter 属性,主要用于计算和筛选数据
可视为 store 的计算属性,是对 state 的加工及派生数据。如同 computed 计算属性,getter 返回值会基于其依赖被缓存,仅当依赖值改变时才重新计算(重点:响应式数据应用)。
可在多组件中共享 getter 函数,此举还能提升运行效率。
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
todos: [{
id: 1,
text: '我是内容一',
done: true
},
{
id: 2,
text: '我是内容二',
done: false
}
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
export default store
Getter 属性接收参数,主要为 state(若在模块中定义则为模块局部状态)及 getters(等同于 store.getters)。
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
todos: [{
id: 1,
text: '我是内容一',
done: true
},
{
id: 2,
text: '我是内容二',
done: false
}
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
},
doneTodosCount: (state, getters) => {
//state :可以访问数据
//getters:访问其他函数,等同于 store.getters
return getters.doneTodos.length
},
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
})
export default store
应用 Getter 属性方法一:通过属性访问,Getter 会暴露为 store.getters 对象,可将其以属性形式访问。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view v-for="(item,index) in todos">
<view>{{item.id}}</view>
<view>{{item.text}}</view>
<view>{{item.done}}</view>
</view>
</view>
</template>
<script>
import store from '@/store/index.js'//需要引入store
export default {
computed: {
todos() {
return store.getters.doneTodos
}
}
}
</script>
应用 Getter 属性方法二:通过 this.$store 访问。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view v-for="(item,index) in todos">
<view>{{item.id}}</view>
<view>{{item.text}}</view>
<view>{{item.done}}</view>
</view>
</view>
</template>
<script>
export default {
computed: {
todos() {
return this.$store.getters.doneTodos
}
}
}
</script>
应用 Getter 属性方法三:通过让 getter 返回函数来实现传参,这在查询 store 内数组时非常有用。注意,通过方法访问 getter 时每次都会调用,不会缓存结果(即一次调用一次请求,无依赖关系)。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view v-for="(item,index) in todos">
<view>{{item}}</view>
</view>
</view>
</template>
<script>
export default {
computed: {
todos() {
return this.$store.getters.getTodoById(2)
}
}
}
</script>
应用 Getter 属性进阶(简写):通过 mapGetters 辅助函数访问。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view>{{doneTodosCount}}</view>
</view>
</template>
<script>
import {mapGetters} from 'vuex' //引入mapGetters
export default {
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodos',
'doneTodosCount',
// ...
])
}
}
</script>
4. Mutation 属性,Vuex 中 store 数据改变的唯一位置(数据必须同步)
通俗理解,mutations 包含改变数据的方法集合,所有处理数据逻辑的方法均置于 mutations 中,实现数据与视图分离。Vuex 中的 mutation 类似事件:每个 mutation 拥有字符串类型 (type) 和回调函数 (handler)。回调函数即实际进行状态更改的地方,并接受 state 作为第一个参数:
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state) {
// 变更状态
state.count += 2
}
}
})
export default store
不能直接调用 mutation handler。该选项类似事件注册:“当触发类型为 add 的 mutation 时,调用此函数”。要唤醒 mutation handler,需以相应 type 调用 store.commit 方法。注意:store.commit 调用 mutation(需在根节点注入 store)。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view>数量:{{count}}</view>
<button @click="addCount">增加</button>
</view>
</template>
<script>
import store from '@/store/index.js'
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
addCount() {
store.commit('add')
}
}
}
</script>
mutation 中的函数接收参数:可向 store.commit 传入额外参数,即 mutation 的载荷(payload):
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
//传递数值
add(state, n) {
state.count += n
}
//传递对象类型
add(state, payload) {
state.count += payload.amount
}
}
})
export default store
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view>数量:{{count }}</view>
<button @click="addCount">增加</button>
</view>
</template>
<script>
import store from '@/store/index.js'
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
//传递数值
addCount() {
store.commit('add', 5)//每次累加 5
}
//传递对象
addCount () {//把载荷和type分开提交
store.commit('add', { amount: 10 })
}
}
}
</script>
应用 Getter 属性方法二:通过 this.$store 访问。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view v-for="(item,index) in todos">
<view>{{item.id}}</view>
<view>{{item.text}}</view>
<view>{{item.done}}</view>
</view>
</view>
</template>
<script>
export default {
computed: {
todos() {
return this.$store.getters.doneTodos
}
}
}
</script>
应用 mutation 属性进阶(简写):通过 mapMutations 辅助函数访问。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view>数量:{{count}}</view>
<button @click="add">增加</button>
</view>
</template>
<script>
import { mapMutations } from 'vuex'//引入mapMutations
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
...mapMutations(['add'])//对象展开运算符直接拿到add
}
}
</script>
5. Action 属性:
action 提交的是 mutation,通过 mutation 来改变 state,而非直接变更状态。action 可包含任意异步操作。
// 页面路径:store/index.js
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 1
},
mutations:{
add(state) {
// 变更状态
state.count += 2
}
},
actions:{
addCountAction (context) {
context.commit('add')
}
}
})
export default store
action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此可调用 context.commit 提交 mutation,或通过 context.state 和 context.getters 获取 state 和 getters。
actions 通过 store.dispatch 方法触发:
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view>数量:{{count}}</view>
<button @click="add">增加</button>
</view>
</template>
<script>
import store from '@/store/index.js';
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
add () {
store.dispatch('addCountAction')
}
}
}
</script>
actions 支持以载荷形式分发:
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 1
},
mutations:{
add(state, payload) {
state.count += payload.amount
}
},
actions:{
addCountAction (context , payload) {
context.commit('add',payload)
}
}
})
export default store
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view>数量:{{count }}</view>
<button @click="add">增加</button>
</view>
</template>
<script>
import store from '@/store/index.js';
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
add () {
// 以载荷形式分发
store.dispatch('addCountAction', {amount: 10})
}
add () {
// 以对象形式分发
store.dispatch({
type: 'addCountAction',
amount: 5
})
}
}
}
</script>
actions 的异步:
// 页面路径:store/index.js
//调用mutations的方法来改变数据(同步、异步)
actions:{
//异步调用
actionA({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('add',5)
resolve()
}, 2000)
})
}
actionB ({ dispatch, commit }) {
return dispatch('actionA').then(() => {commit('someOtherMutation')
})
async actionA ({ commit }) {commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
}
}
应用 Actions 属性进阶(简写):通过 mapActions 辅助函数访问。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view>数量:{{count }}</view>
<button @click="addCountAction">增加</button>
</view>
</template>
<script>
import { mapActions } from 'vuex'
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
...mapActions([
'addCountAction',
// 将 `this.addCountAction()` 映射为 `this.$store.dispatch('addCountAction')`
])
}
}
</script>
6. Module 结构。
由于使用单一状态树,应用所有状态会集中到一个较大对象。当应用变得非常复杂时,store 对象可能相当臃肿。为解决此问题,Vuex 允许将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter,甚至嵌套子模块——从上至下进行相同方式的分割:
1. 在 store 文件夹下新建 modules 文件夹,并在下面新建 moduleA.js 和 moduleB.js 文件以存放 vuex 的 modules 模块。
├── components # 组件文件夹 └── myButton └── myButton.vue # myButton组件 ├── pages └── index └── index.vue # index页面 ├── static ├── store ├── index.js # 我们组装模块并导出 store 的地方 └── modules # 模块文件夹 ├── moduleA.js # 模块moduleA └── moduleB.js # 模块moduleB ├── App.vue ├── main.js ├── manifest.json ├── pages.json └── uni.scss
2. 在 main.js 文件中引入 store。
// 页面路径:main.js
import Vue from 'vue'
import App from './App'
import store from './store'
Vue.prototype.$store = store
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
const app = new Vue({
store,
...App
})
app.$mount()
3. 在项目根目录下,新建 store 文件夹,并在下面新建 index.js 文件作为模块入口,引入各子模块。
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import moduleA from '@/store/modules/moduleA'
import moduleB from '@/store/modules/moduleB'
Vue.use(Vuex)
export default new Vuex.Store({
modules:{
moduleA,moduleB
}
})
4. 子模块 moduleA 页面内容。
// 子模块moduleA路径:store/modules/moduleA.js
export default {
state: {
text:"我是moduleA模块下state.text的值"
},
getters: {
},
mutations: {
},
actions: {
}
}
5. 子模块 moduleB 页面内容。
// 子模块moduleB路径:store/modules/moduleB.js
export default {
state: {
timestamp: 1608820295//初始时间戳
},
getters: {
timeString(state) {//时间戳转换后的时间
var date = new Date(state.timestamp);
var year = date.getFullYear();
var mon = date.getMonth()+1;
var day = date.getDate();
var hours = date.getHours();
var minu = date.getMinutes();
var sec = date.getSeconds();
var trMon = mon<10 ? '0'+mon : mon
var trDay = day<10 ? '0'+day : day
return year+'-'+trMon+'-'+trDay+" "+hours+":"+minu+":"+sec;
}
},
mutations: {
updateTime(state){//更新当前时间戳
state.timestamp = Date.now()
}
},
actions: {
}
}
6. 在页面中引用组件 myButton,并通过 mapState 读取 state 中的初始数据。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view class="content">
<view>{{text}}</view>
<view>时间戳:{{timestamp}}</view>
<view>当前时间:{{timeString}}</view>
<myButton></myButton>
</view>
</template>
<script>
import {mapState,mapGetters} from 'vuex'
export default {
computed: {
...mapState({
text: state => state.moduleA.text,
timestamp: state => state.moduleB.timestamp
}),
...mapGetters([
'timeString'
])
}
}
</script>
7. 在组件 myButton 中,通过 mutations 操作刷新当前时间。
<!-- 组件路径:components/myButton/myButton.vue -->
<template>
<view>
<button type="default" @click="updateTime">刷新当前时间</button>
</view>
</template>
<script>
import {mapMutations} from 'vuex'
export default {
data() {
return {}
},
methods: {
...mapMutations(['updateTime'])
}
}
</script>
总结
vue 是单向数据流,子组件不能直接修改父组件数据,而通过 vuex 状态管理实现:将组件的共享状态抽取出来,以全局单例模式管理。在此模式下,组件树构成一个巨大的“视图”,无论位于树的哪个位置,任何组件都能获取状态或触发行为!
vuex 的整体结构并不复杂,只是规范较为繁琐,自己多尝试几次即可。
到此这篇关于 uniapp 中 vuex 应用使用的文章就介绍到这了,更多相关 uniapp 中 vuex 应用内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!
Vue.js 高阶组件封装与自定义 Hook 实战技巧
2026-11-05 17:15:22
怎么在Vue3项目中集成轻量级JS文本编辑器
2026-11-03 12:21:35
Vue.js官网怎么切换Vue 2与Vue 3版本文档?避免看错版本指南
2026-11-03 08:08:08
ElementUI el-switch 开关组件使用详解与高级应用
2026-10-31 15:21:18
Element UI 表格行按钮点击加载与状态管理实现
2026-10-31 14:12:32








