【Vue】 实现TodoList案例(待办事项)
目录
组件化编码流程(通用)
1.实现静态组件:抽取组件,使用组件实现静态页面效果
2.展示动态数据:
1. 常规 HTML 属性
3.交互——从绑定事件监听开始
什么时候要用 event:
什么时候不需要用 event:
总结TodoList案例
总结不易!本章节对我有很大的收获, 希望对你也有帮助!!!
本节文件素材自取:https://gitee.com/liu-yihao-hhh/i-love---vue/tree/master/vue-06/src
组件化编码流程(通用)
1.实现静态组件:抽取组件,使用组件实现静态页面效果





2.展示动态数据:
- 数据的类型、名称是什么?
- 数据保存在哪个组件?

实际上是写成 v-for = "(title, index) in todos"
传入值给MyItem 进行值的接收~ 打印这里的生命周期钩子中todo对象
v-bind就是得到Vue里面的值 然后进行传给html标签里面的属性值使用!
1. 常规 HTML 属性
-
href
: 链接的 URL -
src
: 图像、视频或其他资源的来源 -
alt
: 图像的替代文本 -
title
: 元素的提示信息 -
disabled
: 控制按钮、输入框等元素的禁用状态 -
readonly
: 使输入框成为只读 -
checked
: 复选框或单选框的选中状态 -
value
: 表单控件的值 -
placeholder
: 表单控件的占位符文本 -
maxlength
: 输入框允许的最大字符数 -
type
: 表单控件的类型,如text
、password
、checkbox
等
就好比 给img :src=“”图片传入地址
3.交互——从绑定事件监听开始
-
@keyup
是v-on:keyup
的简写,它用于监听keyup
事件。keyup
事件会在用户松开按键时触发。 -
.enter
是一个修饰符,它限制只在用户按下 Enter 键 时触发事件。也就是说,只有当用户按下 Enter 键并松开时,才会触发add
方法。 -
add
是你在 Vue 组件中定义的方法,当这个事件触发时,Vue 会调用add
方法。
这里有两种办法来接受输入框的数据:
1. 给这个add函数来进行添加
-
event
是触发keyup
事件时,浏览器传递给事件处理函数的原生 DOM 事件对象。 -
event.target
是触发事件的元素(即<input>
输入框)。 -
event.target.value
获取的是这个输入框的当前值,也就是用户输入的内容。
什么时候要用 event
:
-
你需要获取触发事件的元素(比如按钮、输入框等): 比如你点击了一个按钮,想知道是哪个按钮触发了事件,或者想获取这个按钮的某个属性(比如按钮的文本、值等)。这时需要
event.target
来拿到这个元素。
<button @click="handleClick">Click me</button>methods: {handleClick(event) {console.log(event.target); // 这里你就可以得到触发点击的那个按钮元素}
}
你需要获取更多的事件信息: 比如你按了某个键,想知道是哪个键被按下。你需要 event.key
来获取按下的键的名字(例如 "Enter"
,"Escape"
等)。
<input type="text" @keyup="handleKeyup">methods: {handleKeyup(event) {console.log(event.key); // 输出你按下的键名}
}
你需要阻止事件的默认行为: 比如你点击了一个提交按钮,但你不想让它立即提交表单,而是执行其他的操作。你可以使用 event.preventDefault()
来阻止表单的提交。
<form @submit="handleSubmit"><button type="submit">Submit</button>
</form>methods: {handleSubmit(event) {event.preventDefault(); // 阻止表单提交console.log("表单没有提交");}
}
你需要停止事件冒泡: 有时候你点击某个元素时,可能不希望事件传播到父元素(例如,你点击了按钮,但父元素的点击事件也不想被触发)。这时你可以使用 event.stopPropagation()
来停止事件的传播。
<div @click="handleDivClick"><button @click="handleClick">Click me</button>
</div>methods: {handleDivClick() {console.log("Div clicked");},handleClick(event) {event.stopPropagation(); // 阻止事件冒泡,不让父 div 的点击事件触发console.log("Button clicked");}
}
什么时候不需要用 event
:
-
如果你不需要获取事件的具体信息(比如你只是希望某个方法被执行),就不需要用
event
。比如你用 Vue 的@click
,然后直接调用一个方法,没有涉及到原生事件信息的处理时,就不需要传event
。
2. 采用v-modle进行双向数据绑定,来直接获取输入的title值
v-model="title"
:实现了输入框的值与title
数据的双向绑定。
为了生成一个绝对不会重复的id号, 这里就推荐一个nanoid库进行生成唯一的id
安装好nanoid库后,直接进行引入:然后打印出输入的对象看看效果!
由于我们现在数据在MyHeader上 需要将数据传入到MyList内才能将数据进行渲染,但是我们现在实现不了兄弟组件之间的互传,就比如上面之前的List组件传至item组件, 它们之间的关系就是父子组件的关系, List引入了item组件,所以才可以通过props进行传输数据!
这里我们只能先将header数据传入App 然后 才从App传入至List的方法可行!!!
1. 先实现比较简单的这条线,将数据从App组件传向List就是用props即可,将todos数组放入App组件,进行传输:
App组件:
List获取App组件传来的todos 然后再传给item单个事件进行渲染:
2.第二条线就是, 要将Header输入框的值传送给App组件!
然后就只需要将receive名字换成addTodo 并且获得的todoObj进行unshift数组todos即可!
Header组件进行数据检验!
if(!event.target.value.trim()) return alert('输入不能为空')
export default {name: 'MyHeader',props:['addTodo'],methods: {add(event) {// 检验数据if(!event.target.value.trim()) return alert('输入不能为空')// 将用户的输入包装成一个todo对象// console.log(event.target.value)const todoObj = {id:nanoid(), title: event.target.value, done:false}// console.log(todoObj)// 通知App组件添加一个todoObj对象this.addTodo(todoObj)event.target.value = ''}}
}
当我想要改变当前标签值的done时, 首先第一步就是要获得该事件的id号!再Item组件中~
那么仍然再App组件内进行定义函数:来进行勾选或取消勾选当前事件,得到该id后 将当前事件的done进行反转!
那么就要将该函数进行传递至item组件内, 就要进行连续传递两次
item勾选or取消勾选的另一种方法!直接利用v-model的双向数据绑定, 来获取props传来的数组todo.done来控制当前的checkbox的勾选效果!
但是这里有一个很明显的冲突:
这里的todo.done 是props传进来的 是只读的 但是这里却被修改了
- 但是Vue的监测比较宽松,比如:let obj = {a: 1, b: 2}
- obj.a = 666 这种只修改属性值, Vue是监测不到的
- obj = {x: 100, y: 200} 这种修改整个对象 才是Vue能够监测到的
所以强烈不建议这种写法,还是不要直接对props进行修改的好~
定义删除item任务, 跟勾选是用养一个效果, 再App组件内进行创建deleteTodo函数 然后进行传递给item组件中!
Footer计算任务:
Footer组件要接收App传入的todos 然后来计算当前的全部任务和已完成任务数!
<span>已完成{{ doneTotal }}</span> / 全部{{ todos.length }}
export default {name:'MyFooter',props:['todos'],// 计算属性 因为我们要计算已完成的任务数computed: {// 简写 写成函数形式doneTotal() {// 写法不高级// let i = 0// this.todos.forEach(todo => {if(todo.done) i++})// return i// 第一个参数就是一个函数 第二个参数 用来做统计的初始值 就像是定义 i = 0// 数组的长度是几 这个函数就被调用几次// pre 就是上一次的值, current就是当前的值// 返回值就是下一次执行这个函数的pre来进行接收// 最后一次调用函数的返回值就是整个reduce方法的返回值// current就是每一个todo对象 就是数组里面的下标为pre当前内容// const x = this.todos.reduce((pre, current) => {// return pre + (current.done ? 1 : 0)// }, 0)// return xreturn this.todos.reduce((pre, todo) => pre + (todo.done ? 1 : 0), 0)}}
}
计算已完成任务数,这里用到了reduce这个数组内置函数,用来进行筛选计算作用,那么就要放入计算函数内部进行返回!
reduce()
方法对数组中的每个元素按序执行一个提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。
全部勾选 or 全部不勾选按钮 以及 清除已经完成的任务
Footer的input checkbox复选框:
但是这里input 又采用:checkbox 进行获取isAll的值 还进行@click进行点击事件 所以二者可以进行合并为v-model= "isAll"
正常流程是:
get()
→ 用户修改 →set(value)
→ 响应式数据变了 → 自动触发get()
→ 页面刷新
清除已完成任务:
本节文件素材自取:https://gitee.com/liu-yihao-hhh/i-love---vue/tree/master/vue-06/src
总结TodoList案例
-
组件化编码流程:
(1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
(2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:
1).一个组件在用:放在组件自身即可。
2). 一些组件在用:放在他们共同的父组件上(<span style="color:red">状态提升</span>)。
(3).实现交互:从绑定事件开始。
-
props适用于:
(1).父组件 ==> 子组件 通信
(2).子组件 ==> 父组件 通信(要求父先给子一个函数)
-
使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!
-
props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。