综合练习
迷你 Todo + 路由 + Pinia。
40 分钟
综合练习
这一课你将能做到
- 独立完成「Todo + Router + Pinia + 三态 fetch」迷你应用并
npm run build通过 - 用自己的话写一段 Vue 与 React 实现同一 Todo 的差异(200 字级)
- 明确收官后:Vue 路线图可打勾,本站主产品代码仍回 Next/React
为什么要学
零件课过完不等于会组装。综合练习强迫你做选择:状态放组件还是 Pinia、详情要不要独立路由、列表要不要远程加载。
做完后,读 Element Admin 一类项目会轻松很多。
先建立图像
/ 列表 + 筛选 + 新增(Pinia)
/todo/:id 详情编辑
可选 /api/todos 初始加载(三态)
localStorage 持久化
npm run build 验收
| 验收项 | 标准 |
|---|---|
| 路由 | 直达 /todo/1 不白屏 |
| 状态 | 刷新后列表仍在(若做了持久化) |
| 远程 | 有 loading/error(若接 API) |
| 构建 | build 成功 |
跟着做
步骤 1:搭路由
routes: [
{ path: "/", component: TodoList },
{ path: "/todo/:id", component: TodoDetail },
]
App.vue 放导航与 RouterView。
步骤 2:Pinia store
沿用 pinia 课骨架:items/filter/visible/add/toggle,再补:
function update(id, text) {
const row = items.value.find((x) => x.id === id);
if (row) row.text = text;
}
function hydrate() {
const raw = localStorage.getItem("vue-todo");
if (raw) items.value = JSON.parse(raw);
}
watch(items, (v) => localStorage.setItem("vue-todo", JSON.stringify(v)), {
deep: true,
});
应用启动时 hydrate()。
步骤 3:列表页
<script setup>
import { storeToRefs } from "pinia";
import { useTodoStore } from "@/stores/todo";
import { RouterLink } from "vue-router";
const store = useTodoStore();
const { visible, filter } = storeToRefs(store);
</script>
<template>
<input
@keyup.enter="
store.add($event.target.value);
$event.target.value = '';
"
/>
<button
v-for="f in ['all', 'active', 'done']"
:key="f"
type="button"
@click="filter = f"
>
{{ f }}
</button>
<ul>
<li v-for="t in visible" :key="t.id">
<input type="checkbox" :checked="t.done" @change="store.toggle(t.id)" />
<RouterLink :to="`/todo/${t.id}`">{{ t.text }}</RouterLink>
</li>
</ul>
</template>