Vue(七) TodoList案例1.0

news2024/11/13 9:26:26

文章目录

  • 组件化编码流程(通用)
  • 1. 拆分静态组件
  • 2. 初始化列表
    • 展示动态数据
    • 如何让一个标签动态的拥有某一个属性
  • 3. 按回车添加todo
    • 子组件给父组件传值之props
  • 4. 勾选与取消勾选一个Todo
  • 5. 删除
  • 6. footer底部统计
  • 7. footer底部交互
    • 7.1 全选框自动打勾
    • 7.2 全选框取消勾选
  • 8. 清除已完成任务
  • 总结

组件化编码流程(通用)

1、实现静态组件:抽取组件,使用组件实现静态页面效果

2、展示动态数据:

  • 数据的类型、名称是什么
  • 数据保存再哪个组件

3、交互–从绑定事件监听开始

如果组件名字不好起,想一下是不是组件拆分的不合理

1. 拆分静态组件

根据功能,可划分为以下几个组件:
在这里插入图片描述
将已写好页面的html,css根据组件进行拆分,得到的文件结构如下:
App组件里使用了MyHeader、MyList、MyFooter组件
在这里插入图片描述
MyList组件里使用了MyItem组件:
在这里插入图片描述

2. 初始化列表

展示动态数据

(1) 确定数据名称、数据类型
数据名称:这一堆的代办事项数据名称可以叫todos,
数据类型:最好用数组存储这一堆的待办事项,而每一个代办事项可以用对象存储。

(2) 数据保存在哪个组件:
谁用这些数据,就写在哪个组件里后续如果有变化,再改变位置。因此暂时写在MyList组件里。
MyList.vue

<template>
  <ul class="todo-main">
   <!-- 循环生成多个MyItem,且将具体的代办事项传递给MyItem,否则还是页面的列表里还是yyyy-->
    <MyItem v-for="toboObj in todos" :key="toboObj.id" :todo="toboObj" />
  </ul>
</template>
<script>
...
  data () {
    return {
      todos: [
        { id: '0001', title: '吃饭', done: true },
        { id: '0002', title: '睡觉', done: true },
        { id: '0003', title: '打豆豆', done: false }]
    }
  }
</script>

MyItem.vue

<template>
  <li>
    <label>
      <!-- 添加checked属性,初始化复选框的数据 -->
      <input type="checkbox" checked />
      <span>{{ todo.title }}</span>
    </label>
    <button class="btn btn-danger" style="display: none">删除</button>
  </li>
</template>

<script>
export default {
  name: 'MyItem',
  // 接收MyList组件传递的对象
  props: ["todo"]
}
</script>

但是添加checked后,所有的复选框都被勾选了。

如何让一个标签动态的拥有某一个属性

答:v-bind动态绑定

  <input type="checkbox" :checked="todo.done" />

在这里插入图片描述

3. 按回车添加todo

输入框在Header组件中,因此Header组件中要添加点击事件

<template>
  <div class="todo-header">
    <!-- v-model获取表单元素的值 -->
    <input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keydown.enter="add"/>
  </div>
</template>

add回调函数中要做以下几件事:

import { nanoid } from 'nanoid'
methods: {
    add () {
        // 1. 获取到表单元素的内容
        console.log(this.title); // 或者通过 e.target.value获取到输入框的内容
        // 2. 将用户的输入包装成一个todo对象
        const todoObj = { id: nanoid(), title: this.title, done: false }  
        // 3. 将todo对象添加到todo列表里,即todos数组中
        // 4. 输入框内容置空。
        this.title = '' // 或者 e.target.value = '' 
    }
}
  • nanoid
    包装的对象应该有一个唯一的id,uuid这个库可以生成全球唯一的编码,但是太大且生成的编码复杂。采用uuid的精简版:nanoid

    安装npm i nanoid
    引用 import {nanoid} from 'nanoid'
    使用: nanoid()(这是个函数,直接调用即可)

  • todoObj在MyHeader组件里,而数据todos在MyList组件里。两组件为兄弟组件,目前还不会兄弟组件之间通信。所以还是采用props属性。
    为了方便MyHeader通信,将todos改放在App组件里,而不是MyList组件里。此时:
    在这里插入图片描述

App可通过props将todos交给MyList组件进行展示。MyHeader该如何将todoObj交给父组件App呢?

子组件给父组件传值之props

父组件给子组件传递带参的函数

<!--App.vue-->
<template>
    ...
    <!-- 给子组件传函数 -->
    <MyHeader :addTodo="addTodo"></MyHeader>
    <!-- 给子组件传数据 -->
    <MyList :todos="todos"></MyList>
    <MyFooter></MyFooter>
    ...
</template>
<script>
  methods: {
    // 添加todoObj
    addTodo (todoObj) {
      this.todos.unshift(todoObj)
    }
  }
}
</script>

子组件接收函数

<!--MyHeader.vue-->
<script>
  props: ["addTodo"],
  methods: {
    add () {
      //完善一下:校验数据
      if (!this.title.trim()) return alert('输入不能为空')
      const todoObj = { id: nanoid(), title: this.title, done: false }
      // 调用函数,通过参数将todoObj传递给父组件
      this.addTodo(todoObj)
      this.title = ''
    }
  }
}
</script>

总结:子组件向父组件传值时,父组件需提前向子组件传递一个带参的函数,子组件通过函数的参数将数据传给父组件。

捋顺一下流程:
1、按下回车,执行MyHeader里的add函数,在add里调用了App组件里的addTodo函数。
2、addTodo函数修改了App组件中data里的todos数据。
3、Vue捕获到todos变了,于是重新解析App里的template模板,重新解析时,将变化后的todos交给了MyList组件。
4、MyList收到数据,重新解析自己组件内的模板,v-for,虚拟DOM对比,更新页面。

4. 勾选与取消勾选一个Todo

在这里插入图片描述

MyItem.vue添加change事件(@click也可以)

  <input  type="checkbox"  :checked="todo.done" @change="handleCheck(todo.id)" />

handleCheck事件里需要对todos数据进行修改。数据在App组件里, 数据在哪里,操作数据的方法就在哪里,所以这里需要把待修改的todo的id传递给App。子组件给父组件传值,父组件需要先传递一个带参函数。此处应该是App传给MyList,MyList再传递给MyItem。

App.vue

<template>
...
    <!-- 先将函数传递给MyList -->
    <MyList :todos="todos" :checkTodo="checkTodo"></MyList>
...
<script>
    // 勾选or取消勾选一个todo
    checkTodo (id) {
        this.todos.forEach((todo) => {
            if (todo.id === id) {
                todo.done = !todo.done
            }
        })
    }
</script>

MyList.vue

  <MyItem   v-for="toboObj in todos" :key="toboObj.id" :todo="toboObj"  :checkTodo="checkTodo" />
<script>
  props: ["todos", "checkTodo"]
</script>

MyItem.vue

// 接收MyList组件传递的对象
props: ["todo", "checkTodo"],
    methods: {
        handleCheck (id) {
            this.checkTodo(id)
    }
}

需要注意的是:
:checked="todo.done" ----初始化复选框
@change="handleCheck(todo.id) ----更新复选框
这两个操作可用v-model进行合并

<!-- 这行代码也能实现,但是有点儿违反原则,因为这样修改了props里数据的值,不报错是因为,todo是个对象,地址值没被修改, --> 
<input type="checkbox" v-model="todo.done" />

5. 删除

在这里插入图片描述
点击按钮,获取当前MyItem的id,根据id删除该条数据。同样的套路

添加监听事件,监听事件里调用父组件传递过来的函数。通过父组件里的这个函数对todos进行删除操作。
App.vue:

<MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"></MyList>
<script>
    // 删除一个todo
    deleteTodo (id) {
        this.todos = this.todos.filter((todo) => {
            return todo.id !== id
        })
    }
</script>

MyList.vue:

<MyItem
v-for="toboObj in todos"
:key="toboObj.id"
:todo="toboObj"
:checkTodo="checkTodo"
:deleteTodo="deleteTodo"
/>
<script>
    props: ["todos", "checkTodo", "deleteTodo"]
</script>

MyItem.vue:

<button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
<script>
    // 处理删除
    handleDelete (id) {
      // 通知App,删除对应的todo
      this.deleteTodo(id)
    }
</script>

6. footer底部统计

在这里插入图片描述

<!--Footer.vue--> 
<!--使用计算属性--> 
<span>已完成{{ doneTotal }}</span> / 全部{{ total }}
<script>
  props: ["todos"],
  computed: {
    total () {
      return this.todos.length
    },
    doneTotal () {
        // reduce记数
      return this.todos.reduce((prev, cur) => {
        return prev + (cur.done ? 1 : 0)
      }, 0)
      // 简写
      // return this.todos.reduce((prev, current) => prev + (current.done ? 1 : 0))
    }
</script>

7. footer底部交互

这里结合6底部统计一起看

7.1 全选框自动打勾

如果代办事项全都选上,则该框自动打勾,
在这里插入图片描述

<input type="checkbox" :checked="isAll" @change="checkAll" />
<script>
  computed: {
    isAll () {
      // 已完成的数量是否等于todos的总数
      return this.doneTotal === this.total
    }
  },
</script>  

但是这样有个问题:
在这里插入图片描述
改进:

isAll () {
    return this.doneTotal === this.total && this.total > 0
}

优化:当没有代办事项时,footer组件不应该显示
在这里插入图片描述

7.2 全选框取消勾选

方式一:添加点击事件
App组件中创建操作todos的函数并传递给子组件
在这里插入图片描述
子组件接收函数并调用
在这里插入图片描述
方式二:v-model

<!-- :check = "isAll"用于初始化复选框
@change="checkAll"用来更新复选框
-->
<input type="checkbox" :checked="isAll" @change="checkAll" />
<!-- 简写为 -->
<input type="checkbox" v-model="isAll" />

由于isAll是计算属性,且v-model是双向绑定,所以当操作复选框时,对isAll的值进行了修改;
在这里插入图片描述
所以此时isAll不能采用简写形式了

isAll: {
    get () {
        return this.doneTotal === this.total && this.total > 0
    },
    set (value) {
        this.checkAllTodo(value)
   }
}

8. 清除已完成任务

在这里插入图片描述

添加点击事件
MyFooter.vue

<button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
<script>
props: ["todos", "checkAllTodo", "clearAllTodo"],
clearAll () {
    this.clearAllTodo()
}
</script>

App.vue

<MyFooter
    :todos="todos"
    :checkAllTodo="checkAllTodo"
    :clearAllTodo="clearAllTodo"
></MyFooter>
<script>
// 清除所有已完成的todo
    clearAllTodo () {
      this.todos = this.todos.filter((todo) => {
        return !todo.done
      })
    }
</script>

总结

  1. 组件化编码流程:

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

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

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

    ​ 2). 一些组件在用:放在他们共同的父组件上(状态提升)。

    ​ (3).实现交互:从绑定事件开始。数据在哪里,对数据进行处理的方法就在哪里

  2. props适用于:

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

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

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

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

  5. 7.2节很好的体现了计算属性set方法的用途

项目完整代码链接:https://gitee.com/LXHST/vue2–Todo-list-case-1.0/tree/master/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2091692.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【java】vscode配置javaweb开发环境

下载jdk https://www.oracle.com/java/technologies/downloads/?er221886下载完毕直接安装&#xff0c;安装完毕自动添加以下环境变量 在cmd中运行 java -version出现以下代表成功 再添加系统变量 下载Maven https://maven.apache.org/download.cgi下载完解压放到自己方…

win10环境下gvim离线配置插件的一些补充

0 总述 在上一篇博客&#xff0c;即《Windows系统下使用gvim配置LaTeX快速书写环境》一文中&#xff0c;本小白试图模仿神级人物Gilles Castel&#xff0c;打造vim下的 LaTeX \LaTeX LATE​X书写环境。实话实说&#xff0c;东施效颦了。虽不至于一无所得&#xff0c;但也仅仅算…

STM32通过ADM3222完成UART转232通信电平转换

1、简介 单片机默认串口输出电平是UART信号,但是在实际项目中经常需要将其转换成232电平,此时就需要ADM3222芯片来完成电平的转换,下面对使用过程进行总结。 2、硬件电路 从上图中可以看到芯片需要对1、18进行配置才能进行工作,通过查阅手册可知,1引脚需要配置低电平,…

生物信息学:DNA序列的构成

DNA序列是由一串字母表示的真实的或者假设的携带基因信息的DNA分子的一级结构。‌ DNA序列的构成基于四种特定的碱基&#xff0c;分别是腺嘌呤&#xff08;A&#xff09;、胸腺嘧啶&#xff08;T&#xff09;、鸟嘌呤&#xff08;G&#xff09;和胞嘧啶&#xff08;C&#xff…

【机器学习】K近邻(K-Nearest Neighbors,简称KNN)的基本概念以及消极方法和积极方法的区别

引言 K近邻&#xff08;K-Nearest Neighbors&#xff0c;简称KNN&#xff09;算法是一种基础的机器学习方法&#xff0c;属于监督学习范畴 文章目录 引言一、K近邻&#xff08;K-Nearest Neighbors&#xff0c;简称KNN&#xff09;1.1 原理详述1.1.1 距离度量1.1.2 选择k值1.1.…

django网吧收费管理系统 项目源码26819

摘 要 随着互联网的普及&#xff0c;网吧作为公共互联网接入场所&#xff0c;依旧在许多地区发挥着重要作用。现代网吧不仅仅是提供上网服务的场所&#xff0c;还包括了游戏、社交、休闲等多功能体验。为了提高网吧的服务质量和运营效率&#xff0c;迫切需要一个高效的管理系统…

采集工具选型调研

原文阅读&#xff1a;【巨人肩膀社区博客分享】采集工具选型调研 大家一起来探讨SeaTunnel方案&#xff0c;简化当前Dinky与chunjun的双轨模式&#xff08;Dinky仅用于实时同步&#xff0c;chunjun负责离线处理&#xff09;。提议小组一起共议&#xff0c;并由大数据组构建dem…

大模型battle,哪家才是真的“价美”也“物美”

大模型battle&#xff0c;哪家才是真的“价美”也“物美” 物美价廉何为物美价廉大模型battle基础能力测试&#xff1a;专业能力测试&#xff1a;中文特性能力测试&#xff1a;逻辑推理能力测试&#xff1a;创新能力测试&#xff1a;安全性与合规性测试&#xff1a;写在最后 近…

【Qt窗口】—— 对话框

目录 &#xff08;一&#xff09; 对话框介绍 &#xff08;二&#xff09;对话框的分类 2.1 模态对话框 2.2 非模态对话框 2.3 混合属性对话框 &#xff08;三&#xff09;内置对话框 消息对话框 QMessageBox 颜色对话框 QColorDialog 字体对话框 QFontDialog 输入对…

RK3588 系列之1—串口连接

RK3588 系列之1—串口连接 1.串口转USB芯片驱动2.使用MobaXterm进行串口链接3.注意事项 1.串口转USB芯片驱动 根据使用的芯片安装不同的驱动&#xff0c;常见的如CH340。装完驱动后&#xff0c;通过设备管理器&#xff0c;查看开发板与个人PC连接情况&#xff0c;记住占用的端…

超声波智能水表通讯方式有哪些?

超声波智能水表采用多种通讯方式实现数据传输&#xff0c;包括但不限于有线连接、无线网络、以及短距离无线通信技术&#xff0c;这些方式各有优劣&#xff0c;适用于不同的应用场景。 一、通讯方式概述 1.有线通讯 -RS-485接口&#xff1a;这是一种半双工的串行通信接口标准…

微服务框架二

微服务 微服务技术栈 服务发现概念 服务发现两种方式 客户端发现 服务端服务发现 服务发现技术对比 Nacos架构图 基于dubbo nacos服务调用 Nacos核心源码解析 registery 具体实现在nacosServiceRegistery setbeat 返回clientBeatInterval

cannot import name ‘greycomatrix‘ from ‘skimage.feature.texture‘ 解决方法

症状&#xff1a; ImportError: cannot import name ‘greycomatrix’ from ‘skimage.feature’ (D:\ProgramData\anaconda3\Lib\site-packages\skimage\feature_init_.py) 解决方案 将涉及的grey全部替换为gray即可

黑神话·悟空亢金龙怎么打?亢金龙全攻略

走到湖心庙宇&#xff0c;长得像弥勒缩小版的小和尚出现了。 他为师为师的叫着&#xff0c;似乎还想收天命人为徒&#xff0c;跟着他修行似得。 不过&#xff0c;他身上的乾坤袋出卖了自己&#xff0c;不是黄眉大仙是谁? 不知为何&#xff0c;曾经从金铙里救出悟空的亢金龙居…

Minkowski分形电路生成工具[程序附后]

此工具用于生成Minkowski分形电路&#xff0c;应用领域可参考分形电路的纪录片或CNKI论文。运行环境在Altium Designer中&#xff0c;可用于Altium Designer全系列的版本中。 程序界面如下图所示&#xff0c;可以支持外框和迭代次数的更改。 程序下载链接&#xff1a; Minkows…

加载:loader实现

1、利用内联汇编显示字符串 通过反复调用BIOS显示字符的方式来显示一个完整的字符串&#xff0c;该功能将用于loader在初始化过程中显示初始化进度、错误信息。 具体代码 // 16位代码&#xff0c;必须加上放在开头&#xff0c;以便有些io指令生成为32位 __asm__(".code…

STM32外设SPI(串行通信),W25Q64(8Mb)

1 非易失存储器:E2PROM,FLASH(断电不丢失) 2 易失存储器&#xff1a;SRAM,DRAM 3 W25Q64 1 从00 00 00 到 7F FF FF 2 block(块)&#xff0c;sector(扇区) &#xff0c;page&#xff08;页区&#xff09; 写数据到FLASH&#xff08;256字节&#xff09; 读数据很快&#…

002.Python爬虫系列_初识协议

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

论文学习哇

2024.7.18 1.A gated cross-domain collaborative network for underwater object detection 对图像进行增强 摘要&#xff1a;水下存在低对比度和低光的问题&#xff0c;有的学者通过水下图像增强来提高图片质量&#xff0c;但会移除或者改变水下物体的细节。所以作者探索两…

【Android】使用 ADB 查看 Android 设备的 CPU 使用率

目录 一 查看整体CPU使用率 1 top 二 查看特定应用的CPU使用率 1 获取特定应用的进程 ID (PID) 2 使用 top 命令并过滤该 PID 三 常见的CPU相关命令参数 1 adb shell top 参数 一 查看整体CPU使用率 1 top top命令将显示当前所有进程的 CPU 使用情况&#xff0c;包括每…