Appearance
页面拆解与 Prompt 策略
先拆页面与组件契约,再写 Prompt——让 AI 一次生成对的前端代码。
AI CODING · 场景二 · 契约先行
顺序固定:主路径 → 页面职责 → 组件 props/事件 → 给 AI 的 Prompt → diff → 浏览器。跳过契约直接「写首页」,后面极难拆。
时间 40–60 分钟(拆卡)组件 2 个起输出 可执行 Prompt
本节要点
- 首页 / 详情各干什么、两个组件的输入输出
- 一张「看见就停」的坏 Diff 样例
- 组件+首页、详情页两张可粘贴 Prompt
跟做顺序
text
主路径(用户点什么)
→ 页面清单(每页一句话职责)
→ 组件契约(props / 事件)
→ 域规则(筛选 / 查找)——场景二总览 Mock 已先做则跳过
→ 给 AI 的 Prompt(一次一个组件或一页)
→ 看 diff → 浏览器验收页面清单
| 页面 | 职责 | 不做 |
|---|---|---|
| 首页 | 保存当前用餐场景;调 dishesForScene;组合选择器与列表;收 open 后导航 | 声明第二套场景数组;在模板里手写 filter |
| 详情 | 从路由读 id;调 findDish;展示字段或空态 | 复制整份 Mock;自己请求网络 |
用户点什么(和场景一同一条):
text
打开首页 → 选「一人食」→ 列表变化 → 点「番茄炒蛋」→ 详情有小贴士
故意坏 id → 空态,不是白屏冻结两个组件契约
text
ScenePicker
输入:scenes、modelValue
输出:update:modelValue(sceneId)
DishCard
输入:item
输出:open(dishId)卡片不自己跳转;父页听事件再导航——以后列表复用到收藏页时不用改卡片。
TypeScript 形态示意:
ts
// ScenePicker
defineProps<{ scenes: readonly MealScene[]; modelValue: MealSceneId }>();
defineEmits<{ "update:modelValue": [value: MealSceneId] }>();
// DishCard
defineProps<{ item: Dish }>();
defineEmits<{ open: [id: string] }>();首页接线形态(实现细节可调,职责不能漂):
ts
const selectedScene = ref<MealSceneId>("solo");
const visible = computed(() =>
dishesForScene(DISHES, selectedScene.value),
);
function onOpen(id: string) {
uni.navigateTo({ url: `/pages/detail/index?id=${id}` });
}看见这种 Diff 就停
diff
<script setup lang="ts">
+const scenes = [
+ { id: "family", name: "家庭" },
+ { id: "future-scene", name: "未约定场景" },
+]
+const visible = computed(() =>
+ dishes.filter((item) => item.sceneIds.includes(selected.value)),
+)
+function open(id: string) {
+ uni.navigateTo({ url: `/pages/detail/index?id=${id}` })
+}
</script>三类问题叠在一起:组件新建场景真源、组件做筛选、组件决定 URL。
处理:场景与筛选回 domain,导航回 page;不要在页面加兼容分支「先顶着」。
| 坏信号 | 正确落点 |
|---|---|
组件内再声明 scenes = [...] | 只用 props 传入的 MEAL_SCENES |
组件内 filter | dishesForScene |
卡片里 navigateTo | 只 emit('open', id) |
MealSceneId 改成 string | 打回,不要放宽 |
给 AI 的 Prompt
两张卡分开执行。第一组出错只查组件与首页;第二组只查路由与详情。
A · 两个组件 + 首页接线
给 AI · Prompt · ScenePicker + DishCard + 首页
text
【目标】拆出用餐场景选择与菜品卡片,并接到首页。
【允许改】
- 创建 components/ScenePicker.vue
- 创建 components/DishCard.vue
- 修改 pages 首页
【禁止改】
- domain/、data/(若已存在)
- package.json、lockfile、构建配置
- Mock 字段结构
【契约】
- ScenePicker:scenes / modelValue → update:modelValue(MealSceneId)
- DishCard:item → open(dishId)
- 首页负责状态、调用 dishesForScene、导航
【验收】
- 开发预览:切换用餐场景列表变化;点卡片进详情(详情可下一张卡再做)
- 若有单测:domain 相关全绿
【请你】先复述允许文件、禁止文件与契约;我确认后再改。B · 详情页(单独一张)
给 AI · Prompt · 详情页
text
【目标】补齐菜品详情页。
【允许改】详情页文件 + 路由注册(如 pages.json)
【禁止改】domain/、data/、components/、依赖配置
【契约】
- 从 onLoad/query 读 id;非 string 当空
- 使用 domain 的 findDish;不复制 Mock
- 合法 id:菜名、摘要、依据、小贴士;非法 id:明确空态文案
【验收】合法 id 与故意错误 id 各点一次;构建通过
【请你】先复述范围与契约,确认后再改。Prompt 策略三条
- 范围写死 — 允许 / 禁止文件列表
- 契约写死 — 输入输出比「好看」优先
- 验收写死 — 你点哪里算过;AI 自称完成不算
执行后看 diff:
bash
git diff -- components/ScenePicker.vue \
components/DishCard.vue \
pages/...核对:props/事件是否被放宽成 string;是否出现第二套场景数组;导航是否漏在卡片里。