从零编写vue3系统--5步教学
案例:“Todo待办事项列表”,(功能类似:添加/删除代办、切换完成状态、统计数量)
4个核心功能:
①输入框输入待办事项,点击“添加”按钮
②每个待办事项可以标记“完成/未完成”(文字变灰并加删除线)
③每个待办事项可以删除
④实时统计“已完成数量/总数量”
步骤①:基础框架(模板+脚本+样式)
所有vue组件都有这三部分组成,奖项盖房子的“地基+墙体+装修”
<!--TodoList.vue-->
<template><!--写页面文件HTML--><div></div>
</template><script steup>//写逻辑,JavaScript</script><style scoped>/*这里写样式CSS*/</style>
步骤②:编写模板(<template>):页面结构
先把页面“骨架”搭起来,包含输入域,列表区域,统计区域
模板里面的核心语法:
1、v-model="inputText":双向绑定,输入框内容变化时,inputText变量会同步更新;反过来,inputText变化,输入框也会更新
2、v-for=“(todo,index)in todos”:循环遍历todos数组,每次循环拿到todo(当前代办对象)和Index(索引)
3、:key="index":Vue要求循环列表时必须加key,帮助Vue识别每个元素的唯一性(这里简单的用Index,实际项目推荐唯一ID)
4、:style="{textDecoration:todo.done?'line-through':'none'}":动态样式绑定
Todo.done为ture时文字加删除线(line-through),否则正常
5、@click“toggleDone(index)":事件绑定,点击时触发,toggleDone函数,并传入index(当前代办索引)
<!--TodoList.vue-->
<template><!--写页面文件HTML--><div class="todo-container"><!--容器,方便整体样式控制--><!--输入区域:输入框+按钮--><div class="input-area"><input v-model="inputText"placeholder="请输入待办事项(按回车也可添加)"@keyup.enter="addTodo"<button @click="addTodo"></button>/></div><!--代办列表区域:循环渲染待办事项--><div class="todo-list"><!--用v-for遍历todos数组,每个元素使todo对象--><div class ="todo-item"v-for="(todo,index) in todos":key="index"><span class="todo-text":style="{textDecoration:todo.done?'line-through':'none',color:todo.done?'#999':'#333'}"@click="toggleDone(index)">{{todo.text}}<!--显示代办内容--></span><!--按钮组:完成/未完成+删除--><div class ="todo-buttons"><button @click="toggleDone(index)">{{todo.done?'未完成':'完成'}}<!--按钮文字根据状态变化--></button><button @click="deleteTodo(index)" class="delete-btn">删除</button></div></div></div><!--3、统计区域:已完成/总数量--><div class ="stats">已完成:<span class ="done-count">{{doneCount}}</span>/总数量:<span class="total-count">{{todos.length}}</span></div></div>
</template>
步骤③:编写逻辑<script seyup>:数据和方法
这部分是“大脑”,定义数据、函数、控制页面交互逻辑
<script steup>//写逻辑,JavaScript//导入vue3的ref函数,用于定义响应式变量import {ref,computed}from 'vue';//定义响应式变量(数据)// inputText:绑定输入框的临时文本(用户输入的待办内容)//初始化 实例数据 done:true表示已完成 done:false表示未完成const inputText=ref([{text'学习vue的v-for语法',done:flase},{text:'掌握v-model双向绑定,done:tr'}]);//定义计算属性(根据已有数据计算新数据,又换存功能)//doneCount:已完成的代办数量(过滤出done为true的元素,统计长度const doneCount=computer(()=>{return todos.value.filter(todo=>todo.done).length;});//定义方法(函数、处理交互逻辑)//addTodo:添加待办事项const addTodo=()=>{//步骤1:先判断输入框是否为空(trim()去除收尾空格)if(inputText.value.trim()==='') {alert('请输入待办事项内容!');//为空则提示return;//终止函数,不执行后续添加逻辑}//步骤2:如果不为空,王todos数组添加新待办对象todos.value.push({text:inputText.value,//待办内容,输入框的内容done:false//新增待办默认未完成});//步骤3:清空输入框inputText.value='';};// toggleDone:切换待办事项的完成状态(点击“完成”按钮或文本时触发)const toggleDone=(index)=>{//todos是ref变量,所以要通过.value访问数组// 找到索引为 index 的待办,取反 done 的值(true → false,false → true)todos.value[index].done=!!todos.value[index].done;};// deleteTodo:删除待办事项(点击“删除”按钮时触发)const deleteTodo=(index)=>{//splice(index,1):从index位置开始删除1个元素(数组的常用删除方法todos.value.splice(index, 1);};
</script>
ref('')
:Vue3 定义“基础类型响应式变量”的方法(字符串、数字、布尔值)。变量变化时,页面会自动更新。
- 定义时:
const inputText = ref('')
(初始值为空字符串)- 使用/修改时:
inputText.value
(必须加.value
,因为 ref 包装了变量)computed(() => { ... })
:计算属性,依赖todos
数组变化时自动重新计算。比如todos
中某个done
变了,doneCount
会自动更新,页面统计数字也会变。- 方法定义:用
const 方法名 = () => { ... }
语法(箭头函数),避免 this 指向问题(Vue3<script setup>
中不常用 this)
步骤④:编写样式:美化页面
<style scoped>
/* scoped 表示样式只作用于当前组件,不污染其他组件 */
.todo-container {max-width: 600px; /* 容器最大宽度 */margin: 50px auto; /* 上下边距 50px,左右居中 */padding: 20px;font-family: Arial, sans-serif;
}.input-area {display: flex; /* 弹性布局,让输入框和按钮并排 */gap: 10px; /* 元素间距 */margin-bottom: 20px;
}.input-area input {flex: 1; /* 输入框占满剩余宽度 */padding: 10px;border: 2px solid #ddd;border-radius: 4px; /* 圆角边框 */font-size: 16px;
}.input-area button {padding: 10px 20px;background-color: #42b983; /* Vue 绿色 */color: white;border: none;border-radius: 4px;cursor: pointer; /* 鼠标悬停时显示手型 */font-size: 16px;
}.input-area button:hover {background-color: #359469; /* hover 时颜色加深(交互反馈) */
}.todo-list {margin: 20px 0;
}.todo-item {display: flex; /* 弹性布局,让文本和按钮组并排 */justify-content: space-between; /* 文本居左,按钮组居右 */align-items: center; /* 垂直居中对齐 */padding: 12px;border-bottom: 1px solid #eee; /* 下划线分隔每个待办 */
}.todo-text {font-size: 16px;cursor: pointer; /* 点击文本也能切换状态,所以加手型 */transition: color 0.3s; /* 颜色变化时的过渡动画(平滑效果) */
}.todo-buttons {display: flex;gap: 8px; /* 按钮之间的间距 */
}.todo-buttons button {padding: 6px 12px;border: none;border-radius: 4px;cursor: pointer;font-size: 14px;
}.todo-buttons button:hover {opacity: 0.8; /* 按钮 hover 时半透明 */
}.delete-btn {background-color: #ff4444; /* 删除按钮红色 */color: white;
}.stats {margin-top: 20px;font-size: 16px;color: #666;
}.done-count {color: #42b983; /* 已完成数量绿色 */font-weight: bold;
}.total-count {color: #ff9800; /* 总数量橙色 */font-weight: bold;
}
</style>
scoped
属性:避免样式冲突(比如这个组件的button
样式不会影响其他组件的按钮)。display: flex
:弹性布局,让元素横向排列(输入框和按钮并排、文本和按钮组并排)。- 交互反馈:
hover
效果、点击文本的手型光标,提升用户体验。
步骤④:再APP.vue中使用这个组件
写完TodoList.vue后,需要在跟组件中引入才能显示:
<!-- App.vue -->
<template><div id="app"><h1>Todo 待办事项列表</h1><TodoList /> <!-- 使用咱们写的 TodoList 组件 --></div>
</template><script setup>
import TodoList from './components/TodoList.vue'; // 引入组件
</script><style>
#app {text-align: center; /* 文字居中 */padding: 20px;
}
</style>
⑤、调试技巧:遇到问题怎么办
- 看浏览器控制台(按 F12 → Console 面板),如果有红色错误,根据错误提示找问题(比如“变量未定义”“函数不存在”)。
- 打印变量:在方法里用
console.log(变量名)
查看值,比如addTodo
中打印inputText.value
,看是否获取到用户输入。- 简化问题:如果某个功能不生效,先注释其他代码,只留最小化的测试代码(比如先测试
v-for
是否能渲染静态数组)。
⑥小练习:巩固知识
- 给待办事项添加“编辑”功能:点击待办文本变成输入框,修改后按回车保存。
- 添加“清空已完成”按钮:删除所有
done: true
的待办事项。- 按“是否完成”排序:已完成的待办显示在底部(提示:用
sort
方法)。