在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

鸿蒙 Next 共享工具库 App 开发实战:社区共享 + 借还系统 + 分类筛选

作者:duluo
SDK 版本:HarmonyOS API 24 (Next)
开发工具:DevEco Studio
语言框架:ArkTS + ArkUI
字数:约 9600 字


目录

  1. 引言
  2. 产品概念与工具模型
  3. 两 Tab 架构设计
  4. 工具卡片组件
  5. 分类筛选系统
  6. 借还系统与状态管理
  7. 详情弹窗中的内联访问
  8. 社区属性与评分系统
  9. 编译错误全记录
  10. 第三十六款 App 全景回顾
  11. 结语

1. 引言

1.1 工具共享的社区价值

一把电钻每年平均使用时间不到 30 分钟。一个梯子一年用不了 5 次。一台高压清洗机用完后大半年闲置在角落。

这些东西家家都有、家家都需要,但使用频率极低。从经济角度看,购买这些工具的成本远高于单次使用的价值。从社区角度看,如果这些工具能在邻里之间共享,所有人的生活成本都会降低。

社区共享工具库的核心理念就是:与其每家买一件,不如共享一个工具库。

1.2 本 App 的定位

本 App 与"二手流转"(App 35)共享相同的"社区共享"基因,但核心机制不同:

二手流转(#35) 共享工具库(#36)
关系 一次性买卖 周期性借还
状态变化 interested borrowed → returned
物品属性 个人所有 个人/社区所有
归还机制 ✅ 有归还功能
评分系统 ✅ 5 星评分

1.3 三十六款 App 全景

App 数量:    36
代码总行数:  ~19,400 行
编译错误数:  ~312 个
博客总字数:  ~360,000 字
技术博客数:  36 篇

2. 产品概念与工具模型

2.1 功能需求

用户故事 1:我想看看邻居们分享了哪些工具可以借
用户故事 2:我想按分类筛选工具
用户故事 3:我想借一把电钻用两天
用户故事 4:我用完了想归还
用户故事 5:我想看看谁提供了工具

功能清单:
├── F1: 工具列表(10 件工具)
├── F2: 分类标签筛选
├── F3: 工具卡片(名称/主人/距离/状态)
├── F4: 借出工具
├── F5: 归还工具
├── F6: 借还记录列表
├── F7: 详情弹窗
└── F8: 评分展示

2.2 工具数据模型

interface Tool {
  id: number;
  name: string;       // 工具名称
  emoji: string;      // 图标
  owner: string;      // 主人(如"301室 张叔")
  dist: string;       // 距离/位置
  status: string;     // 状态("可借"/"出借中")
  desc: string;       // 描述
  tag: string;        // 分类
  rating: number;     // 评分(1-5)
}

9 个字段比"二手流转"的 Item 模型多了一个 status 字段。status 是一个字符串,但只有两个可能的值:“可借"和"出借中”。

为什么用字符串而不是布尔:字符串的扩展性更强。后续如果增加"维修中"、"已下架"等状态,不需要修改代码逻辑。

2.3 10 件工具的社区感设计

所有工具的主人以"301室 张叔"、“502室 李哥"这样的社区身份标识,而不是"用户A”、“用户B”。这种设计传递了一个信息:这些工具是真实的邻居在共享,不是虚拟平台在运营。


3. 两 Tab 架构设计

3.1 Tab 配置

build() {
  Stack() {
    Column().backgroundColor(C.bg)
    Column() {
      this.buildHeader()
      if (this.activeTab === 0) this.buildBrowseTab()
      else this.buildMyTab()
      this.buildTabBar()
    }
    if (this.showDetail) this.buildDetailOverlay()
  }
}
Tab 图标 功能
0 🔧 工具 — 浏览所有工具
1 📋 借还 — 已借出工具列表

3.2 首页布局

┌──────────────────────────────┐
│  🤝 共享让生活更美好           │
│  把闲置的工具借给邻居…         │
├──────────────────────────────┤
│  [全部] [工具] [清洁] [园艺]   │
├──────────────────────────────┤
│  🔧 电钻                    │
│  301室张叔 · 同楼  可借       │
│  充电式手电钻…               │
│  工具  ⭐⭐⭐⭐⭐     📩 借出    │
├──────────────────────────────┤
│  🪜 梯子                    │
│  502室李哥 · 同楼  可借       │
│  ...                        │
└──────────────────────────────┘

3.3 数据流

浏览 Tab → 筛选 → 工具列表 → 点击详情
     ↓
借出 → borrowed 数组更新 → 状态变为"已借出"
     ↓
我的 Tab → 显示已借出工具 → 点击"归还"
     ↓
归还 → borrowed 数组移除 → 首页状态恢复

借出和归还是双向的——借出在首页操作,归还在我的 Tab 操作。两个 Tab 通过同一个 borrowed 数组保持状态同步。


4. 工具卡片组件

4.1 卡片布局

┌──────────────────────────────────────┐
│  🔧                    可借           │
│  电钻                                 │
│  301室张叔 · 同楼                     │
│                                      │
│  充电式手电钻,带一套钻头。           │
│                                      │
│  工具  ⭐⭐⭐⭐⭐        📩 借出      │
└──────────────────────────────────────┘

顶部行:左侧 emoji,右侧状态标签("可借"绿色 / "出借中"灰色)
中间行:名称 + 主人/距离
描述行:2 行限制
底部行:左侧分类标签 + 评分,右侧操作按钮

4.2 状态标签

Text(tool.status).fontSize(13)
  .fontColor(tool.status === '可借' ? C.accent : C.textMuted)
  .fontWeight(tool.status === '可借' ? FontWeight.Bold : FontWeight.Normal)

"可借"使用绿色粗体,"出借中"使用灰色普通体。视觉权重差异明显。

4.3 操作按钮

if (tool.status === '可借') {
  // 显示"借出"或"已借出"按钮
  Text(this.isBorrowed(tool.id) ? '✅ 已借出' : '📩 借出')
} else {
  // 显示灰色"出借中"文字
  Text('⏳ 出借中').fontSize(13).fontColor(C.textMuted)
}

三态按钮:可借 + 未借出 → 橙色"📩 借出"按钮;可借 + 已借出 → 绿色"✅ 已借出"标签;出借中 → 灰色文字。


5. 分类筛选系统

5.1 标签配置

const TAGS: string[] = ['全部', '工具', '清洁', '园艺'];

4 个标签覆盖 10 件工具的分类:工具(5 件)、清洁(3 件)、园艺(2 件)。

5.2 筛选逻辑

getFiltered(): Tool[] {
  if (this.selectedTag === 0) return TOOLS;
  const result: Tool[] = [];
  for (const t of TOOLS) { if (t.tag === TAGS[this.selectedTag]) result.push(t); }
  return result;
}

与"二手流转"(App 35)的筛选逻辑完全相同。这个方法被 ForEach 和详情弹窗两处调用。


6. 借还系统与状态管理

6.1 状态设计

@State borrowed: number[] = [];

一维数组存储已借出工具的 ID。

6.2 借出

borrowTool(id: number): void {
  this.borrowed = [id, ...this.borrowed];
  promptAction.showToast({ message: '📩 已借出!用时请爱惜,用完及时还' });
}

Toast 提示中包含了"用时请爱惜,用完及时还"的善意提醒——不是在说教,而是在提醒共享的规则。

6.3 归还

returnTool(id: number): void {
  const idx = this.borrowed.indexOf(id);
  if (idx >= 0) {
    const b = this.borrowed.concat([]);
    b.splice(idx, 1);
    this.borrowed = b;
    promptAction.showToast({ message: '✅ 已归还!感谢你的诚信' });
  }
}

归还操作是借出的逆操作:找到索引 → 创建数组副本 → 移除 → 赋值新数组。concat([]) 创建新引用触发 @State 更新。

6.4 我的 Tab 中的归还卡片

🔧 电钻                 📩 已借出
来自 301室张叔
✅ 记得及时归还哦           归还

每张已借出卡片底部有"归还"按钮(暖橙色),点击后工具从 borrowed 数组移除,首页卡片状态恢复。


7. 详情弹窗中的内联访问

7.1 内联模式

Text(this.getFiltered()[this.selectedTool].emoji).fontSize(64)
Text(this.getFiltered()[this.selectedTool].name).fontSize(22)
Text('⭐ ' + this.getFiltered()[this.selectedTool].rating + '分')
Text('👤 ' + this.getFiltered()[this.selectedTool].owner)
Text(this.getFiltered()[this.selectedTool].desc)

详情弹窗中所有数据通过 this.getFiltered()[this.selectedTool].xxx 内联访问。重复了 8 次 this.getFiltered()[this.selectedTool]

这种模式的优缺点:

优点

  • 零错误——没有 const 声明,不会触发 10905209
  • 调用 getFiltered() 确保了数据始终与当前分类筛选一致
  • 不需要额外的 Helper 方法

缺点

  • 代码重复——同一表达式写 8 次
  • 可读性稍差——需要从长表达式中提取出具体字段

8. 社区属性与评分系统

8.1 评分展示

getStars(r: number): string {
  return '⭐'.repeat(r);
}

String.repeat() 是 ES6 标准方法,ArkTS 支持。'⭐'.repeat(5) 生成 '⭐⭐⭐⭐⭐'

与常规的"4.2 分"数字评分不同,星级评分更适合社区场景——星越多越受欢迎,简单直观。

8.2 主人身份展示

每件工具都标注了主人信息:"301室 张叔""502室 李哥"。距离标注:"同楼""3号楼""物业"

居委会有自己的工具(“社区公用工具箱”),评分 5 星。这个细节传递了"社区支持"的信息——共享不是个别热心人的行为,而是社区在推动的事情。


9. 编译错误全记录

9.1 错误概览

本 App 出现 3 个编译错误

# 错误代码 位置 原因 修复
1 10505001 L205 重复的方法定义 删除空方法体
2 10505001 L287 重复的方法定义 删除空方法体
3 链式编译失败 修复后自动消失

9.2 重复方法错误

// ❌ 错误代码:buildBorrowCard 被定义了两次
@Builder
buildBorrowCard(id: number) {
  // 完整实现...
}

@Builder
buildBorrowCard(id: number) {}  // ❌ 第二次定义(空的)

原因:在从"二手流转"App 迁移代码时,buildBorrowCard 方法被复制了两次。第二次是一个空的 Builder 方法(占位符),忘记删除了。

修复:删除空的 Builder 方法。

9.3 三十六款 App 的错误趋势

App 1:   16  ← 入门
App 10:  11  ← 模式形成
App 20:   2  ← 高效期
App 24:  48  ← AI 探索
App 31:   0  ← 零错误
App 33:   0  ← 零错误
App 34:   1  ← Text 类型
App 35:   3  ← Builder const
App 36:   3  ← 重复方法

App 36 的 3 个错误不是"新的知识",而是"旧的垃圾代码"。修复方式也不是学习新的 ArkTS 规则,而是——删掉多余的代码。


10. 第三十六款 App 全景回顾

10.1 数据总览

指标 数值
代码行数 295 行
编译错误数 3 个(2 个重复方法 + 1 个连锁)
@State 变量 4 个
@Builder 方法 6 个
工具数量 10 件
分类数量 3 个
Tab 数 2 个
弹窗数 1 个
外部依赖 0 个

10.2 共享/平台类 App 系列总结

从 App 23 到 App 36,共享/平台类 App 共 5 款:

App 共享内容 核心操作 行数
23 情绪漂流瓶 心事 扔出 → 捞取 → 回复 447
29 反向导师 技能 浏览 → 申请 → 等待 373
32 临期食品救援 食品 浏览 → 救援 342
35 二手流转 物品 浏览 → 联系 266
36 共享工具库 工具 浏览 → 借出 → 归还 295

共享类 App 的平均代码量约 345 行——远低于系列平均值 546 行。原因是共享类 App 的逻辑路径简洁(浏览→操作),不需要复杂的用户系统或内容创建系统。

10.3 社区属性的价值

5 款共享类 App 中,本 App 是唯一一款强调"社区"概念的:

  • 23 📩 匿名漂流瓶 — 陌生人
  • 29 🎓 反向导师 — 陌生师生
  • 32 🥪 临期食品救援 — 消费者 vs 商家
  • 35 🔄 二手流转 — 陌生人
  • 36 🔧 共享工具库 — 同社区邻居

“301室 张叔”、“502室 李哥”——这些不是系统生成的用户名,而是模拟了真实社区中的身份标识。当你知道工具的主人是楼下 301 室的张叔时,你更有可能爱惜工具、及时归还。


11. 结语

11.1 36 款 App 的旅程

从第 1 款 App(白噪音)到第 36 款(共享工具库),横跨了工具、教育、社交、情感、健康、环保、公益、平台等近 10 个领域。

每一款 App 都解决了一个特定的问题——有些工具很实用(慢病管理、碳足迹),有些偏观念普及(防骗雷达、临期食品救援),有些纯属实验(AI 树洞)。

36 款 App 没有什么宏大的主题——就是一个个独立的、小而美的概念验证。

11.2 给开发者的建议

  1. 重复方法是最容易避免的错误——写代码时留意是否复制了同名方法
  2. 共享类 App 的代码量不需要很多——345 行平均,比系列总平均低 37%
  3. 社区属性是最好的信用系统——"301室 张叔"比"用户 #12345"更能让人产生信任感
  4. 36 款 App 证明了 ArkUI 的能力边界——从白噪音到共享工具库,ArkUI 都做得来

11.3 致谢

36 款 App、36 篇博客。36 不是终点。

每一款 App 都有一个博客,每一个博客都记录了一款 App 从零到一的完整过程。如果你从第 1 篇读到了第 36 篇——你已经见证了超过 19,000 行代码、312 个编错误、360,000 字的开发记录。

现在,打开 DevEco Studio,去创造属于你自己的第 1 款——或者第 36 款——App 吧。


附录 A:核心代码速查

借出工具

borrowTool(id: number): void {
  this.borrowed = [id, ...this.borrowed];
  promptAction.showToast({ message: '📩 已借出!' });
}

归还工具

returnTool(id: number): void {
  const idx = this.borrowed.indexOf(id);
  if (idx >= 0) {
    const b = this.borrowed.concat([]);
    b.splice(idx, 1);
    this.borrowed = b;
  }
}

分类筛选

getFiltered(): Tool[] {
  if (this.selectedTag === 0) return TOOLS;
  const result: Tool[] = [];
  for (const t of TOOLS) { if (t.tag === TAGS[this.selectedTag]) result.push(t); }
  return result;
}

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐