0


TodoList经典案例①

文章目录

案例介绍

如下图所示:
在这里插入图片描述
有几个小细节:

  • 当所有事件都被勾选之后,下面已完成前面的框也会自动勾选
  • 只有在至少一个事件被选中之后,才会出现“清除已完成任务”的按钮在这里插入图片描述
  • 当列表中没有待办事件的时候,已完成的那一行整体都不会显示在这里插入图片描述
  • 添加的事件出现在列表的最上面

案例要求

使用前端框架Vue实现
且不使用全局事件总线、消息订阅与发布的有关知识

案例分析

首先根据组件化我们肯定是要对这个待办列表进行拆分的。当然这里有很多拆法,我推荐两种:

  • 分成三个部分:List item
  • 分成四个部分在这里插入图片描述

在这里我使用第二种方式,我们将每一个组件命名:

  • 红色部分组件 – headers.vue
  • 绿色部分组件 – tasks.vue
  • 粉色部分组件 – task.vue
  • 蓝色部分组件 – record.vue

代码实现

App组件

<template><divid="app"><Headers:addTasks="addTasks":getLength="getLength"></Headers><Tasks:tasks="tasks":updateTasks="updateTasks":deleteTask="deleteTask"></Tasks><Record:tasks="tasks":getFinished="getFinished":deleteAll="deleteAll":selectAll="selectAll"></Record></div></template><script>import Headers from'./components/headers'import Tasks from'./components/tasks'import  Record from'./components/record'exportdefault{name:'App',components:{
    Headers,
    Tasks,
    Record
  },data(){return{tasks:[{id:1,inform:'睡觉',completed:true},{id:2,inform:'吃饭',completed:false},{id:3,inform:'喝水',completed:true},//注意此处是示范数据,在实际时候删除,否则可能会报错。按照代码逻辑,如果你删除一个,再添加一个,就会出现//       两个id为3的数据,那么操作会发生混乱。//注意:这里的tasks是可以直接进行数据传递的]}},methods:{addTasks(task){this.tasks.unshift(task)
      console.log(this.tasks)},getLength(){returnthis.tasks.length
    },updateTasks(id){for(let i =0; i <this.tasks.length; i++){if(this.tasks[i].id === id){this.tasks[i].completed =!this.tasks[i].completed
        }}},getFinished(){let sum =0for(let i =0; i <this.tasks.length; i++){if(this.tasks[i].completed ==true){
          sum++}}return sum
    },deleteTask(id){this.tasks =this.tasks.filter(value=>{return value.id !== id
      })},deleteAll(){this.tasks =this.tasks.filter(value=>{return value.completed ==false})},selectAll(obj){//注意这里要讨论的是按下按钮之后的情况if(obj.checked ==true){for(let i =0; i <this.tasks.length; i++){this.tasks[i].completed =true}}else{for(let i =0; i <this.tasks.length; i++){this.tasks[i].completed =false}}},}}</script><style>#app{width: 400px;text-align: center;border-width: 2px;border-color: #eaeaea;border-style: solid;border-radius: 10px;}</style>

注意点:

  • 考虑到有几个组件可能会使用到tasks数据,所以我们把它放到这些组件的父组件App中,如此便于数据的传递
  • tasks里面有几条示范数据。在实际时候删除,否则可能会报错。按照代码逻辑,如果你删除一个,再添加一个,就会出现两个id为3的数据,那么操作会发生混乱。
  • 我们使用props来实现父组件向子组件传递数据的功能
  • 如果子组件要向父组件传递数据,我们首先要在父组件中定义一个方法,传递给子组件,再让子组件调用即可
  • 虽然使用的是data的函数式,但是这里的tasks也是可以直接使用props传递的
  • 展示不需要修改的数据直接props就行;如果要改变数据,数据在哪里方法就在哪里

headers组件

<template><inputtype="text"class="read"placeholder="按下Enter添加待办事件"@keydown.enter="addTask"v-model="task"></template><script>exportdefault{name:"MyHeader",props:['addTasks','getLength'],data(){return{task:'',}},methods:{addTask(){this.addTasks({id:this.getLength()+1,inform:this.task,completed:false})this.task=''},}}</script><stylescoped>.read{width:370px;margin-top: 20px;border: 2px solid #e3e2e2;border-radius: 10px;height: 25px;font-size: 20px;color: orange;}</style>

注意点:

  • 在输入完待办事件,按下enter添加之后,输入框要清空

tasks组件

<template><div><ulid="form"v-for="task in tasks":key="task.id"><Task:task="task":updateTasks="updateTasks":deleteTask="deleteTask"></Task></ul></div></template><script>import Task from"@/components/task";exportdefault{name:"MyTasks",props:['tasks','updateTasks','deleteTask'],components:{
            Task
        }}</script><stylescoped>#form{list-style-type: none;padding: 0px;}</style>

注意:

  • 使用了v-for的标签是不能当作根标签的,所以这里我使用div再包裹一层

task组件

<template><liclass="tasks"><inputtype="checkbox"class="select":checked="task.completed"@click="handleTask(task.id)">{{task.inform}}<buttonclass="delete"@click="deleteOne(task.id)">删除</button></li></template><script>exportdefault{name:"MyTask",props:['task','updateTasks','deleteTask'],methods:{handleTask(id){this.updateTasks(id)},deleteOne(id){this.deleteTask(id)}},}</script><stylescoped>li{text-align: left;width: 370px;margin: 0 auto;border: 2px solid #e3e2e2;height: 30px;line-height: 30px;}li:hover{background-color: #dcdcdc;visibility: visible;}li:hover .delete{visibility: visible;}.delete{height: 30px;color: white;background-color: red;border-radius: 5px;visibility: hidden;float: right;}</style>

在做这一部分的时候,难点肯定是怎么作用到具体的元素。怎么理解呢?就是说我们在点击了某一项前面的勾选框之后,我们怎么精确的修改到他的数据?通过id即可,因为我们将点击事件的回调方法放在了App组件中,所以这是一个子组件向父组件传递数据的过程,我们在父组件中定义好方法,并传递给子组件,再由子组件来调用这个方法,在调用的同时传入数据,如此就可以精准的通过id操作到对应的数据。

record组件

<template><divclass="record"v-show="tasks.length != 0"><!--        :checked="finish == tasks.length && tasks.length > 0 "  此处是为了列表删除为空之后,取消勾选--><inputtype="checkbox":checked="getFinished() == tasks.length && tasks.length > 0 "ref="checkAll"@click="selectAll($refs.checkAll)">
        已完成{{getFinished()}}/全部{{tasks.length}}
<!--        展示这种不需要改变的数据直接props就行,如果要改变数据,数据在哪里方法就在哪里--><!--        v-show里面如果你这个表达式是一个方法,那么这个方法是要带()的--><buttonclass="delete"@click="deleteAllTasks"v-show="ifShow()">清除已完成任务</button></div></template><script>exportdefault{name:"MyRecord",props:['getFinished','deleteAll','selectAll','tasks'],methods:{deleteAllTasks(){this.deleteAll()this.$refs.fuyuan.checked =false},ifShow(){for(let i =0; i <this.tasks.length; i++){if(this.tasks[i].completed ===true)returntrue}returnfalse}}}</script><stylescoped>.record{width:370px;margin:0 auto;text-align: left;height: 35px;}.delete{height: 30px;color: white;background-color: red;border-radius: 5px;/*visibility: hidden;*/float: right;}</style>

注意:

  • v-show里面如果你这个表达式是一个方法,那么这个方法是要带()的

在这里插入图片描述
此处可以不用ref来获取DOM节点,我们也可以使用点击事件对象的target属性来直接获得到这个元素,下面我介绍两种常用的在vue中获取事件对象的方法:
方法①:$event关键字(适用于事件回调函数有外来参数的时候)
在这里插入图片描述
方法②:直接写回调函数名(适用于事件回调函数没有外来参数的时候)
在这里插入图片描述

案例总结

总结TodoList案例

  1. 组件化编码流程:​ (1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。​ (2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:​ 1).一个组件在用:放在组件自身即可。​ 2). 一些组件在用:放在他们共同的父组件上(状态提升)。​ (3).实现交互:从绑定事件开始。
  2. props适用于:​ (1).父组件 ==> 子组件 通信​ (2).子组件 ==> 父组件 通信(要求父先给子一个函数)
  3. 使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!
  4. props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。

本文转载自: https://blog.csdn.net/zyb18507175502/article/details/125531951
版权归原作者 十八岁讨厌编程 所有, 如有侵权,请联系我们删除。

“TodoList经典案例①”的评论:

还没有评论