# [特殊字符] 购物模拟器 — 鸿蒙ArkTS完整技术解析
2026/7/17 1:12:31 网站建设 项目流程

一、引言

购物模拟器是系列中第一个引入多页分类(Tab切换)购物车机制的应用。它将模拟购物体验分为三个关键环节:

浏览商品(分类切换)→ 加入购物车 → 结算购买 → 放入背包

从技术角度看,购物模拟器引入了几个新的ArkTS概念:

  • 多页切换:通过page状态变量控制显示哪个分类
  • 正则表达式解析:从字符串中提取价格数字
  • 购物车临时状态:与背包(永久状态)的分离
  • 列表渲染:使用ForEach渲染商品列表
  • 背包管理:已购物品的展示和清理

二、需求分析

2.1 功能需求

需求ID功能描述
F1分类浏览水果/食品/百货三类商品
F2商品列表每类5件商品,显示名称和价格
F3加入购物车扣钱后将商品放入购物车
F4购物车结算将购物车内所有商品放入背包
F5背包管理查看已购物品
F6余额管理动态更新余额
F7余额不足买不起时给出提示

2.2 数据模型

private shopItems: string[][] = [ ['🍎 苹果 5元', '🍌 香蕉 3元', '🍇 葡萄 8元', '🍊 橙子 4元', '🍉 西瓜 12元'], ['🥛 牛奶 6元', '🍞 面包 4元', '🧀 奶酪 15元', '🥚 鸡蛋 2元', '🧈 黄油 10元'], ['🧸 玩具 30元', '📚 书本 25元', '👕 衣服 50元', '🎧 耳机 80元', '🎮 游戏 100元'] ];

使用二维数组管理商品数据:

  • 第一维:分类索引(水果/食品/百货)
  • 第二维:具体商品(字符串形式,包含名称、emoji和价格)

三、多页分类切换

3.1 分类状态

@State page: number = 0;

一个简单的数字索引控制显示哪个分类的页面。

3.2 分类Tab实现

Row() { ForEach(this.categoryNames, (name: string, idx: number) => { Button(name) .fontSize(13) .backgroundColor(this.page === idx ? '#FF9800' : '#BDBDBD') .margin({ right: 5 }) .onClick(() => { this.page = idx; }) }) }

Tab切换的核心机制:通过this.page === idx条件动态设置按钮颜色。选中时显示橙色(#FF9800),未选中时显示灰色(#BDBDBD)。这在UI设计中称为"活性指示器"(Active Indicator)。

3.3 商品列表渲染

Column() { ForEach(this.shopItems[this.page], (item: string) => { Row() { Text(item) .fontSize(16) .width('60%') Button('➕ 加入购物车') .fontSize(12) .backgroundColor('#4CAF50') .onClick(() => { // 处理购买逻辑 }) } .width('90%') .justifyContent(FlexAlign.SpaceBetween) .padding(8) .margin({ bottom: 5 }) .backgroundColor('#FAFAFA') .borderRadius(8) }) }

page变化时,this.shopItems[this.page]获取对应分类的商品数组,ForEach自动重新渲染列表。


四、价格解析算法

4.1 从字符串提取数字

let price = parseInt(item.match(/\d+/)?.[0] || '0');

这行代码是价格解析的核心,包含三个关键部分:

  1. item.match(/\d+/):使用正则表达式\d+匹配字符串中的数字序列
  2. ?.[0]:可选链操作符,取第一个匹配结果
  3. || '0':如果未匹配到,默认为’0’

例如,'🍎 苹果 5元'经过解析:

  1. match(/\d+/)['5']
  2. [0]'5'
  3. parseInt('5')5

4.2 正则表达式详解

/\d+/

  • \d:匹配任何数字字符(0-9)
  • +:匹配一个或多个
  • 斜杠/:正则字面量分隔符

4.3 购买逻辑的完整流程

.onClick(() => { let price = parseInt(item.match(/\d+/)?.[0] || '0'); if (this.money < price) { this.message = '余额不足,买不起这个了😅'; return; } this.money -= price; this.cart.push(item); this.message = '加入了购物车:' + item; })

流程:解析价格→检查余额→扣除余额→加入购物车→显示反馈。


五、购物车与背包系统

5.1 购物车(临时)vs 背包(永久)

@State cart: string[] = []; // 购物车 - 结算前 @State bag: string[] = []; // 背包 - 已购

两个数组的核心区别:

维度购物车(cart)背包(bag)
状态临时永久
可清空结算后自动清空手动清空
数据来源"加入购物车"操作购物车结算
展示结算按钮上计数页面底部展示

5.2 结算逻辑

Button('🧾 结算购物车 (' + this.cart.length + ' 件)') .onClick(() => { if (this.cart.length === 0) { this.message = '购物车是空的,去买点东西吧!'; return; } for (let item of this.cart) { this.bag.push(item); } this.message = '🛍️ 购买成功!共买了 ' + this.cart.length + ' 件商品'; this.cart = []; // 清空购物车 })

结算的实质是将cart数组中的商品逐个pushbag数组,然后清空cart。这是一个经典的"暂存→提交"模式。

5.3 背包展示

if (this.bag.length > 0) { Text('已购物品:') .fontSize(14) .fontWeight(FontWeight.Bold) .margin({ top: 10 }) ForEach(this.bag, (item: string) => { Text(' ✅ ' + item) .fontSize(13) .fontColor('#666') }) Button('🗑️ 清空背包') .onClick(() => { this.bag = []; this.message = '背包已清空!'; }) }

背包展示采用ForEach渲染列表,每个商品前加 ✅ 标记。清空背包按钮提供批量删除功能。


六、UI布局与交互

6.1 余额展示

Text('💰 ' + this.money + ' 元') .fontSize(20) .fontWeight(FontWeight.Bold) .fontColor('#FF9800')

余额使用较大字号和橙色强调,使用户时刻关注自己的财务状况。

6.2 购物车计数器

Button('🧾 结算购物车 (' + this.cart.length + ' 件)')

购物车中的商品数量直接显示在按钮文案中,这种"徽标式"设计让用户一目了然地知道待结算商品数量。

6.3 空状态处理

if (this.cart.length === 0) { this.message = '购物车是空的,去买点东西吧!'; }

对购物车为空的情况进行特殊处理,避免无意义的结算操作。


七、数据流分析

7.1 完整数据流

初始:money=500, cart=[], bag=[] 操作1:加入购物车"苹果5元" → price=5, money>=5 ✅ → money=495, cart=['🍎 苹果 5元'] 操作2:加入购物车"面包4元" → price=4, money>=4 ✅ → money=491, cart=['🍎 苹果 5元', '🍞 面包 4元'] 操作3:结算 → cart.length=2, 遍历push到bag → bag=['🍎 苹果 5元', '🍞 面包 4元'] → cart=[]

7.2 边界条件

场景结果
余额刚好够买成功购买
余额差1元提示"余额不足"
购物车为空结算提示"购物车是空的"
背包为空清空无操作(无按钮)

八、与打工模拟器的联动

购物模拟器和打工模拟器天然构成了一个完整的经济生态系统:

打工模拟器:赚钱 → 金额积累在money中 购物模拟器:花钱 → 消耗money获取商品

虽然当前两个应用是独立的,但在设计上共享money变量含义——这正是未来整合的基础。


九、扩展思路

9.1 折扣系统

@State discount: number = 0.9; // 9折 let finalPrice = Math.floor(price * this.discount);

9.2 搜索功能

@State searchQuery: string = ''; @State filteredItems: string[] = []; // 在build中 ForEach(this.shopItems[this.page].filter(item => item.includes(this.searchQuery) ), (item) => { ... })

9.3 购买记录

使用 PersistentStorage 持久化购买记录:

PersistentStorage.persistProp('purchase_history', []); @StorageLink('purchase_history') purchaseHistory: string[] = [];

十、总结

购物模拟器展示了ArkTS在"电商类模拟"场景下的开发模式:

  1. 多页分类:使用page索引 + 二维数组实现Tab切换
  2. 正则解析item.match(/\d+/)?.[0]从字符串中提取价格
  3. 购物车与背包:临时状态与永久状态的分离管理
  4. 守卫逻辑:余额不足时阻止购买
  5. 空状态处理:购物车为空的校验

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询