HarmonyOS厨房助手实战第2篇:食谱列表、分类搜索与详情页
HarmonyOS厨房助手实战第2篇食谱列表、分类搜索与详情页摘要本篇进入厨房助手的核心模块食谱管理。我们会拆解RecipeListPage、RecipeCard和RecipeDetailPage理解分类筛选、关键词搜索、响应式网格、详情页 Tab、收藏和删除等功能。一、食谱数据模型食谱模型定义在models/Recipe.etsexport interface Recipe { id: string; name: string; category: RecipeCategory; cover: string; covers: string[]; rating: number; durationMin: number; servings: number; intro: string; ingredients: RecipeIngredient[]; steps: RecipeStep[]; tip: string; tags: string[]; nutrition: RecipeNutrition; createdAt: number; updatedAt: number; schemaVersion: number; }这个模型覆盖了一个家庭菜谱应用常见字段分类、封面、评分、用时、人数、简介、食材、步骤、小贴士和营养信息。二、分类侧边栏RecipeListPage维护了分类数组private readonly categories: CategoryItem[] [ { key: RecipeCategory.All, label: 全部 }, { key: RecipeCategory.Meat, label: 荤菜 }, { key: RecipeCategory.Vegetable, label: 素食 }, { key: RecipeCategory.Breakfast, label: 早餐 }, { key: RecipeCategory.Dessert, label: 甜点 } ];页面把它传给CategorySidebarCategorySidebar({ items: this.categories, selectedKey: this.category, onChange: (key: string) { this.onCategoryChange(key); } })组件只负责显示和回调真正的筛选逻辑仍在页面和服务层完成。三、搜索栏搜索栏使用TextInput输入变化后刷新列表TextInput({ placeholder: 搜索食谱名称, text: this.keyword }) .onChange((v: string) { this.onKeywordChange(v); })onKeywordChange会保存关键词并调用refresh()。项目现在是本地 JSON 数据直接刷新开销不大如果以后接入网络接口可以加防抖处理。四、服务层过滤筛选逻辑在RecipeServiceasync listFiltered(category: RecipeCategory, keyword: string): PromiseRecipe[] { const all: Recipe[] await this.list(); const kw: string keyword.trim().toLowerCase(); return all.filter((r: Recipe) { const matchCat category RecipeCategory.All || r.category category; const matchKw kw.length 0 || r.name.toLowerCase().indexOf(kw) 0; return matchCat matchKw; }); }服务层统一处理查询页面不用关心数据来自文件、缓存还是后端接口。五、响应式网格列表使用Flex换行网格Flex({ wrap: FlexWrap.Wrap }) { ForEach(this.recipes, (item: Recipe) { Column() { RecipeCard({ recipe: item }) } .width(this.cardWidthPct()) }) }卡片宽度根据断点变化private cardWidthPct(): string { if (this.bp BreakpointKey.LG) { return 50%; } if (this.bp BreakpointKey.MD) { return 33.33%; } return 50%; }小屏两列中屏三列大屏因为左侧列表只占 42% 宽度所以仍保持两列避免卡片过窄。六、详情页状态详情页RecipeDetailPage负责加载食谱、收藏状态和笔记const r await RecipeService.ensure(ctx).getById(this.recipeId); const fav await FavoritesService.ensure(ctx).findByRecipe(this.recipeId); this.recipe r; this.isFav fav ! null; this.note fav null ? : fav.note;详情页内部使用四个 Tab简介食材步骤笔记这样一页内容很多时用户不会被长页面压住。七、收藏与删除收藏使用FavoritesService.toggle()const nowFav: boolean await FavoritesService.ensure(ctx).toggle(this.recipeId); this.isFav nowFav;删除食谱时还会清理对应收藏await RecipeService.ensure(ctx).remove(this.recipe.id); await FavoritesService.ensure(ctx).removeByRecipe(this.recipe.id);这个细节很重要否则“我的收藏”里会留下已删除食谱的孤儿数据。八、本篇小结本篇完成了食谱模块的列表和详情拆解Recipe模型定义了完整菜谱结构。分类和搜索在页面触发服务层执行过滤。Flex ForEach实现响应式网格。详情页用 Tab 展示简介、食材、步骤和笔记。收藏和删除都通过服务层维护数据一致性。下一篇讲新建/编辑食谱包括封面选择、食材编辑、步骤编辑和营养信息。标签HarmonyOS, ArkTS, 食谱管理, Flex布局, 本地数据