uni-app 状态管理深度解析:Vuex 与全局方案实战指南
uni-app 状态管理深度解析:Vuex 与全局方案实战指南
一、Vuex 使用示例
1. 基础 Vuex 配置
1.1 项目结构
src/
├── store/
│ ├── index.js # 主入口文件
│ └── modules/
│ └── counter.js # 计数器模块
└── main.js # 应用入口
1.2 安装 Vuex
npm install vuex --save
2. 核心代码实现
2.1 主入口文件 (store/index.js)
import Vue from 'vue'
import Vuex from 'vuex'
import counter from './modules/counter'Vue.use(Vuex)export default new Vuex.Store({modules: {counter}
})
2.2 计数器模块 (store/modules/counter.js)
export default {state: {count: 0},mutations: {increment(state) {state.count++},decrement(state) {state.count--},setCount(state, value) {state.count = value}},actions: {incrementAsync({ commit }) {setTimeout(() => {commit('increment')}, 1000)}},getters: {doubleCount: state => state.count * 2}
}
2.3 应用入口 (main.js)
import Vue from 'vue'
import App from './App.vue'
import store from './store'Vue.config.productionTip = falsenew Vue({store,render: h => h(App)
}).$mount('#app')
3. 组件中使用示例
3.1 显示计数器 (CounterDisplay.vue)
<template><div><h2>计数器示例</h2><p>当前计数: {{ count }}</p><p>双倍计数: {{ doubleCount }}</p></div>
</template><script>
import { mapState, mapGetters } from 'vuex'export default {computed: {...mapState('counter', ['count']),...mapGetters('counter', ['doubleCount'])}
}
</script>
3.2 操作计数器 (CounterControls.vue)
<template><div><button @click="increment">+1</button><button @click="decrement">-1</button><button @click="incrementAsync">1秒后+1</button><input type="number" v-model.number="newCount"><button @click="setCount(newCount)">设置值</button></div>
</template><script>
import { mapMutations, mapActions } from 'vuex'export default {data() {return {newCount: 0}},methods: {...mapMutations('counter', ['increment', 'decrement', 'setCount']),...mapActions('counter', ['incrementAsync'])}
}
</script>
4. 完整应用示例 (App.vue)
<template><div id="app"><CounterDisplay /><CounterControls /></div>
</template><script>
import CounterDisplay from './components/CounterDisplay.vue'
import CounterControls from './components/CounterControls.vue'export default {name: 'App',components: {CounterDisplay,CounterControls}
}
</script>
5. 核心概念说明
- State - 存储应用状态数据
state: {count: 0
}
- Mutations - 修改状态的同步方法
mutations: {increment(state) {state.count++}
}
- Actions - 可以包含异步操作
actions: {incrementAsync({ commit }) {setTimeout(() => {commit('increment')}, 1000)}
}
- Getters - 计算派生状态
getters: {doubleCount: state => state.count * 2
}
- 模块化 - 按功能拆分模块
modules: {counter
}
6. Vuex 中访问数据(state)方式
在 Vuex 中访问数据(state)主要有以下几种方式,取决于你是在组件内还是组件外访问:
1. 在 Vue 组件中访问 Vuex 数据
(1) 使用 this.$store
在 Vue 组件中,可以通过 this.$store 访问 Vuex 的 state、getters、mutations 和 actions:
// 访问 state
this.$store.state.carData// 访问 getter
this.$store.getters.carDataGetter// 调用 mutation
this.$store.commit('setCarData', payload)// 调用 action
this.$store.dispatch('fetchCarData', payload)
(2) 使用 mapState、mapGetters、mapMutations、mapActions
Vuex 提供了辅助函数,可以更方便地在组件中引入 Vuex 数据和方法:
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'export default {computed: {// 映射 state.carData 到 this.carData...mapState(['carData']),// 映射 getters.carDataGetter 到 this.carDataGetter...mapGetters(['carDataGetter']),},methods: {// 映射 this.setCarData(payload) 到 this.$store.commit('setCarData', payload)...mapMutations(['setCarData']),// 映射 this.fetchCarData(payload) 到 this.$store.dispatch('fetchCarData', payload)...mapActions(['fetchCarData']),}
}
(3) 访问模块化的 Vuex 数据
如果使用了模块化(modules),访问方式稍有不同:
// 直接访问模块 state
this.$store.state.moduleName.carData// 使用 mapState 访问模块 state
...mapState('moduleName', ['carData'])// 使用命名空间访问 mutations/actions
this.$store.commit('moduleName/setCarData', payload)
this.$store.dispatch('moduleName/fetchCarData', payload)
2. 在非 Vue 组件(JS 文件)中访问 Vuex
如果你在普通的 JS 文件(如 API 请求、工具函数)中需要访问 Vuex,可以:
(1) 直接导入 store 实例
import store from '@/store' // 假设 store 导出在 @/store/index.js// 访问 state
const carData = store.state.carData// 调用 mutation
store.commit('setCarData', payload)// 调用 action
store.dispatch('fetchCarData', payload)
(2) 动态获取 store(适用于插件或异步场景)
import Vue from 'vue'// 获取全局 store
const store = Vue.prototype.$storeif (store) {const carData = store.state.carData
}
3. 在 Vuex 内部访问数据
在 Vuex 的 getters、mutations、actions 内部,可以直接访问 state 和 getters:
const store = new Vuex.Store({state: {carData: null,},getters: {getCarData: (state) => state.carData,},mutations: {setCarData(state, payload) {state.carData = payload},},actions: {fetchCarData({ state, commit, getters }) {const currentCarData = state.carDataconst formattedData = getters.getCarDatacommit('setCarData', newData)},},
})
总结
| 访问方式 | 适用场景 | 示例 |
|---|---|---|
this.$store | 组件内直接访问 | this.$store.state.carData |
mapState/mapGetters | 组件内计算属性映射 | ...mapState(['carData']) |
mapMutations/mapActions | 组件内方法映射 | ...mapMutations(['setCarData']) |
直接导入 store | 非组件 JS 文件 | store.state.carData |
| 模块化访问 | 命名空间模块 | this.$store.state.moduleName.carData |
这样,你就可以在 Vue 项目的任何地方正确访问 Vuex 数据了! 🚀
二、全局方案灵活应用(轻量级方案)
2.1 全局变量深度应用
增强型全局数据管理
// app.js
class GlobalData {constructor() {this._config = {apiBase: 'https://api.example.com',theme: 'light'}}get config() {return {...this._config} // 返回副本保证只读}updateTheme(newTheme) {this._config.theme = newThemeuni.$emit('theme-change', newTheme)}
}App({globalData: new GlobalData()
})
组件中安全访问
// 获取可维护的全局对象
const global = getApp().globalData// 读取配置(推荐使用拷贝)
const currentTheme = {...global.config}.theme// 修改时使用封装方法
global.updateTheme('dark')
2.2 事件通信高级技巧
安全通信模式
// 创建事件总线单例
const eventBus = new Vue()// 封装安全监听方法
function safeOn(event, callback) {const wrappedCallback = (...args) => {try {return callback(...args)} catch (error) {console.error(`事件处理错误: ${event}`, error)}}eventBus.$on(event, wrappedCallback)return () => eventBus.$off(event, wrappedCallback)
}// 在组件中使用
export default {mounted() {this.unlisten = safeOn('data-updated', this.handleData)},beforeDestroy() {this.unlisten && this.unlisten()}
}
类型安全通信
// 创建事件类型枚举
const EventTypes = Object.freeze({DATA_UPDATE: Symbol('DATA_UPDATE'),USER_LOGOUT: Symbol('USER_LOGOUT')
})// 发送规范事件
uni.$emit(EventTypes.DATA_UPDATE, {timestamp: Date.now(),payload: newData
})// 接收时类型检查
uni.$on(EventTypes.DATA_UPDATE, ({ timestamp, payload }) => {// 安全处理数据
})
三、方案选型决策树
四、性能优化实践
4.1 Vuex性能贴士
- 冻结大对象:防止Vue过度追踪
state: {bigData: Object.freeze(largeStaticData)
}
- 模块懒加载:
const dynamicModule = () => import('./dynamic.module')
// 在需要时注册模块
store.registerModule('dynamic', dynamicModule)
4.2 全局事件优化
- 节流高频事件:
import throttle from 'lodash.throttle'uni.$on('scroll-event', throttle(handleScroll, 100))
- 使用事件池:
const eventPool = new Map()function registerEvent(event, callback) {if (!eventPool.has(event)) {eventPool.set(event, [])}eventPool.get(event).push(callback)
}
五、调试技巧大全
5.1 Vuex调试
// 打印mutation日志
store.subscribe((mutation, state) => {console.groupCollapsed(`mutation ${mutation.type}`)console.log('payload:', mutation.payload)console.log('state:', state)console.groupEnd()
})
5.2 事件追踪
// 监听所有事件
uni.$on('*', (event, ...args) => {console.debug(`[Event Trace] ${event}`, args)
})
六、迁移策略建议
从全局变量迁移到Vuex
- 识别候选数据:找出被多个组件修改的全局变量
- 创建过渡层:
// 临时兼容方案
const legacyData = getApp().globalData.legacy
Object.defineProperty(Vue.prototype, '$legacy', {get() {console.warn('该属性已废弃,请使用store迁移')return legacyData}
})
- 逐步替换:按模块迁移数据到Vuex
七、最佳实践总结
-
核心准则:
- 表单数据保持本地
- 用户会话使用Vuex+持久化
- 页面间参数用URL传递
- 组件通信优先用事件
-
架构建议:
src/ ├── store/ │ ├── modules/ │ │ ├── user.store.js │ │ └── product.store.js │ └── index.js ├── utils/ │ └── eventBus.js └── config/└── global.js -
安全原则:
- Vuex mutation必须同步
- 全局变量只读访问
- 事件监听必须清理
- 敏感数据加密存储
通过本指南的实践,开发者可以构建出既具备企业级健壮性,又保持灵活性的uni-app应用架构。根据项目规模选择合适的方案,在保证可维护性的同时提升开发效率。
相关文章:
uni-app 状态管理深度解析:Vuex 与全局方案实战指南
uni-app 状态管理深度解析:Vuex 与全局方案实战指南 一、Vuex 使用示例 1. 基础 Vuex 配置 1.1 项目结构 src/ ├── store/ │ ├── index.js # 主入口文件 │ └── modules/ │ └── counter.js # 计数器模块 └── main.js …...
剑指offer经典题目(五)
目录 栈相关 二叉树相关 栈相关 题目一:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的 min 函数,输入操作时保证 pop、top 和 min 函数操作时,栈中一定有元素。OJ地址 图示如下。 主要思想:我们…...
3、排序算法1---按考研大纲做的
一、插入排序 1、直接插入排序 推荐先看这个视频 1.1、原理 第一步,索引0的位置是有序区(有序区就是有序的部分,刚开始就只有第一个数据是有序的)。第二步,将第2个位置到最后一个位置的元素,依次进行排…...
llama-webui docker实现界面部署
1. 启动ollama服务 [nlp server]$ ollama serve 2025/04/21 14:18:23 routes.go:1007: INFO server config env"map[OLLAMA_DEBUG:false OLLAMA_FLASH_ATTENTION:false OLLAMA_HOST: OLLAMA_KEEP_ALIVE:24h OLLAMA_LLM_LIBRARY: OLLAMA_MAX_LOADED_MODELS:4 OLLAMA_MAX_…...
jinjia2将后端传至前端的字典变量转换为JS变量
后端 country_dict {AE: .amazon.ae, AU: .amazon.com.au} 前端 const country_list JSON.parse({{ country_list | tojson | safe }});...
如何深入理解引用监视器,安全标识以及访问控制模型与资产安全之间的关系
一、核心概念总结 安全标识(策略决策的 “信息载体) 是主体(如用户、进程)和客体(如文件、数据库、设备)的安全属性,用于标记其安全等级、权限、访问能力或受保护级别,即用于标识其安全等级、权限范围或约束…...
Linux的Socket开发补充
是listen函数阻塞等待连接,还是accept函数阻塞等待连接? 这两个函数的名字,听起来像listen一直在阻塞监听,有连接了就accept,但其实不是的。 调用listen()后,程序会立即返回,继续执行后续代码&a…...
Flutter异常Couldn‘t find dynamic library in default locations
Flutter项目在Windows系统使用ffigen生成代码时报下面的错误: [SEVERE] : Couldnt find dynamic library in default locations. [SEVERE] : Please supply one or more path/to/llvm in ffigens config under the key llvm-path. Unhandled exception: Exception: …...
Spring-AOP分析
Spring分析-AOP 1.案例引入 在上一篇文章中,【Spring–IOC】【https://www.cnblogs.com/jackjavacpp/p/18829545】,我们了解到了IOC容器的创建过程,在文末也提到了AOP相关,但是没有作细致分析,这篇文章就结合示例&am…...
[特殊字符] Prompt如何驱动大模型对本地文件实现自主变更:Cline技术深度解析
在AI技术快速发展的今天,编程方式正在经历一场革命性的变革。从传统的"人写代码"到"AI辅助编程",再到"AI自主编程",开发效率得到了质的提升。Cline作为一款基于VSCode的AI编程助手,通过其独特的pro…...
【专业解读:Semantic Kernel(SK)】大语言模型与传统编程的桥梁
目录 Start:什么是Semantic Kernel? 一、Semantic Kernel的本质:AI时代的操作系统内核 1.1 重新定义LLM的应用边界 1.2 技术定位对比 二、SK框架的六大核心组件与技术实现 2.1 内核(Kernel):智能任务调度中心 2…...
PHP 8 中的 Swow:高性能纯协程网络通信引擎
一、什么是 Swow? Swow 是一个高性能的纯协程网络通信引擎,专为 PHP 设计。它结合了最小化的 C 核心和 PHP 代码,旨在提供高性能的网络编程支持。Swow 的核心目标是释放 PHP 在高并发场景下的真正潜力,同时保持代码的简洁和易用性…...
你学会了些什么211201?--http基础知识
概念 HTTP–Hyper Text Transfer Protocol,超文本传输协议;是一种建立在TCP上的无状态连接(短连接)。 整个基本的工作流程是:客户端发送一个HTTP请求(Request ),这个请求说明了客户端…...
每天学一个 Linux 命令(29):tail
可访问网站查看,视觉品味拉满: http://www.616vip.cn/29/index.html tail 命令用于显示文件的末尾内容,默认显示最后 10 行。它常用于实时监控日志文件或查看文件的尾部数据。以下是详细说明和示例: 命令格式 tail [选项] [文件...]常用选项 选项描述-n <NUM> …...
【形式化验证基础】活跃属性Liveness Property和安全性质(Safety Property)介绍
文章目录 一、Liveness Property1、概念介绍2、形式化定义二、Safety Property1. 定义回顾2. 核心概念解析3. 为什么强调“有限前缀”4. 示例说明4.1 示例1:交通信号灯系统4.2 示例2:银行账户管理系统5. 实际应用的意义三. 总结一、Liveness Property 1、概念介绍 在系统的…...
技工院校无人机专业工学一体化人才培养方案
随着无人机技术在农业植保、地理测绘、应急救援等领域的深度应用,行业复合型人才缺口持续扩大。技工院校作为技能型人才培养主阵地,亟需构建与行业发展同步的无人机专业人才培养体系。本文基于"工学一体化"教育理念,从课程体系、实…...
PI0 Openpi 部署(仅测试虚拟环境)
https://github.com/Physical-Intelligence/openpi/tree/main 我使用4070tisuper, 14900k,完全使用官方默认设置,没有出现其他问题。 目前只对examples/aloha_sim进行测试,使用docker进行部署, 默认使用pi0_aloha_sim模型(但是文档上没找到对应的&…...
计算机视觉——利用AI幻觉检测图像是否是生成式算生成的图像
概述 俄罗斯的新研究提出了一种非常规方法,用于检测不真实的AI生成图像——不是通过提高大型视觉-语言模型(LVLMs)的准确性,而是故意利用它们的幻觉倾向。 这种新方法使用LVLMs提取图像的多个“原子事实”,然后应用自…...
性能测试工具和JMeter功能概要
主流性能测试工具 LoadRunner JMeter [本阶段学习] 1.1 LoadRunner HP LoadRunner是一种工业级标准性能测试负载工具,可以模拟上万用户实施测试,并在测试时可实时检测应用服务器及服务器硬件各种数据,来确认和查找存在的瓶颈支持多协议&am…...
《理解 Java 泛型中的通配符:extends 与 super 的使用场景》
大家好呀!👋 今天我们要聊一个让很多Java初学者头疼的话题——泛型通配符。别担心,我会用最通俗易懂的方式,带你彻底搞懂这个看似复杂的概念。准备好了吗?Let’s go! 🚀 一、为什么我们需要泛型通配符&…...
C#学习第17天:序列化和反序列化
什么是序列化? 定义:序列化是指把对象转换为一种可以轻松存储或传输的格式,如JSON、XML或二进制格式。这个过程需要捕获对象的类型信息和数据内容。用途:使得对象可以持久化到文件、发送至网络、或存储在数据库中。 什么是反序列…...
FlaskRestfulAPI接口的初步认识
FlaskRestfulAPI 介绍 记录学习 Flask Restful API 开发的过程 项目来源:【Flask Restful API教程-01.Restful API介绍】 我的代码仓库:https://gitee.com/giteechaozhi/flask-restful-api.git 后端API接口实现功能:数据库访问控制…...
CSS预处理工具有哪些?分享主流产品
目前主流的CSS预处理工具包括:Sass、Less、Stylus、PostCSS等。其中,Sass是全球使用最广泛的CSS预处理工具之一,以强大的功能、灵活的扩展性以及完善的社区生态闻名。Sass通过增加变量、嵌套、混合宏(mixin)等功能&…...
微信小程序中,将搜索组件获取的值传递给父页面(如 index 页面)可以通过 自定义事件 或 页面引用 实现
将搜索组件获取的值传递给父页面(如 index 页面)可以通过 自定义事件 或 页面引用 实现 方法 1:自定义事件(推荐) 步骤 1:搜索组件内触发事件 在搜索组件的 JS 中,当获取到搜索值时,…...
深度学习预训练和微调
目录 1. 预训练(Pre-training)是什么? 2. 微调(Fine-tuning)是什么? 3. 预训练和微调的对象 4. 特征提取如何实现? 预训练阶段: 微调阶段: 5. 这样做的作用和意义 …...
AI 速读 SpecReason:让思考又快又准!
在大模型推理的世界里,速度与精度往往难以兼得。但今天要介绍的这篇论文带来了名为SpecReason的创新系统,它打破常规,能让大模型推理既快速又准确,大幅提升性能。想知道它是如何做到的吗?快来一探究竟! 论…...
Qt通过ODBC和QPSQL两种方式连接PostgreSQL或PolarDB PostgreSQL版
一、概述 以下主要在Windows下验证连接PolarDB PostgreSQL版(阿里云兼容 PostgreSQL的PolarDB版本)。Linux下类似,ODBC方式则需要配置odbcinst.ini和odbc.ini。 二、代码 以下为完整代码,包含两种方式连接数据库,并…...
MobaXterm连接Ubuntu(SSH)
1.查看Ubuntu ip 打开终端,使用指令 ifconfig 由图可知ip地址 2.MobaXterm进行SSH连接 点击session,然后点击ssh,最后输入ubuntu IP地址以及用户名...
Lambda 函数与 peek 操作的使用案例
Lambda 函数和 peek 操作是 Java 8 Stream API 中非常有用的特性,下面我将介绍它们的使用案例。 Lambda 函数使用案例 Lambda 表达式是 Java 8 引入的一种简洁的匿名函数表示方式。 集合操作 List<String> names Arrays.asList("Alice", "B…...
C# 的 字符串插值($) 和 逐字字符串(@) 功能
这段代码使用了 C# 的 字符串插值($) 和 逐字字符串() 功能,并在 SQL 语句中动态拼接变量。下面详细解释它们的用法: 1. $(字符串插值) $ 是 C# 的 字符串插值 符号,允许…...
