本项目与 React 记录板使用相同任务:新增、完成、搜索和只看待学。对比时关注状态如何读写、派生值如何表达、事件如何进入模型,不要只比较模板行数。项目数据在内存中,刷新后重置。

运行起点

pnpm create vite@latest study-vue --template vue-ts
cd study-vue
pnpm install

用 App.vue 覆盖 src/App.vue,用 style.css 覆盖 src/style.css。保留模板 main.ts,然后运行 pnpm dev。运行 pnpm build 时确认 vue-tsc 与生产构建都成功。

为什么这样组织

lessons 和输入条件是 ref,visible 与待学数量是 computed。模板里使用 v-model 绑定输入与复选框,脚本中显式使用 .value。新增后清空草稿和旧错误;改变筛选只影响派生结果,不删除原记录。

const visible = computed(() => {
  const word = query.value.trim().toLocaleLowerCase();
  return lessons.value.filter(item =>
    (!onlyPending.value || !item.done) &&
    item.title.toLocaleLowerCase().includes(word));
});

本例在组件内通过 map 更新记录,便于与 React 对照。Vue 也能追踪许多对象和数组的原地修改;是否采用不可变更新取决于边界与工具需求,不能把 React 的所有约定直接当成 Vue 必须遵守的运行机制。

若拆成 LessonForm 和 LessonList,父组件可以持有记录,子组件 emit 新增或切换 ID。只在多个页面确实共享数据且管理复杂度增长时,再考虑 Pinia 等状态方案。网络请求仍应通过独立接口处理 HTTP、校验与取消,而不是塞进 computed。

完成条件

新增中文与英文标题,提交空格,反复切换完成状态与过滤条件,检查数量和可见列表一致。搜索不存在的词时应显示无匹配项;清空搜索后原记录仍在。使用键盘操作,并检查错误提示可被感知。

练习:加入按标题和按新增顺序排序,但不要直接 sort 原数组后意外改变默认顺序;再把编辑中的草稿与正式记录分开。接入本地持久化时,写明版本与坏数据回退规则。

需要路由时使用 Vue Router;需要服务端渲染、预渲染或文件路由时再评估 Nuxt。基础逻辑可以复用,路由、数据加载与部署的边界仍要按框架契约调整。

参考:Vue 快速上手、组件基础、Vue Router、Pinia。