一、前言:为什么需要全局数据共享?
你是否遇到过这些问题?
- 用户登录后,多个页面都要获取
userInfo - 主题色切换,所有页面都要响应
- 购物车商品数量变化,底部 tab 需要实时更新
根本原因 :小程序页面之间天然隔离,无法直接共享数据!
在 Vue 中有 Vuex,React 中有 Context 或 Redux,那小程序有没有优雅的全局状态管理方案?
答案是:有!而且不止一种 。本文将为你详解 5 种主流全局数据共享方案,从简单到复杂,助你选择最适合项目的方案。
二、方案 1:App.globalData(最简单)
原理
利用 App 实例的 globalData 属性,作为全局变量容器。
实现步骤
javascript
// app.js
App({
globalData: {
userInfo: null,
theme: 'light'
}
});
javascript
// pages/profile/profile.js
const app = getApp();
Page({
onLoad() {
// 读取
console.log(app.globalData.userInfo);
// 修改
app.globalData.theme = 'dark';
}
});
✅ 优点
- 无需额外依赖
- 上手极快,适合小型项目
❌ 缺点
- 无响应式更新:修改后页面不会自动刷新
- 无数据监听:无法知道谁改了数据
- 易造成命名冲突
📌 适用场景:只读配置、一次性初始化数据(如用户信息)
三、方案 2:Behavior(可复用逻辑 + 数据)
原理
通过 Behavior 封装可复用的状态和方法,被多个页面/组件混入。
实现示例
javascript
// behaviors/user-behavior.js
module.exports = Behavior({
data: {
userInfo: null
},
methods: {
setUserInfo(user) {
this.setData({ userInfo: user });
}
}
});
javascript
// pages/home/home.js
const userBehavior = require('../../behaviors/user-behavior');
Page({
behaviors: [userBehavior],
onLoad() {
this.setUserInfo({ name: '张三' });
}
});
✅ 优点
- 逻辑复用,避免重复代码
- 支持 setData 响应式更新
❌ 缺点
- 每个页面/组件拥有独立副本,不是真正"全局共享"
- 无法跨页面同步状态
📌 适用场景 :相同 UI 逻辑复用(如表单验证),非全局状态
四、方案 3:事件总线(Event Bus)------ 推荐!
原理
基于 wx. $ emit / wx. $ on 实现发布-订阅模式,实现跨页面通信。
实现步骤
javascript
// utils/event-bus.js
class EventBus {
constructor() {
this.events = {};
}
on(name, callback) {
if (!this.events[name]) this.events[name] = [];
this.events[name].push(callback);
}
emit(name, data) {
if (this.events[name]) {
this.events[name].forEach(cb => cb(data));
}
}
off(name, callback) {
if (this.events[name]) {
const index = this.events[name].indexOf(callback);
if (index > -1) this.events[name].splice(index, 1);
}
}
}
export default new EventBus();
javascript
// app.js
import eventBus from './utils/event-bus';
App({ eventBus });
javascript
// pages/cart/cart.js
const app = getApp();
Page({
data: { count: 0 },
onLoad() {
// 监听购物车变化
app.eventBus.on('cartChange', (count) => {
this.setData({ count });
});
},
onUnload() {
// 记得取消监听,防止内存泄漏
app.eventBus.off('cartChange');
}
});
javascript
// pages/goods/goods.js
// 添加商品时触发
getApp().eventBus.emit('cartChange', 5);
✅ 优点
- 真正跨页面通信
- 轻量、灵活、解耦
- 支持多对多通信
❌ 缺点
- 需手动管理监听/移除
- 调试困难(事件流不直观)
📌 适用场景:中大型项目,需跨页面状态同步(如购物车、登录态)
五、方案 4:自定义 Store(类 Vuex)
原理
封装一个响应式 Store,支持 state、mutations、actions。
简易实现
javascript
// store/index.js
class Store {
constructor(options) {
this.state = options.state;
this.mutations = options.mutations || {};
this.subscribers = [];
}
commit(mutationName, payload) {
if (this.mutations[mutationName]) {
this.mutations[mutationName](this.state, payload);
this.notify();
}
}
subscribe(callback) {
this.subscribers.push(callback);
return () => {
const index = this.subscribers.indexOf(callback);
if (index > -1) this.subscribers.splice(index, 1);
};
}
notify() {
this.subscribers.forEach(cb => cb(this.state));
}
}
export default new Store({
state: {
cartCount: 0,
userInfo: null
},
mutations: {
SET_CART_COUNT(state, count) {
state.cartCount = count;
},
SET_USER_INFO(state, user) {
state.userInfo = user;
}
}
});
javascript
// pages/cart/cart.js
import store from '../../store';
Page({
data: { count: 0 },
onLoad() {
this.unsubscribe = store.subscribe((state) => {
this.setData({ count: state.cartCount });
});
},
onUnload() {
this.unsubscribe && this.unsubscribe();
}
});
javascript
// 任意页面修改状态
store.commit('SET_CART_COUNT', 10);
✅ 优点
- 结构清晰,类似 Vuex
- 支持响应式更新
- 易于测试和维护
❌ 缺点
- 需自行实现(或引入第三方库)
- 学习成本略高
📌 适用场景:复杂状态管理,追求代码规范性
六、方案 5:使用第三方库(如 miniprogram-store)
如果你不想造轮子,可直接使用社区成熟方案:
- `miniprogram-store`:轻量级状态管理
- `mobx-miniprogram`:MobX 适配版
安装示例:
bash
npm install miniprogram-store --save
然后按文档集成即可,享受开箱即用的响应式体验。
七、五大方案对比总结
| 方案 | 响应式 | 跨页面 | 复杂度 | 适用项目规模 |
|---|---|---|---|---|
| globalData | ❌ | ✅ | ⭐ | 小型 demo |
| Behavior | ✅ | ❌(独立副本) | ⭐⭐ | 组件逻辑复用 |
| ✅ Event Bus | ✅(需手动 setData) | ✅ | ⭐⭐ | 中大型项目(推荐) |
| 自定义 Store | ✅ | ✅ | ⭐⭐⭐ | 大型项目 |
| 第三方库 | ✅ | ✅ | ⭐⭐ | 追求效率的团队 |
八、避坑指南
❌ 坑 1:在 globalData 中存大量数据
风险 :主包体积增大,启动变慢
建议:仅存关键标识(如 userId),详情按需加载
❌ 坑 2:忘记移除事件监听
后果 :内存泄漏,页面多次触发
解决 :务必在onUnload中off或unsubscribe
❌ 坑 3:Store 状态直接修改
错误:
javascriptstore.state.cartCount = 5; // 不会触发更新!正确:
javascriptstore.commit('SET_CART_COUNT', 5);
九、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!