上一篇讲餐桌方案页时我说过一个点用户选中的不是一个 UI 卡片而是一整桌饭。那选完这一桌饭以后下一步最自然的问题就是我到底要买什么如果应用只把用户带到一个空白买菜页让用户重新手填食材那前面的推荐就断掉了。所以中式美食里的买菜清单页不是单独存在的页面它是从TableSolutionPage里带着当前方案过来的。用户点“去买菜”时ShoppingListPage接到的不是一个字符串而是一份完整的TableSolutionPlan。这样买菜页就知道这一桌有哪些菜、每道菜属于什么分类、后面应该给什么替换建议。本文验证环境项目版本或范围开发工具Flutter / Dart 工程配合 DevEco Studio 做 HarmonyOS 上架前体验验证Dart SDK^3.12.2Flutter 依赖flutter、cupertino_icons、flutter_lintsHarmonyOS 目标中式美食上架后的家庭餐桌链路HarmonyOS SDK API 20 作为后续适配目标核心文件lib/main.dart入口页面TableSolutionPage清单页面ShoppingListPage核心模型TableSolutionPlan、ShoppingSectionData、ShoppingItemData这里讲的是当前项目真实代码里的买菜清单链路。它现在还是 Flutter 工程里的实现但页面拆法、数据传递和分组思路后面迁到 ArkUI 时仍然能复用。先把当前方案带过去从方案页进入买菜页时代码是这样走的Navigator.of(context).push(MaterialPageRoute(builder:(_)ShoppingListPage(plan:plan)),);这个写法很朴素但它避免了一个常见问题买菜页不要自己重新决定“当前是哪一桌”。用户是在某一套方案里点的买菜那买菜页就应该服务这套方案。这个上下文如果丢了后面就会出现推荐页和清单页对不上的情况。比如用户刚选了“清淡版”买菜页却展示“招待版”的食材这种体验会很别扭。所以我更喜欢把当前上下文直接传过去。等后面数据复杂了可以把完整对象换成planId再从仓储里查但无论怎么改买菜页都不应该脱离当前方案独立工作。清单页只认一份 planShoppingListPage的入口很清楚classShoppingListPageextendsStatefulWidget{constShoppingListPage({super.key,requiredthis.plan});finalTableSolutionPlanplan;overrideStateShoppingListPagecreateState()_ShoppingListPageState();}这其实是一个很好的边界。页面不关心用户刚才点的是哪个按钮也不关心方案页怎么展示。它只关心一件事我拿到了一份TableSolutionPlan现在要把它变成买菜清单。这个边界一清楚后面功能就好加了。比如要做“已买”“可替换”“预计花费”“缺货提醒”都可以围绕plan派生出来不用反过来改方案页。分组不是装饰是为了让用户能买买菜清单如果只是从上到下列十几个食材用户在菜市场或超市里很难照着走。中式美食这里按用途拆分至少要让用户知道哪些是主菜、哪些是汤、哪些是时蔬。示意代码可以这样理解ListShoppingSectionDatashoppingSectionsFor(TableSolutionPlanplan){finalmenuItemsplan.menuItems;return[ShoppingSectionData(title:主菜,items:menuItems.where((item)item.category主菜).map((item)ShoppingItemData(name:item.name)).toList(),),ShoppingSectionData(title:汤,items:menuItems.where((item)item.category汤).map((item)ShoppingItemData(name:item.name)).toList(),),ShoppingSectionData(title:时蔬,items:menuItems.where((item)item.category时蔬).map((item)ShoppingItemData(name:item.name)).toList(),),];}真实页面可以比这段代码更细比如加数量、备注、可替换食材。但方向不要变清单要服务实际采购不只是服务页面排版。分组用户价值页面表现主菜先确认今天这桌饭的核心放在最前面避免漏买关键食材汤提醒耗时和锅具安排和主菜分开方便判断是否要提前炖时蔬支持替换和临场调整给出“可换菜心”等备注备注降低临场决策成本告诉用户哪里可以替代备注比“更多文字”重要买菜页里有一个容易被低估的东西备注。比如“小青菜可换菜心”这种话看起来只是很短的一句但对真实用户很有用。因为买菜时最常见的问题不是“不知道菜名”而是“现场没有这个我能不能换”。ShoppingItemData里保留备注字段就是为了让清单变得更像一个能落地的助手classShoppingItemData{constShoppingItemData({requiredthis.name,this.amount,this.note,});finalStringname;finalStringamount;finalStringnote;}我建议这类生活工具不要把字段设计得太“后台化”。数量、备注、替换建议这些字段最好在模型里就有位置。否则后面产品想补体验时只能到处塞字符串。底部操作栏要给下一步买菜清单页看完以后用户还需要继续往下走。如果清单页只展示列表用户买完东西就不知道回到哪里。中式美食这里用底部操作栏把用户往下一步带可以继续看厨房节奏也可以回到餐桌方案。这类入口不要太多。两个就够了操作适合场景继续做菜用户已经确认清单想看备菜和出菜顺序回到方案用户觉得清单太复杂想换一桌更简单的操作少一点用户反而更容易走下去。为什么这篇值得单独拆买菜清单看起来只是方案页后面的一小步但它其实决定了中式美食能不能从“内容应用”变成“行动应用”。只看菜谱用户学到的是一道菜怎么做能生成清单用户才会真的开始准备。这里的差别很大。对工程来说买菜清单页至少承担三件事承接上游方案不丢当前上下文把菜品按真实采购场景分组给下一步动作不让用户停在列表里。只要这三件事做稳后面接家庭库存、常买食材、价格估算、多人协作都会顺很多。工程验收记录检查点当前结果页面入口ShoppingListPage(plan: plan)明确接收当前餐桌方案数据来源买菜内容从TableSolutionPlan.menuItems派生不另写一套菜名分组能力主菜、汤、时蔬可以拆开展示备注能力ShoppingItemData支持amount和note操作闭环底部操作栏继续承接“做菜”或“回到方案”迁移价值后续迁到 ArkUI 时仍然可以保留“方案驱动清单”的数据方向本文小结买菜清单页最怕变成一个孤立页面。中式美食这里的做法是让它接住当前餐桌方案再把方案拆成可以执行的采购动作。这样用户从“今晚吃什么”到“我要买什么”之间就不会断。如果你也在做类似的家庭餐食应用我会建议先把这个链路想清楚推荐结果能不能直接变成下一步动作如果不能用户还是要自己重新组织信息应用的价值就少了一半。最后留一个问题买菜清单里的数量你会先用固定规则估算还是让用户手动调整后再沉淀成家庭偏好我现在更倾向先给一个轻量默认值再让用户调整因为一开始就追求完全准确反而会拖慢体验落地。