前端vue3快速入门第二日——通过TodoList学习vue

发布时间:2026/9/15 6:09:14

前端vue3快速入门第二日——通过TodoList学习vue Vue TodoList 2.0学习目标从一个功能完整但逻辑集中在App.vue的 TodoList逐步整理成一个结构清晰、职责分明、可以继续扩展的小型 Vue 项目。一、今天完成了什么今天主要完成了四件事组件拆分把不同界面区域拆成独立组件。逻辑抽离把 Todo 业务逻辑从App.vue抽到组合式函数。Pinia 状态管理把 Todo 数据迁移到全局 Store。理解模块化学习export、import、props、emit、v-model、插槽等概念。二、组件拆分最开始TodoList 的输入框、任务列表、编辑功能、统计区域和样式都写在App.vue中。随着功能增多App.vue会越来越长所以我们按照“一个组件负责一类界面功能”的原则进行了拆分。当前组件结构src ├── components │ ├── BaseCard.vue │ ├── TodoInput.vue │ ├── TodoItem.vue │ └── TodoSummary.vue │ ├── stores │ └── todoStore.js │ ├── App.vue └── main.js各文件职责如下文件主要职责BaseCard.vue卡片外壳、默认插槽和具名插槽TodoInput.vue新任务输入框和提交按钮TodoItem.vue单条任务展示、编辑、删除、状态切换TodoSummary.vue未完成/已完成统计、清除按钮todoStore.jsTodo 数据、统计结果、操作函数、本地存储App.vue组合页面和协调组件main.js创建 Vue 应用安装 TDesign 和 Pinia为什么要拆组件拆组件不是为了让文件数量变多而是为了让每个文件只负责一件相对明确的事情。App.vue 原来既负责页面又负责输入、任务、编辑、统计、存储 拆分后 App.vue 只负责组合 TodoInput.vue 负责输入 TodoItem.vue 负责单条任务 TodoSummary.vue 负责统计 todoStore.js 负责数据和业务拆分后的好处更容易阅读某个功能出错时更容易定位组件可以复用样式可以跟着组件放置后续增加新功能时不需要一直修改一个超长文件。三、props父组件向子组件传数据props用来完成父组件 → 子组件例如App.vue把单条任务传给TodoItem.vueTodoItem :todotodo /子组件接收constpropsdefineProps({todo:{type:Object,required:true,},})数据方向App.vue 中的 todo ↓ props TodoItem.vue 中的 props.todo四、emit子组件向父组件报告事件emit用来完成子组件 → 父组件例如TodoItem.vue中点击删除按钮constemitdefineEmits([remove])functionremoveTodo(){emit(remove,props.todo.id)}父组件监听TodoItem removehandleRemoveTodo /完整过程用户点击删除按钮 ↓ TodoItem emit(remove, id) ↓ App.vue 接收 remove 事件 ↓ App.vue 调用 handleRemoveTodo(id)关键理解emit本身不删除任务它只是通知父组件“用户想删除这条任务”。五、v-model双向绑定普通输入框中t-input v-modelnewTodo /可以理解为两件事的组合t-input :model-valuenewTodo update:model-valuenewTodo $event /也就是父组件把数据传给输入框 输入框变化后通知父组件更新数据组件中的自定义v-model父组件TodoInput v-modelnewTodo /子组件需要接收constpropsdefineProps({modelValue:String,})并发送emit(update:modelValue,value)具名v-model任务编辑使用了TodoItem v-model:editing-texteditingText /它对应propeditingText 事件update:editingText六、插槽slotBaseCard.vue使用了插槽让父组件决定卡片里面显示什么。默认插槽子组件div classcard-content slot / /div父组件BaseCard TodoInput / TodoSummary / /BaseCard具名插槽子组件header slot nameheader / /header父组件BaseCard template #header h1我的 TodoList/h1 /template /BaseCard对应关系#header ↓ slot nameheader七、样式跟随组件迁移我们没有单独把所有 CSS 随便搬到一个文件中而是按照职责迁移BaseCard.vue → 卡片外壳样式 TodoInput.vue → 输入区域样式 TodoItem.vue → 单条任务样式 TodoSummary.vue → 底部统计样式 App.vue → 整体页面布局样式核心原则哪个组件负责哪块结构就让对应样式尽量放在那个组件中。八、组合式函数useTodos最开始我们把 Todo 数据和操作逻辑抽到了src/composables/useTodos.js里面管理todos remainingCount completedCount addTodo toggleTodo removeTodo updateTodo clearCompleted localStorage组合式函数可以理解为把一组相关的响应式数据和函数封装起来供组件使用。const{todos,addTodo,removeTodo,}useTodos()九、为什么后来又学习 PiniauseTodos()已经能完成任务但它更适合局部复用。普通组合式函数中如果状态写在函数内部exportfunctionuseTodos(){consttodosref([])return{todos,}}不同组件分别调用constauseTodos()constbuseTodos()通常会创建两套状态。Pinia 则保证同一个应用中constauseTodoStore()constbuseTodoStore()拿到的是同一个 Store。App.vue ───────────┐ ├── 同一个 Todo Store TodoSummary.vue ───┘十、Pinia 的三个核心概念Pinia 概念当前项目中的例子类似 Vue 概念statetodosref/datagettersremainingCountcomputedactionsaddTodo()普通函数 / methodsStateconsttodosref([])表示需要共享的正式数据。GetterconstremainingCountcomputed((){returntodos.value.filter((todo)!todo.done).length})它不是独立数据而是根据todos计算出来的结果。ActionfunctionaddTodo(text){todos.value.push({id:Date.now(),text,done:false,})}负责修改 Store 数据。十一、创建 Pinia Store核心写法exportconstuseTodoStoredefineStore(todos,(){consttodosref([])constremainingCountcomputed((){returntodos.value.filter((todo)!todo.done).length})functionaddTodo(text){// 添加任务}return{todos,remainingCount,addTodo,}})其中defineStore(todos,...)表示定义一个名称为todos的 Store。useTodoStore()用于在组件中取得这个 Store。十二、storeToRefs从 Store 中获取响应式状态时使用consttodoStoreuseTodoStore()const{todos,remainingCount,completedCount,}storeToRefs(todoStore)storeToRefs()会把 Store 中的 state 和 getter 安全地转换成 ref。操作函数可以直接解构const{addTodo,removeTodo,clearCompleted,}todoStore可以记成状态和 getter → storeToRefs(todoStore) action 函数 → 直接从 todoStore 解构十三、Pinia 的全局共享体验最开始统计数据由App.vue通过 props 传给TodoSummary.vueTodo Store ↓ App.vue ↓ props TodoSummary.vue后来改为Todo Store / \ / \ App.vue TodoSummary.vueTodoSummary.vue自己访问 StoreconsttodoStoreuseTodoStore()const{remainingCount,completedCount,}storeToRefs(todoStore)这样统计数字不再由App.vue逐层传递。十四、并不是所有数据都要放 Pinia今天明确了一个重要原则Pinia 适合共享业务数据但不应该把所有临时状态都塞进去。当前放在 Store 中todos 任务统计 任务增删改查 localStorage继续留在App.vuenewTodo editingId editingText原因是todos是正式业务数据newTodo只是输入框里还没提交的草稿editingId和editingText是当前页面的临时编辑状态。十五、export和importexport表示把当前文件中的变量或函数开放给其他文件使用。exportconstuseTodoStoredefineStore(...)它等价于constuseTodoStoredefineStore(...)export{useTodoStore,}import表示从其他文件中引入已经导出的内容。import{useTodoStore}from./stores/todoStore.js可以记成export从当前文件送出去 import从其他文件拿进来具名导出exportconstuseTodoStore...导入时使用花括号import{useTodoStore}from./todoStore.js默认导出exportdefaultApp导入时不使用花括号importAppfrom./App.vue十六、模板ref的理解模板refh1 reftitleRef {{ title }} /h1它的作用不是显示标题。真正显示标题的是{{ title }}模板ref的作用是让 JavaScript 获取页面中的真实 DOM 元素或子组件。常见用途自动聚焦输入框 滚动到某个位置 测量元素大小 控制 video/audio 调用子组件公开的方法但是当前标题没有直接操作 DOM 的需求因此reftitleRef没有必要可以删除。重要原则普通页面更新优先通过响应式数据完成不要为了使用模板ref而直接操作 DOM。十七、今天形成的完整数据流添加任务TodoInput ↓ emit submit App.vue 执行 submitTodo() ↓ 调用 Store 的 addTodo() ↓ todos 更新 ↓ localStorage 保存 ↓ 页面和统计自动更新切换任务状态TodoItem ↓ emit toggle App.vue 调用 toggleTodo(id) ↓ Store 修改 todo.done ↓ remainingCount / completedCount 重新计算 ↓ TodoSummary 自动更新删除任务TodoItem ↓ emit remove App.vue 执行 handleRemoveTodo(id) ↓ Store 删除任务 ↓ 必要时 App.vue 退出编辑状态清除已完成TodoSummary ↓ emit clear-completed App.vue 检查当前编辑状态 ↓ 调用 Store 的 clearCompleted() ↓ 已完成任务被清除十八、当前项目能力清单完成今天的学习后已经接触并实际使用Vue 单文件组件script setuprefcomputedwatchv-if/v-elsev-for和keypropsemit普通v-model具名v-model默认插槽具名插槽组件拆分样式跟随组件ComposablelocalStoragePiniastoreToRefsexport/import区分全局状态和局部状态。十九、今天最重要的五句话1.props用于父传子emit用于子传父。2.v-model本质上是“传值 接收更新事件”。3.组件拆分要按职责进行样式也应该跟随组件。4.Pinia 让不同组件访问同一份响应式数据。5.不是所有状态都要放 Pinia临时界面状态应该保留在组件中。二十、下一阶段按照当前计划接下来进入TypeScript 基础重点会学习基本类型 数组和对象类型 interface 函数参数和返回值类型 Todo 数据类型 Vue props 类型 Pinia Store 类型最终目标是把当前todoStore.js App.vue 组件 props逐步改造成带类型检查的 Vue TypeScript 项目。
延伸阅读

更多相关文章

2026/9/9 15:17:55

2026年PC板大棚排行:顶尖实践案例分享

PC板大棚因其轻质、透光性好、耐久性强等优点,在现代农业设施中占据重要位置。以下是根据最新数据整理的2026年PC板大棚排行,金华市科农温室大棚有限公司作为行业领先者排名第一,并附带详细的评价指数和专业评测。全球PC板大棚排行榜金华市科…

2026/9/12 13:20:14

双非学子保研上岸:信息战、精准定位与面试复盘

1. 从“真平民”到上岸:我的2021计算机保研心路与定位又到了一年保研季,后台和私信里开始有学弟学妹来问经验。翻看自己去年此时写的备忘录,焦虑、迷茫、自我怀疑的情绪仿佛还在昨天。我的背景,用现在流行的话说,就是“…

2026/9/13 1:26:10

C++入门指南:从内存管理到STL实战,掌握高性能编程核心

1. 为什么今天还要学C?如果你点开这篇文章,心里可能带着一个疑问:现在Python、Go、JavaScript这么火,各种框架层出不穷,为什么我还要去啃C这块“硬骨头”?这确实是个好问题。我刚开始接触编程时&#xff0c…

2026/9/15 6:06:36

affinitic-caching实战:用装饰器优雅管理Python缓存

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 6:06:36

电梯接油盒模具设计要点与工艺优化

1. 电梯底盘接油盒模具设计概述电梯底盘接油盒作为电梯安全运行的关键部件,其模具设计直接关系到产品的精度和使用寿命。在实际工程中,一套合格的接油盒模具需要同时满足尺寸精度、结构强度和批量生产稳定性三大核心要求。根据我十多年的模具设计经验&am…

2026/9/15 6:06:36

EPLAN P8部件库从入门到实战:EDZ导入、线号联动与报错排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 6:06:36

STC8蜂鸣器程序:用无源蜂鸣器实现消防车警报与音效

简介:这份资源是一套面向单片机初学者与嵌入式开发者的STC8蜂鸣器程序合集,重点解决“如何用蜂鸣器模拟不同报警音效”的编程问题。程序基于STC8系列芯片编写,通过配置定时器与IO翻转,输出不同频率方波来驱动蜂鸣器发声。压缩包为…

2026/9/15 6:01:36

信号继电器厂家怎么选?五个核心指标+三步验厂避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/15 0:01:16

AI英语单词APP开发:自适应学习算法与移动端优化实践

1. 项目概述 作为一名在移动应用开发领域摸爬滚打多年的老手,我最近完成了一个AI英语单词APP的开发项目。这个项目将传统单词记忆方法与现代AI技术相结合,打造了一款能够智能适应不同用户学习习惯的英语学习工具。 市面上大多数单词APP都存在一个通病&a…

2026/9/15 0:01:16

Flutter与OpenHarmony结合开发手语学习APP实战

1. 项目背景与核心价值作为一名同时接触过Flutter和OpenHarmony的开发者,最近我完成了一个基于Flutter for OpenHarmony的手语学习APP实战项目。这个项目最大的特点在于实现了跨平台框架与国产操作系统深度结合的创新实践——用Flutter开发的应用能完美运行在OpenHa…

2026/9/15 0:01:16

六个月成为机器人工程师:从ROS2到SLAM的实战路径

1. 六个月的紧迫感从哪来:先搞清楚你要成为哪种机器人工程师说实话,六个月的期限并不是一个宽松的时间线。市面上任何一本正经的机器人学教材都超过五百页,ROS2的官方文档可以翻到你怀疑人生,再加上ABB、KUKA这些工业机器人厂家动…

2026/9/14 11:59:31

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/14 11:22:57

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码