Vue3实战入门:手把手拆解Todo应用
前情提要:每个Vue学习者都踩过的坑
你是否经历过这样的困境?看文档时觉得v-model、v-for这些指令都懂,打开编辑器却不知从何下手;明明理解了响应式原理,真写代码时数据更新总是不按预期。这个Todo项目就像一面照妖镜,能照出Vue学习路上的认知盲区。
一、Vue3核心指令速览
指令 | 描述 |
---|---|
v-bind | 用于将 Vue 实例的数据绑定到 HTML 元素的属性上。 |
v-if | 用于根据表达式的值来条件性地渲染元素或组件。 |
v-for | 用于根据数组或对象的属性值来循环渲染元素或组件。 |
v-on | 用于在 HTML 元素上绑定事件监听器,使其能够触发 Vue 实例中的方法或函数。 |
v-model | 用于在表单控件和 Vue 实例的数据之间创建双向数据绑定。 |
二、项目实战应用
直接切入正题,讲讲 Vue 在这个 Todos 应用里到底有多厉害。
First: 建立框架
<script src="./vue.js"></script>
<div id="app">
</div>
<script type="module">
const {
createApp,// 创建Vue3应用
ref // 响应式数据
} = Vue;
const app = createApp({
setup(){
}
})
app.mount("#app");
</script>
这段代码是在创建一个最基本的Vue 3应用框架。就像盖房子要先搭架子一样,这里就是在搭Vue应用的架子。
-
首先用
<script>
标签引入了Vue.js文件,就像我们要用工具得先把工具箱拿来一样。这里的./vue.js
表示Vue库文件放在当前目录下。 -
然后有个
<div id="app">
的空容器,这就像在页面上划出一块地,专门给Vue应用使用,之后Vue渲染的内容都会放在这个div里面。 -
接着看到两个相似的代码块都在从Vue对象中解构出
createApp
和ref
:createApp
是用来创建Vue应用的"施工队"ref
是用来创建响应式数据的"魔法工具"(虽然这里还没用上)
-
最后用
createApp
创建了一个Vue应用实例,并调用mount("#app")
把这个应用挂载到之前准备好的那个div容器上。不过现在这个应用还是个空壳子,因为setup函数里什么都没写。
这就像你要装修房子:
- 先找来装修工具(引入Vue.js)
- 划定装修区域(准备#app容器)
- 挑选需要的工具(解构createApp和ref)
- 开始装修施工(createApp和mount)
- 不过现在还没决定具体怎么装修(setup为空)
Sconed: 打造房子
1. 标题和输入表单
<h1>ToDo-It</h1>
<form @submit.prevent="addTodo">
<input
type="text"
v-model="title"
placeholder="请输入任务"
required
>
<button type="submit">添加任务</button>
</form>
<form>
:表单用于提交新任务。 @submit.prevent="addTodo"
:当用户提交表单时,阻止默认刷新行为,并调用 addTodo
方法。
<input>
:文本输入框,绑定到 title
变量(v-model="title"
),用户在这里输入任务内容 placeholder
:提示用户输入。 required
:确保输入不能为空。
<button>
:提交按钮,点击后触发 addTodo
。
2. 显示当前输入的任务
<p v-if="title == ''">添加的任务: <strong>暂无</strong></p>
<p v-else>添加的任务:{{ title }}</p>
v-if="title == ''"
:如果 title
为空(用户还没输入),显示 "暂无" 。
v-else
:如果用户输入了内容,显示当前输入的任务({{ title }}
是上述v-model="title"
文本框的内容)。
3. 任务列表展示
<template v-if="todoList.length === 0">
{{ Loading }}
</template>
<template v-else>
<ul>
<li v-for="(todo, index) in todoList" :key="index">
{{ todo }}
<button @click="removeTodo(index)">删除</button>
</li>
</ul>
</template>
v-if="todoList.length === 0"
:
如果 todoList
是空的(还没有任务),显示 {{Loading}}
v-else
:如果 todoList
有任务,渲染一个 <ul>
列表。
v-for="(todo, index) in todoList"
:遍历 todoList
,显示每个任务 todo
和对应的索引 index
。
:key="index"
:Vue 要求列表渲染时必须提供唯一的 key
,这里用 index
作为标识。
<button @click="removeTodo(index)">删除</button>
:
每个任务旁边有个 "删除" 按钮,点击时调用 removeTodo(index)
,传入当前任务的索引,以便删除它。
重点:
{{ Loading }}
、todoList
、{{title}}
、addTodo
和 removeTodo
方法,这些需要在 Vue 的 setup()
里实现(用 ref
动态渲染)。
这个模板已经搭建好了 UI 结构,接下来只需要在 Vue 的 setup()
里补充数据和方法,就能让整个应用跑起来! 🚀
Third:装修房子
1. 定义响应式数据(ref
)
const todoList = ref([]); // 存储所有待办事项(初始为空数组)
const Loading = "Nothing to do!"; // 列表为空时的提示文字
const title = ref(""); // 绑定输入框的内容(初始为空)
todoList
:用 ref([])
创建一个响应式数组,用来存储所有的任务(比如 ["买菜", "写作业"]
)。
Loading
:只是一个普通字符串,当任务列表为空时显示(对应模板里的 {{ Loading }}
)。
title
:用 ref("")
创建一个响应式字符串,绑定到输入框(v-model="title"
),实时存储用户输入的任务内容。
2. 添加任务(addTodo
函数)
const addTodo = () => {
todoList.value.push(title.value); // 把当前输入的任务添加到列表
title.value = ""; // 清空输入框
};
当用户 提交表单(<form @submit.prevent="addTodo">
)时触发:
todoList.value.push(title.value)
:把输入的内容(title.value
)添加到 todoList
数组。
title.value = ""
:清空输入框(因为 v-model
是双向绑定的,界面也会自动更新)。
3. 删除任务(removeTodo
函数)
const removeTodo = (index) => {
todoList.value.splice(index, 1); // 根据索引删除对应任务
};
当用户点击 "删除" 按钮(@click="removeTodo(index)"
)时触发:
splice(index, 1)
:从 todoList
数组中删除指定 index
的任务(比如点击第 2 个任务的删除按钮,index
就是 1
)。
4. 返回数据和方法(return
)
return {
todoList, // 让模板能访问任务列表
Loading, // 让模板能显示加载提示
title, // 让模板能绑定输入框
addTodo, // 让表单能调用添加方法
removeTodo // 让按钮能调用删除方法
};
setup()
必须返回所有模板需要的东西,否则模板里用不了。- 这样模板里的
v-for="todo in todoList"
、@click="removeTodo(index)"
等才能正常工作。
整体流程(用户视角)
- 输入任务:在输入框打字,
title
自动更新。 - 添加任务:按回车或点按钮,触发
addTodo
,任务被添加到列表,输入框清空。 - 删除任务:点击某个任务旁边的 "删除" 按钮,触发
removeTodo
,该任务从列表中消失。
你可能想问的问题
- 为什么用
ref
?
因为 Vue 3 需要用ref
或reactive
让数据变成 响应式(数据变,界面自动更新)。 - 为什么
todoList.value.push
要用.value
?
因为ref
创建的变量是一个包装对象,真实数据存在.value
里(但在模板里不用写.value
,Vue 会自动解包)。 splice(index, 1)
是什么意思?
这是 JavaScript 的数组方法,index
表示要删除的位置,1
表示删除 1 个元素。
总结
这段代码让之前的 HTML 模板 "活" 起来了!现在这个待办事项应用可以:
✅ 添加任务
✅ 显示任务列表
✅ 删除任务
✅ 自动更新界面