基于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在分布式数据同步方面的强大能力,为电商类应用提供了完整的购物车解决方案。
注意事项:
实际开发中需要处理商品信息变化的情况
考虑添加购物车数据备份/恢复功能
生产环境需要更完善的错误处理和日志记录
可根据业务需求调整同步策略和冲突解决算法




















