uniapp中vuex的应用使用步骤

作者:青团子

时间:2026-10-25

浏览:154

本文详细讲解在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 应用内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章