当前位置: 首页 > news >正文

【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.实现静态组件:抽取组件,使用组件实现静态页面效果

第一步,进行拆分组件!
首先定义好各个组件的名称,然后分别进行引入和注册
App组件
Item组件属于List的子组件,单独进行引入和注册
这里有当前模块化的html和css直接进行引入, 然后通过 自己拆分,来分别引入组件即可!
现在就定义好了一个静态的组件!

2.展示动态数据:

  • 数据的类型、名称是什么?
  • 数据保存在哪个组件?
在MyList中存在一堆待处理的事情的时候,我们肯定就是用数组对象来进行存储,每一个都具有当前标签的id号,内容title和是否完成done
进行渲染的时候,可以用我们之前学到的v-for = " todoObj in todos" 注意绑定:key=“todoObj.id”值
实际上是写成 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: 表单控件的类型,如 textpasswordcheckbox

就好比 给img :src=“”图片传入地址

    3.交互——从绑定事件监听开始

    在MyHeader.vue中,进行事件添加, 每次按下回车,都会添加一条新的todo任务

    • @keyupv-on:keyup 的简写,它用于监听 keyup 事件。keyup 事件会在用户松开按键时触发。

    • .enter 是一个修饰符,它限制只在用户按下 Enter 键 时触发事件。也就是说,只有当用户按下 Enter 键并松开时,才会触发 add 方法。

    • add 是你在 Vue 组件中定义的方法,当这个事件触发时,Vue 会调用 add 方法。

    这里有两种办法来接受输入框的数据:

    1. 给这个add函数来进行添加

    • event 是触发 keyup 事件时,浏览器传递给事件处理函数的原生 DOM 事件对象。

    • event.target 是触发事件的元素(即 <input> 输入框)。

    • event.target.value 获取的是这个输入框的当前值,也就是用户输入的内容。

    什么时候要用 event

    1. 你需要获取触发事件的元素(比如按钮、输入框等): 比如你点击了一个按钮,想知道是哪个按钮触发了事件,或者想获取这个按钮的某个属性(比如按钮的文本、值等)。这时需要 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传进来的 是只读的 但是这里却被修改了

    1.      但是Vue的监测比较宽松,比如:let obj = {a: 1, b: 2}
    2.      obj.a = 666 这种只修改属性值, Vue是监测不到的
    3.      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. 组件化编码流程:

      ​ (1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。

      ​ (2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:

      ​ 1).一个组件在用:放在组件自身即可。

      ​ 2). 一些组件在用:放在他们共同的父组件上(<span style="color:red">状态提升</span>)。

      ​ (3).实现交互:从绑定事件开始。

    2. props适用于:

      ​ (1).父组件 ==> 子组件 通信

      ​ (2).子组件 ==> 父组件 通信(要求父先给子一个函数)

    1. 使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!

    2. props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。

    总结不易!本章节对我有很大的收获, 希望对你也有帮助!!!

    相关文章:

  • 赛事季突围!备战2025全国信息素养大赛 python挑战赛~
  • 流量控制机制
  • 基于 Windows I/O 完成端口(IOCP)的多线程任务队列系统小case
  • 鬼泣:motion warping 总结
  • 通过漂移-扩散仿真研究钙钛矿-硅叠层太阳能电池中的电流匹配和滞后行为
  • 企业选择IT技术人员外包能解决哪些问题
  • Qwen多模态系列论文
  • Qwen3快速部署 Qwen3-0.6B、Qwen3-8B、Qwen3-14B,Think Deeper
  • 制作JDK17 arm64基础镜像,解决字体安装问题
  • Fiddler抓取APP端,HTTPS报错全解析及解决方案(一篇解决常见问题)
  • 混淆矩阵(Confusion Matrix);归一化混淆矩阵(Confusion Matrix Normalized)
  • 《AI大模型应知应会100篇》【精华】第40篇:长文本处理技巧:克服大模型的上下文长度限制
  • 制作一款打飞机游戏33:碰撞体编辑
  • 推荐系统实验指标置信度:p值核心原理与工程应用指南
  • 李录谈卖出股票的时机:价值投资的动态决策框架
  • centos6.7安装完python3 找不到python3命令
  • DES与AES算法深度解析:原理、流程与实现细节
  • 【Yolo精读+实践+魔改系列】Yolov2论文超详细精讲(翻译+笔记)
  • 深度学习·经典模型·SwinTransformer
  • C语言教程(二十三):C 语言强制类型转换详解
  • 国铁集团郑州局预计“五一”发送642.5万人
  • “女乘客遭顺风车深夜丢高速服务区”续:滴滴永久封禁两名涉事司机账号
  • 建行一季度净利833.51亿同比下降3.99%,营收降5.4%
  • 习近平对辽宁辽阳市白塔区一饭店火灾事故作出重要指示
  • 王毅:为改革完善全球治理作出金砖贡献
  • 阿里千问3系列发布并开源:称成本大幅下降,性能超越DeepSeek-R1