
基于HarmonyOS的购物车本地缓存与跨设备同步实现 原创
基于HarmonyOS的购物车本地缓存与跨设备同步实现
一、项目概述
本项目基于HarmonyOS的本地存储和分布式能力,开发一个支持离线缓存和多设备同步的购物车系统。参考《鸿蒙跨端U同步:同一局游戏中多设备玩家昵称/头像显示》中的分布式数据同步技术,实现购物车数据在本地持久化存储和多设备间的实时同步。
!https://example.com/shopping-cart-arch.png
图1:购物车系统架构(包含UI层、业务逻辑层、本地存储层和分布式同步层)
二、核心功能实现
数据模型与本地存储(ArkTS)
// 商品数据模型
class Product {
id: string;
name: string;
price: number;
image: Resource;
stock: number;
constructor(id: string, name: string, price: number, image: Resource, stock: number) {
this.id = id;
this.name = name;
this.price = price;
this.image = image;
this.stock = stock;
}
// 购物车项模型
class CartItem {
id: string;
product: Product;
quantity: number;
selected: boolean;
lastUpdated: number;
deviceId: string;
constructor(product: Product, quantity: number = 1) {
this.id = generateUUID();
this.product = product;
this.quantity = quantity;
this.selected = true;
this.lastUpdated = Date.now();
this.deviceId = deviceInfo.deviceId;
}
// 购物车管理器
class CartManager {
private static instance: CartManager;
private items: CartItem[] = [];
private storageKey = ‘shopping_cart_data’;
static getInstance(): CartManager {
if (!CartManager.instance) {
CartManager.instance = new CartManager();
return CartManager.instance;
constructor() {
this.loadFromStorage();
// 添加商品到购物车
addToCart(product: Product, quantity: number = 1): boolean {
const existingItem = this.items.find(item => item.product.id === product.id);
if (existingItem) {
// 更新已有商品数量
if (existingItem.quantity + quantity > product.stock) {
return false; // 超过库存
existingItem.quantity += quantity;
else {
// 添加新商品
if (quantity > product.stock) {
return false; // 超过库存
this.items.push(new CartItem(product, quantity));
this.saveToStorage();
return true;
// 更新购物车项数量
updateQuantity(itemId: string, newQuantity: number): boolean {
const item = this.items.find(item => item.id === itemId);
if (!item) return false;
if (newQuantity > item.product.stock) {
return false; // 超过库存
item.quantity = newQuantity;
item.lastUpdated = Date.now();
this.saveToStorage();
return true;
// 移除购物车项
removeItem(itemId: string): boolean {
const index = this.items.findIndex(item => item.id === itemId);
if (index === -1) return false;
this.items.splice(index, 1);
this.saveToStorage();
return true;
// 切换选中状态
toggleSelection(itemId: string): boolean {
const item = this.items.find(item => item.id === itemId);
if (!item) return false;
item.selected = !item.selected;
item.lastUpdated = Date.now();
this.saveToStorage();
return true;
// 获取购物车所有商品
getCartItems(): CartItem[] {
return […this.items];
// 获取选中商品总价
getTotalPrice(): number {
return this.items
.filter(item => item.selected)
.reduce((sum, item) => sum + (item.product.price * item.quantity), 0);
// 清空购物车
clearCart() {
this.items = [];
this.saveToStorage();
// 从本地存储加载
private loadFromStorage() {
const cartData = localStorage.get(this.storageKey);
if (cartData) {
this.items = JSON.parse(cartData);
}
// 保存到本地存储
private saveToStorage() {
localStorage.set(this.storageKey, JSON.stringify(this.items));
}
分布式数据同步实现(ArkTS)
// 购物车同步服务
class CartSyncService {
private static instance: CartSyncService;
private distObject: distributedDataObject.DataObject;
private deviceList: deviceManager.DeviceInfo[] = [];
static getInstance(): CartSyncService {
if (!CartSyncService.instance) {
CartSyncService.instance = new CartSyncService();
return CartSyncService.instance;
constructor() {
// 初始化分布式数据对象
this.distObject = distributedDataObject.create({
cartItems: [],
operations: []
});
// 监听设备连接变化
deviceManager.on('deviceStateChange', () => {
this.updateDeviceList();
});
// 监听数据变化
this.distObject.on('change', (fields: string[]) => {
if (fields.includes('cartItems')) {
this.handleFullSync();
if (fields.includes(‘operations’)) {
this.handleIncrementalSync();
});
this.updateDeviceList();
// 更新设备列表
private updateDeviceList() {
this.deviceList = deviceManager.getConnectedDevices();
this.distObject.deviceList = this.deviceList.map(d => ({
id: d.deviceId,
name: d.deviceName,
lastSync: Date.now()
}));
this.distObject.setDistributed(this.getConnectedDeviceIds());
// 全量同步购物车
syncFullCart() {
const cartManager = CartManager.getInstance();
this.distObject.cartItems = cartManager.getCartItems();
this.distObject.setDistributed(this.getConnectedDeviceIds());
// 增量同步购物车操作
syncCartOperation(type: ‘add’ ‘update’
‘remove’, item: CartItem) {
const operations = this.distObject.operations as Array<any>;
this.distObject.operations = [
…operations,
type,
item,
timestamp: Date.now(),
deviceId: deviceInfo.deviceId
];
this.distObject.setDistributed(this.getConnectedDeviceIds());
// 处理全量同步
private handleFullSync() {
const remoteItems = this.distObject.cartItems as CartItem[];
const cartManager = CartManager.getInstance();
// 合并策略:保留最新修改的项
const mergedItems = this.mergeCartItems(cartManager.getCartItems(), remoteItems);
cartManager.updateCartItems(mergedItems);
// 处理增量同步
private handleIncrementalSync() {
const operations = this.distObject.operations as Array<{
type: string;
item: CartItem;
timestamp: number;
deviceId: string;
}>;
const cartManager = CartManager.getInstance();
operations.forEach(op => {
if (op.deviceId !== deviceInfo.deviceId) {
switch (op.type) {
case 'add':
cartManager.addItemFromRemote(op.item);
break;
case 'update':
cartManager.updateItemFromRemote(op.item);
break;
case 'remove':
cartManager.removeItem(op.item.id);
break;
}
});
// 清空已处理的操作
this.distObject.operations = [];
// 合并购物车项
private mergeCartItems(localItems: CartItem[], remoteItems: CartItem[]): CartItem[] {
const itemMap = new Map<string, CartItem>();
// 添加本地项
localItems.forEach(item => itemMap.set(item.id, item));
// 合并远程项
remoteItems.forEach(remoteItem => {
const localItem = itemMap.get(remoteItem.id);
if (!localItem || remoteItem.lastUpdated > localItem.lastUpdated) {
itemMap.set(remoteItem.id, remoteItem);
});
return Array.from(itemMap.values());
// 获取已连接设备ID
private getConnectedDeviceIds(): string[] {
return this.deviceList
.map(d => d.deviceId)
.filter(id => id !== deviceInfo.deviceId);
}
UI界面实现(ArkTS)
// 购物车页面组件
@Entry
@Component
struct ShoppingCartPage {
@State cartItems: CartItem[] = [];
@State totalPrice: number = 0;
@State connectedDevices: number = 0;
private cartManager = CartManager.getInstance();
private cartSync = CartSyncService.getInstance();
aboutToAppear() {
this.loadCartData();
// 监听购物车变化
this.cartManager.addListener(() => {
this.loadCartData();
});
// 监听设备连接变化
deviceManager.on('deviceStateChange', () => {
this.connectedDevices = deviceManager.getConnectedDevices().length;
});
this.connectedDevices = deviceManager.getConnectedDevices().length;
// 加载购物车数据
private loadCartData() {
this.cartItems = this.cartManager.getCartItems();
this.totalPrice = this.cartManager.getTotalPrice();
build() {
Column() {
// 标题栏
Row() {
Text('购物车')
.fontSize(24)
.fontWeight(FontWeight.Bold)
// 同步状态
DeviceSyncIndicator()
.width(‘100%’)
.justifyContent(FlexAlign.SpaceBetween)
.padding(16)
// 购物车列表
List({ space: 12 }) {
ForEach(this.cartItems, (item: CartItem) => {
ListItem() {
CartItemView({ item: item })
}, (item: CartItem) => item.id)
.layoutWeight(1)
.width('100%')
// 结算栏
Column() {
Row() {
Text('合计:')
.fontSize(18)
Text(¥${this.totalPrice.toFixed(2)})
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({ left: 8 })
.width(‘100%’)
.justifyContent(FlexAlign.End)
Button('去结算')
.width('100%')
.height(48)
.margin({ top: 12 })
.backgroundColor('#FF5722')
.fontColor(Color.White)
.enabled(this.totalPrice > 0)
.width(‘100%’)
.padding(16)
.backgroundColor('#FFFFFF')
.height(‘100%’)
.backgroundColor('#F5F5F5')
}
// 购物车项组件
@Component
struct CartItemView {
@Prop item: CartItem;
@State quantity: number = this.item.quantity;
private cartManager = CartManager.getInstance();
private cartSync = CartSyncService.getInstance();
build() {
Row() {
// 选择框
Checkbox()
.select(this.item.selected)
.onChange((checked: boolean) => {
this.cartManager.toggleSelection(this.item.id);
this.cartSync.syncCartOperation(‘update’, this.item);
})
// 商品图片
Image(this.item.product.image)
.width(80)
.height(80)
.margin({ left: 12 })
// 商品信息
Column() {
Text(this.item.product.name)
.fontSize(16)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Text(¥${this.item.product.price.toFixed(2)})
.fontSize(14)
.fontColor('#FF5722')
.margin({ top: 4 })
// 数量控制
Row() {
Button('-')
.width(32)
.height(32)
.fontSize(16)
.onClick(() => {
if (this.quantity > 1) {
this.quantity--;
this.updateQuantity();
})
Text(this.quantity.toString())
.width(40)
.textAlign(TextAlign.Center)
Button('+')
.width(32)
.height(32)
.fontSize(16)
.onClick(() => {
if (this.quantity < this.item.product.stock) {
this.quantity++;
this.updateQuantity();
})
.margin({ top: 8 })
.layoutWeight(1)
.margin({ left: 12 })
// 删除按钮
Button($r('app.media.ic_delete'))
.width(32)
.height(32)
.backgroundColor(Color.Transparent)
.onClick(() => {
this.cartManager.removeItem(this.item.id);
this.cartSync.syncCartOperation('remove', this.item);
})
.width(‘100%’)
.padding(16)
.backgroundColor('#FFFFFF')
.borderRadius(8)
// 更新商品数量
private updateQuantity() {
if (this.cartManager.updateQuantity(this.item.id, this.quantity)) {
this.item.quantity = this.quantity;
this.cartSync.syncCartOperation(‘update’, this.item);
else {
this.quantity = this.item.quantity; // 恢复原值
}
// 设备同步指示器组件
@Component
struct DeviceSyncIndicator {
@State connectedDevices: number = 0;
aboutToAppear() {
deviceManager.on(‘deviceStateChange’, () => {
this.connectedDevices = deviceManager.getConnectedDevices().length;
});
this.connectedDevices = deviceManager.getConnectedDevices().length;
build() {
Row() {
Image($r('app.media.ic_sync'))
.width(16)
.height(16)
Text(${this.connectedDevices})
.fontSize(16)
.margin({ left: 4 })
}
三、关键功能说明
本地缓存实现机制
数据持久化:
// 保存到本地存储
private saveToStorage() {
localStorage.set(this.storageKey, JSON.stringify(this.items));
// 从本地加载
private loadFromStorage() {
const cartData = localStorage.get(this.storageKey);
if (cartData) {
this.items = JSON.parse(cartData);
}
离线优先策略:
所有操作先在本地执行
网络恢复后同步到其他设备
冲突解决采用"最后修改优先"原则
分布式同步策略
同步方式 触发条件 数据量 适用场景
全量同步 应用启动、网络恢复 大 初始化同步
增量同步 用户操作 小 实时同步
手动同步 用户点击刷新 可变 按需同步
数据冲突解决算法
private mergeCartItems(localItems: CartItem[], remoteItems: CartItem[]): CartItem[] {
const itemMap = new Map<string, CartItem>();
// 添加本地项
localItems.forEach(item => itemMap.set(item.id, item));
// 合并远程项
remoteItems.forEach(remoteItem => {
const localItem = itemMap.get(remoteItem.id);
if (!localItem || remoteItem.lastUpdated > localItem.lastUpdated) {
itemMap.set(remoteItem.id, remoteItem);
});
return Array.from(itemMap.values());
四、项目扩展与优化
性能优化建议
本地存储优化:
// 使用加密存储敏感数据
import cryptoFramework from ‘@ohos.security.cryptoFramework’;
// 实现数据加密/解密方法
同步性能优化:
添加操作节流(300ms)
实现差异比对算法
使用二进制协议传输
功能扩展建议
购物车过期机制:
interface CartItem {
addedTime: number;
ttl: number; // 存活时间(秒)
多设备合并购买:
实现跨设备商品凑单
支持多设备合并结算
提供配送地址管理
智能推荐:
// 基于购物车商品的分析推荐
getRecommendations(): Product[] {
// 实现推荐算法…
五、测试方案
测试用例设计
测试类型 测试场景 验证点
功能测试 添加商品 本地存储正确
功能测试 离线操作 数据不丢失
同步测试 多设备操作 状态最终一致
性能测试 大数据量 操作流畅
安全测试 敏感数据 加密存储
自动化测试示例
// 购物车功能测试
describe(‘ShoppingCart Tests’, () => {
let cartManager: CartManager;
let testProduct: Product;
before(() => {
cartManager = CartManager.getInstance();
testProduct = new Product(‘p1’, ‘测试商品’, 100, $r(‘app.media.ic_product’), 10);
});
it(‘should add item to cart’, () => {
const success = cartManager.addToCart(testProduct);
expect(success).toBeTruthy();
expect(cartManager.getCartItems().length).toBe(1);
});
it(‘should persist cart data’, () => {
cartManager.addToCart(testProduct);
const newManager = new CartManager();
expect(newManager.getCartItems().length).toBe(1);
});
});
六、总结
本项目基于HarmonyOS实现了具有以下特点的购物车系统:
可靠的本地缓存:支持离线操作,数据持久化
智能的同步机制:自动合并多设备变更
流畅的用户体验:实时响应操作,动画过渡
灵活的扩展架构:易于添加新功能和业务规则
通过参考《鸿蒙跨端U同步:同一局游戏中多设备玩家昵称/头像显示》的技术方案,我们验证了HarmonyOS在分布式数据同步方面的强大能力,为电商类应用提供了完整的购物车解决方案。
注意事项:
实际开发中需要处理商品信息变化的情况
考虑添加购物车数据备份/恢复功能
生产环境需要更完善的错误处理和日志记录
可根据业务需求调整同步策略和冲突解决算法
