当前位置: 首页 > news >正文

鸿蒙 RecommendData 这类卡片数据层应该怎么组织

适合谁看

  • 想写可维护鸿蒙卡片数据层的人

  • 正在做每日推荐、排行榜、轮播类鸿蒙卡片的人

  • 不想把数据硬写进鸿蒙 Ability 文件的人

问题背景

鸿蒙卡片代码很容易越写越乱的一个原因是:

  • Ability 管生命周期

  • Ability 还管数据

  • Ability 还管兜底

  • Ability 还管资源校验

最后所有逻辑都挤在同一个文件里,改一个数据要动 Ability,改一个兜底要动 Ability,改一个资源名也要动 Ability。

项目中的真实场景

食界探味当前把鸿蒙卡片数据层单独放在:

  • app/ohos/entry/src/main/ets/formability/RecommendData.ets

对应的 Ability 只负责消费它:

// DailyRecommendFormAbility.ets import { getRecommendOfToday, resolveImageResName } from './RecommendData'; onAddForm(want: Want): formBindingData.FormBindingData { const item = getRecommendOfToday(); return formBindingData.createFormBindingData({ dishName: item.name, dishImage: resolveImageResName(item.imageResName), // ... }); }

Ability 不关心数据从哪来、怎么选、怎么校验,只关心"拿数据 → 绑定到卡片"。

核心实现

一、RecommendData.ets 的完整结构

// 1. 数据结构定义 export interface RecommendItem { id: string; // 菜品 ID(用于点击跳转) name: string; // 菜名 region: string; // 地区 imageResName: string; // 鸿蒙图片资源名 highlight: string; // 口味亮点 summary: string; // 一句话介绍 } // 2. 推荐列表(10 道菜品) const RECOMMEND_LIST: RecommendItem[] = [ { id: 'beef-curry', name: '牛肉咖喱', region: '印度 · 亚洲', imageResName: 'dish_beef_curry', highlight: '浓郁香料', summary: '椰香与香料层层叠起,入口热烈又厚实。' }, { id: 'sukiyaki', name: '寿喜锅', region: '日本 · 亚洲', imageResName: 'dish_sukiyaki', highlight: '鲜甜酱香', summary: '牛肉、蔬菜与寿喜烧汁一起慢慢煮到刚好。' }, // ... 共 10 道菜品 ]; // 3. 兜底数据 const FALLBACK_ITEM: RecommendItem = { id: 'fallback', name: '环球美食', region: '世界', imageResName: 'dish_fallback', highlight: '今天吃什么', summary: '打开食界探味,挑一道想去认识的新菜。', }; // 4. 图片资源白名单 const VALID_IMAGE_RES_NAMES: Set<string> = new Set( RECOMMEND_LIST.map((item) => item.imageResName).concat(FALLBACK_ITEM.imageResName) ); // 5. 今日选择算法 export function getRecommendOfToday(): RecommendItem { ... } // 6. 兜底获取 export function getFallbackItem(): RecommendItem { ... } // 7. 图片资源校验 export function resolveImageResName(imageResName: string): string { ... }

这个文件承担了 7 类职责,每一类都值得单独分析。

二、职责 1:定义卡片数据结构

export interface RecommendItem { id: string; name: string; region: string; imageResName: string; highlight: string; summary: string; }

通过RecommendItem明确了卡片需要的 6 个字段。这让数据项结构先稳定下来。

字段设计的考量:

字段

类型

用途

为什么需要

id

string

点击跳转到菜品详情页

卡片点击需要传参数

name

string

卡片上显示菜名

核心展示信息

region

string

卡片上显示地区

帮助用户判断兴趣

imageResName

string

鸿蒙图片资源名

卡片需要显示图片

highlight

string

口味亮点标签

吸引用户点击

summary

string

一句话介绍

补充信息,帮助决策

这个结构既不过于复杂(6 个字段),也不过于简单(包含了点击跳转需要的id)。

三、职责 2:维护推荐列表和兜底项

const RECOMMEND_LIST: RecommendItem[] = [ // 10 道菜品... ]; const FALLBACK_ITEM: RecommendItem = { id: 'fallback', name: '环球美食', region: '世界', imageResName: 'dish_fallback', highlight: '今天吃什么', summary: '打开食界探味,挑一道想去认识的新菜。', };

RECOMMEND_LIST是正常推荐数据,FALLBACK_ITEM是兜底数据。

兜底项的价值:

场景

没有兜底

有兜底

列表为空

卡片显示空白

显示"环球美食"

图片资源不存在

卡片渲染崩溃

显示兜底图片

数据异常

用户看到异常

用户看到正常兜底

鸿蒙卡片比应用页面更怕显示异常——因为卡片在桌面上,异常会一直显示,用户无法刷新。

四、职责 3:图片资源校验

const VALID_IMAGE_RES_NAMES: Set<string> = new Set( RECOMMEND_LIST.map((item) => item.imageResName).concat(FALLBACK_ITEM.imageResName) ); export function resolveImageResName(imageResName: string): string { if (!imageResName || !VALID_IMAGE_RES_NAMES.has(imageResName)) { return FALLBACK_ITEM.imageResName; } return imageResName; }

VALID_IMAGE_RES_NAMES是鸿蒙图片资源的白名单。resolveImageResName会检查传入的资源名是否在白名单中,如果不在就返回兜底图片。

这个设计的好处:

  1. 防止资源不存在导致崩溃— 鸿蒙卡片如果引用了不存在的$r()资源,会直接崩溃

  2. 新增菜品时只需加白名单— 不需要改校验逻辑

  3. 兜底行为明确— 用户永远看不到空白图片

五、职责 4:今日选择算法

export function getRecommendOfToday(): RecommendItem { if (RECOMMEND_LIST.length === 0) return FALLBACK_ITEM; const now = new Date(); const dateNum = now.getFullYear() * 10000 + (now.getMonth() + 1) * 100 + now.getDate(); const index = dateNum % RECOMMEND_LIST.length; return RECOMMEND_LIST[index]; }

日期轮询算法:用年月日生成数字,对列表长度取模。

日期

dateNum

index (mod 10)

菜品

2025-01-15

20250115

5

牛肉塔可

2025-01-16

20250116

6

石锅拌饭

2025-01-17

20250117

7

班尼迪克蛋

这个算法的特点:

  • 同一天内结果一致— 所有卡片展示同一道菜

  • 不同天自动切换— 不需要手动更新

  • 列表为空时兜底— 返回FALLBACK_ITEM

  • 不依赖网络— 纯本地计算

六、职责 5:兜底获取

export function getFallbackItem(): RecommendItem { return FALLBACK_ITEM; }

单独导出兜底项,方便其他地方使用(比如卡片 UI 的默认值)。

七、数据层和 Ability 的分工

RecommendData.ets(数据层) │ ├─ RecommendItem ← 数据结构 ├─ RECOMMEND_LIST[] ← 推荐列表 ├─ FALLBACK_ITEM ← 兜底数据 ├─ VALID_IMAGE_RES_NAMES ← 资源白名单 ├─ getRecommendOfToday() ← 选择算法 ├─ getFallbackItem() ← 兜底获取 └─ resolveImageResName() ← 资源校验 DailyRecommendFormAbility.ets(Ability 层) │ ├─ onAddForm() ← 消费数据层 ├─ onUpdateForm() ← 消费数据层 └─ onRemoveForm() ← 清理资源

Ability 只关心"拿数据 → 绑定到卡片",不关心数据从哪来、怎么选、怎么校验。

八、为什么这种组织方式值得复用

好处

说明

职责清晰

数据层管内容,Ability 管生命周期

易于测试

数据层可以独立测试,不需要启动 Ability

易于扩展

新增菜品只需加 RECOMMEND_LIST

易于维护

改数据不影响 Ability,改 Ability 不影响数据

兜底完善

资源异常时不会崩溃

关键代码位置

文件

作用

app/ohos/entry/src/main/ets/formability/RecommendData.ets

鸿蒙卡片数据层(本文核心)

app/ohos/entry/src/main/ets/formability/DailyRecommendFormAbility.ets

消费数据层

数据层职责全景图

RecommendData.ets │ ├─ 接口定义 │ └─ RecommendItem { id, name, region, imageResName, highlight, summary } │ ├─ 数据存储 │ ├─ RECOMMEND_LIST[] ← 10 道菜品 │ ├─ FALLBACK_ITEM ← 兜底数据 │ └─ VALID_IMAGE_RES_NAMES ← 图片资源白名单 │ ├─ 选择算法 │ └─ getRecommendOfToday() ← 日期轮询 │ ├─ 兜底获取 │ └─ getFallbackItem() ← 返回 FALLBACK_ITEM │ └─ 资源校验 └─ resolveImageResName() ← 白名单校验 + 兜底

常见坑

  • 把推荐列表直接写在 Ability 里— 改数据要动 Ability,职责混乱

  • 没有兜底数据项— 鸿蒙卡片异常时显示空白

  • 图片资源名不做校验— 鸿蒙$r()引用不存在的资源会崩溃

  • 每次更新时间策略都散落在多个地方— 应该集中管理

  • 数据结构不稳定— 新增字段时要改多个文件

  • 没有导出数据结构— 其他文件无法复用RecommendItem

可复用模板

鸿蒙卡片数据层模板

// 1. 数据结构 export interface CardItem { id: string; title: string; subtitle: string; imageRes: string; highlight: string; summary: string; } // 2. 数据列表 const ITEM_LIST: CardItem[] = [ { id: '1', title: '标题1', subtitle: '副标题1', imageRes: 'img_1', highlight: '亮点1', summary: '简介1' }, // ... ]; // 3. 兜底数据 const FALLBACK: CardItem = { id: 'fallback', title: '默认标题', subtitle: '默认副标题', imageRes: 'img_fallback', highlight: '默认亮点', summary: '默认简介', }; // 4. 资源白名单 const VALID_RES: Set<string> = new Set(ITEM_LIST.map(i => i.imageRes).concat(FALLBACK.imageRes)); // 5. 选择算法 export function getTodayItem(): CardItem { if (ITEM_LIST.length === 0) return FALLBACK; const now = new Date(); const dateNum = now.getFullYear() * 10000 + (now.getMonth() + 1) * 100 + now.getDate(); return ITEM_LIST[dateNum % ITEM_LIST.length]; } // 6. 资源校验 export function safeImage(name: string): string { if (!name || !VALID_RES.has(name)) return FALLBACK.imageRes; return name; }

数据层职责清单

鸿蒙卡片数据层应该包含: □ 数据结构定义(export interface) □ 数据列表(const LIST) □ 兜底数据(const FALLBACK) □ 资源白名单(const VALID_RES) □ 选择算法(getTodayItem) □ 资源校验(safeImage) □ 兜底获取(getFallback)

本篇总结

鸿蒙卡片数据层应该独立于 Ability 文件。RecommendData.ets这种组织方式很适合"每日推荐"类卡片:

  1. 数据结构稳定RecommendItem接口定义了 6 个字段

  2. 数据和兜底并存RECOMMEND_LIST+FALLBACK_ITEM

  3. 资源校验完善VALID_IMAGE_RES_NAMES白名单 +resolveImageResName兜底

  4. 选择算法轻量— 日期轮询,不依赖网络

  5. 职责分离— 数据层管内容,Ability 管生命周期

先把数据结构、兜底和轮换规则单独收好,后面维护会轻很多。这份代码很适合当鸿蒙卡片数据层组织的第一块样板。

http://www.gsyq.cn/news/1542993.html

相关文章:

  • 2026 成都锦江区名表回收门店汇总,市中心靠谱收表商家合扬 - 开心测评
  • 线上公证操作流程?线上公证怎么办理?数字化时代的公证 - 指上通
  • 2026郑州全屋定制装修公司十大排名推荐 本地高口碑优选 - 装修新知
  • Change-case:为什么它成为JavaScript开发者的首选大小写转换库?
  • 从虚拟阵列到精准感知:TI毫米波MIMO雷达设计实战解析
  • PAROL6桌面机械臂:如何用3D打印和开源方案打造工业级机器人
  • 2026年无人机电机磁铁品牌实力排行榜:谁才是真正的性能之王? - 936品牌测评网
  • 计划上市的国产AI算力公司盘点:谁更适合算力中心建设?
  • 全国商标转让与商品条码极速申请流程及服务商筛选标准 - GEORANK
  • 大连名表变现避坑|正规门店分级甄选,闲置腕表出手必看注意事项 - 薛定谔的梨花猫
  • 解决导热硅脂涂覆不均 如何选靠谱的涂覆设备 - 信息热点
  • 广州装修公司哪家靠谱?2026 本地口碑与施工实力参考榜单 - 装修新知
  • 美景舒适家:优质暖气企业,布局重庆乐山云南成都等地 - 十大品牌榜
  • 2026 沈阳代账公司靠谱榜单!浑南铁西于洪工商注册,工厂建筑电商财税优选,代账避坑核心:必须持有财政局代理记账许可 - 品牌优企推荐
  • 2026主流线上雅思机构专业测评:垂直深耕、备考优选 - 品牌2026
  • 无犯罪记录证明公证在哪里办?无犯罪记录证明公证办理流程是什么?一文解锁 - 指上通
  • ZigBee设备事件与警报集群:实现智能设备主动通信的核心机制
  • 2026年喇叭厂家选型指南:汽车喇叭领域代表性厂家解析 - 信息热点
  • 告别手动配置:让PVE主机自动获取IP地址的DHCP实战指南
  • ZigBee ZCL多状态输出与轮询控制集群实战解析
  • 徐州黄金回收哪家好,2026本地商家实测体验分享 - 生活测评君
  • Java毕业设计-基于 Spring Boot 的房屋交易管理系统的设计与实现 基于 Spring Boot 的线上房产交易服务平台(源码+LW+部署文档+全bao+远程调试+代码讲解等)
  • 闲置大牌包怎么卖高价?2026 成都回收实测,禹竞名奢汇连锁直营实测分享 - 奢品小当家
  • 2026年光纤收发器厂家选型指南:代表性品牌解析与高性价比方案推荐 - 信息热点
  • 超快恢复二极管1N6536:30ns反向恢复时间在高频开关电源中的应用与选型
  • Electron跨平台音乐聚合播放器架构深度解析与实战指南
  • 从原理到实践:在Unreal中构建基于波叠加的动态水面材质
  • 三层交换机原理与华为实战配置:从VLAN间路由到核心网络部署
  • 卫生间隔断配件常见问题解答(2026专家版) - 信息热点
  • 如何高效使用Adobe Illustrator脚本自动化:提升设计工作流的完整指南