vue todolist案例

1 拆分组件

一共拆分为4个组件

  • TodoHeader

  • TodoItem

  • TodoList

  • TodoFooter

item是list的子组件

2 组件化编码流程

  1. 实现静态组件:抽取组件,只考虑结构和样式

    先拆结构再拆样式

  2. 展示动态数据

使用数组对象来保存数据[{},{},{}]

每一个对象的{

id:

name:

ok:

}

谁展示对象,就保存在哪个组件,这里保存在list里面

3 交互-添加一个todo

  • 将要添加的todo包装成一个对象

  • 需要把header中的todoObj添加到list上

问题:现知识无法实现,因为header和list没有父子关系,是兄弟关系

解决方法(初级):

  • 将todos[]放在app中,通过props去传递

  • 在将todo传递给header(子级给父级传)

    • 提前在app里提前准备好methods,设置接收方法receive()

    • 把receive()交给header 【app是父亲可以给孩子传函数(方法),数组,字符串,布尔值…都行】

    • 然后在header中使用props接收receive,此时receive出现在header组件的实例vc上,模板就可以直接用

静态数组不能重名–>addTodo 不可以写成add

组件间通信

父亲给儿子传 儿子给父亲传

4 交互-todos勾选

实现勾选操作数据也会发生变化

思路:拿到勾选框的id,再到todos里找到勾选的todo,将done值取反

  • 给勾选框绑定change()事件

数据再哪里,对数据的操作就写在哪里

todos在App组件中,所以对todos的增删改查都应写在app组件中

  • 在app中写checkTodo(id)方法

    • 此时是app爷爷向item孙子传

  • 一步一步逐层传递
<!-- :checked="true" 如果后面属性是true就勾选 --><!-- 如下代码也能实现功能,但不太推荐,因为有点违反原则,修改了props --><inputtype="checkbox"v-model="todo.done"/>

v-model绑定的是布尔值,输入框是checkbox,那么这个布尔值可以确定checkbox勾或者不勾

因为传入的todo是通过props,props只读不可以修改(栈里面的地址没变,变的是堆里面存的数据),vue监测的是引用地址,只要地址不变,就没修改

使用v-model更改数据是藏在对象中改,vue检测不到

所以v-model不建议使用props传入的数据

5 交互-todos删除

  • 点击删除按钮,拿到按钮的id

  • todos在App中,所以在item中要通知App删除对象

  • 在App中写删除方法deleteTodo()

  • 爷传孙,先给list,在list给item

6 交互-todos底部统计

  • todos的长度就是全部的数量

  • 在遍历todos中done值为真的todo

统计已完成的事项

方法一:遍历

  let i = 0;this.todos.forEach((todo) => {if (todo.done) i++;});return i;

方法二:reduce()

 const x = this.todos.reduce((pre, current) => {console.log("@", pre, current);return pre + (current.done ? 1 : 0);}, 0);
 return this.todos.reduce((pre, todo) => pre + (todo.done ? 1 : 0), 0);

7 交互-todos底部统计

  • 拿到已完成的事项与总计事项作比较,相等且总数事项>0 ,勾选已完成勾选框

  • 一个计算属性可以通过其他计算属性再进行计算

  • 当页面没有展示的todos时,隐藏footer,使用v-show='total’判断total的布尔值

  • 点击已完成勾选框,事项都勾选,到App中写全选和全不选的方法

红色:初始化展示,绿色:交互

可以使用v-model,使用getter和setter完整的写法

<input type="checkbox" v-model="isAll" />
isAll: {//全选框是否勾选get() {return this.doneTotal === this.total && this.total > 0;},//isAll被修改时set被调用set(value) {this.checkAllTodo(value);},},
  • 清除已完成

总结TodoList案例

  1. 组件化编码流程:

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

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

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

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

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

  1. props适用于:

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

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

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

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

实例代码

app.vue

<template><div id="root"><div class="todo-container"><div class="todo-wrap"><todo-header :addTodo="addTodo"></todo-header><todo-list:todos="todos":checkTodo="checkTodo":deleteTodo="deleteTodo"></todo-list><todo-footer:todos="todos":checkAllTodo="checkAllTodo":clearDoneTodo="clearDoneTodo"></todo-footer></div></div></div>
</template><script>
// 引入
import TodoHeader from "./components/TodoHeader.vue";
import TodoList from "./components/TodoList.vue";
import TodoFooter from "./components/TodoFooter.vue";// 注册
export default {name: "App",components: {TodoHeader,TodoList,TodoFooter,},data() {return {//由于todos是MyHeader组件和MyFooter组件都在使用,所以放在App中(状态提升)todos: [{ id: "001", title: "吃饭", done: true },{ id: "002", title: "睡觉", done: false },{ id: "003", title: "喝酒", done: true },],};},methods: {// 添加一个todoaddTodo(todoObj) {// 操作数据往数组前方加数据this.todos.unshift(todoObj);},// 勾选、取消勾选todocheckTodo(id) {// 拿到todos遍历todo项this.todos.forEach((todo) => {if (todo.id == id) todo.done = !todo.done;});},// 删除一个tododeleteTodo(id) {this.todos = this.todos.filter((todo) => todo.id !== id);},// 全选或者全不选checkAllTodo(done) {this.todos.forEach((todo) => {todo.done = done;});},// 清除所有已完成的todoclearDoneTodo() {this.todos = this.todos.filter((todo) => {return !todo.done;});},},
};
</script><style scoped>
/*base*/
body {background: #fff;
}.btn {display: inline-block;padding: 4px 12px;margin-bottom: 0;font-size: 14px;line-height: 20px;text-align: center;vertical-align: middle;cursor: pointer;box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);border-radius: 4px;
}.btn-danger {color: #fff;background-color: #da4f49;border: 1px solid #bd362f;
}.btn-danger:hover {color: #fff;background-color: #bd362f;
}.btn:focus {outline: none;
}.todo-container {width: 600px;margin: 0 auto;
}
.todo-container .todo-wrap {padding: 10px;border: 1px solid #ddd;border-radius: 5px;
}
</style>

TodoFooter.vue

<template><div class="todo-footer" v-show="total"><label><!-- <input type="checkbox" :checked="isAll" @change="checkAll" /> --><!-- 使用v-model --><input type="checkbox" v-model="isAll" /></label><span><span>已完成{{ doneTotal }}</span> / 全部{{ total }}</span><button class="btn btn-danger" @click="clearDone">清除已完成任务</button></div>
</template><script>
export default {name: "TodoFooter",props: ["todos", "checkAllTodo", "clearDoneTodo"],computed: {//总数total() {return this.todos.length;},//计算已完成数doneTotal() {// 遍历let i = 0;this.todos.forEach((todo) => {if (todo.done) i++;});return i;//此处使用reduce方法做条件统计// 最后一个返回值作为reduce的返回值/*  const x = this.todos.reduce((pre, current) => {console.log("@", pre, current);return pre + (current.done ? 1 : 0);}, 0); *//*  return this.todos.reduce((pre, todo) => pre + (todo.done ? 1 : 0), 0); */},/* isAll() {// 总数大于零并且相等return this.doneTotal === this.total && this.total > 0;}, *///控制全选框isAll: {//全选框是否勾选get() {return this.doneTotal === this.total && this.total > 0;},//isAll被修改时set被调用set(value) {this.checkAllTodo(value);},},},methods: {/*     checkAll(e) {this.checkAllTodo(e.target.checked);}, *///清空所有已完成clearDone() {this.clearDoneTodo();},},
};
</script><style scoped>
/*footer*/
.todo-footer {height: 40px;line-height: 40px;padding-left: 6px;margin-top: 5px;
}.todo-footer label {display: inline-block;margin-right: 20px;cursor: pointer;
}.todo-footer label input {position: relative;top: -1px;vertical-align: middle;margin-right: 5px;
}.todo-footer button {float: right;margin-top: 5px;
}
</style>

TodoHeader.vue

<template><div class="todo-header"><!-- @keyup.enter="add":按下enter添加add()方法 --><inputtype="text"placeholder="请输入你的任务名称,按回车键确认"v-model="title"@keyup.enter="add"/></div>
</template><script>
// 引入nanoid生成唯一字符串给id
import { nanoid } from "nanoid";
export default {name: "TodoHeader",props: ["addTodo"],data() {return {title: "",};},methods: {add() {// 将用户的输入包装成todo对象// 校验数据if (!this.title.trim()) return alert("输入不能为空");//将用户的输入包装成一个todo对象// nanoid() 生成全球唯一字符串const todoObj = { id: nanoid(), title: this.title, dnoe: false };// 通知App组件去添加ToDO对象this.addTodo(todoObj);// 成功输入完添加后输入框变为空this.title = "";},// 接受App传过来的参数},
};
</script><style scoped>
/*header*/
.todo-header input {width: 560px;height: 28px;font-size: 14px;border: 1px solid #ccc;border-radius: 4px;padding: 4px 7px;
}.todo-header input:focus {outline: none;border-color: rgba(82, 168, 236, 0.8);box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);
}
</style>

TodoItem.vue

<template><li><label><!-- :checked="true" 如果后面属性是true就勾选 --><!-- 如下代码也能实现功能,但不太推荐,因为有点违反原则,修改了props --><inputtype="checkbox":checked="todo.done"@change="handleCheck(todo.id)"/><!-- 展示todo事项的名字 --><span>{{ todo.title }}</span></label><button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button></li>
</template><script>
export default {name: "TodoItem",// 声明接收父容器todoList传来的对象props: ["todo", "checkTodo", "deleteTodo"],methods: {// 勾选handleCheck(id) {// 通知App组件将对应的todo对象值取反this.checkTodo(id);},// 删除handleDelete(id) {if (confirm("确认删除吗?")) {//通知App组件将对应的todo对象删除this.deleteTodo(id);}},},
};
</script><style scoped>
/*item*/
li {list-style: none;height: 36px;line-height: 36px;padding: 0 5px;border-bottom: 1px solid #ddd;
}li label {float: left;cursor: pointer;
}li label li input {vertical-align: middle;margin-right: 6px;position: relative;top: -1px;
}li button {float: right;display: none;margin-top: 3px;
}li:before {content: initial;
}li:last-child {border-bottom: none;
}li:hover {background-color: #ddd;
}
li:hover button {display: block;
}
</style>

TodoList.vue

<template><ul class="todo-main"><!-- v-for="todoObj in todos" :遍历todos的对象:key="todoObj.id" 使用id作为索引变量--><todo-itemv-for="todoObj in todos":key="todoObj.id":todo="todoObj":checkTodo="checkTodo":deleteTodo="deleteTodo"></todo-item></ul>
</template><script>
// 引入item
import TodoItem from "./TodoItem.vue";
export default {name: "TodoList",components: {TodoItem,},//声明接收App传递过来的数据,其中todos是自己用的,checkTodo和deleteTodo是给子组件MyItem用的props: ["todos", "checkTodo", "deleteTodo"],
};
</script><style scoped>
/*main*/
.todo-main {margin-left: 0px;border: 1px solid #ddd;border-radius: 2px;padding: 0px;
}.todo-empty {height: 40px;line-height: 40px;border: 1px solid #ddd;border-radius: 2px;padding-left: 5px;margin-top: 10px;
}
</style>

尚硅谷todolist案例相关推荐

  1. hive尚硅谷实战案例统计youtube视频热度

    hive视频热度统计案例 文章目录 hive视频热度统计案例 背景及需求描述 项目的完成 1. 数据清洗 (1) maven依赖 (2)ETLUtils-处理具体的数据清洗逻辑 (3)ETLMappe ...

  2. 尚硅谷github案例

    引入第三方bootstrap,要在public文件下的index.html中用link引入(且用相同的BAS_URl),如果在App.vue中引入会出现错误. Search组件(搜索栏) 引入axio ...

  3. 02尚硅谷书城案例-用户的注册

    1.JavaEE 项目的三层架构 2.先创建书城需要的数据库和表 drop database if exists book; create database book; CREATE TABLE t_ ...

  4. 尚硅谷大数据技术Spark教程-笔记09【SparkStreaming(概念、入门、DStream入门、案例实操、总结)】

    尚硅谷大数据技术-教程-学习路线-笔记汇总表[课程资料下载] 视频地址:尚硅谷大数据Spark教程从入门到精通_哔哩哔哩_bilibili 尚硅谷大数据技术Spark教程-笔记01[SparkCore ...

  5. 【视频分享】尚硅谷HTML5前端视频_Vue核心技术视频

    本视频基于Vue2.5录制, 涵盖Vue开发所需技术: 模板.数据绑定.声明式渲染.计算属性.事件处理.过渡动画.指令.自定义Vue插件.组件化开发.组件间通信.Ajax前后台交互.Vue-Route ...

  6. 尚硅谷大数据视频_Shell视频教程

    Shell是一个功能相当强大的编程语言,易编写.易调试.灵活性强.Shell可以帮助我们来管理大数据集群,提高开发效率.本课程详细讲解:Shell解析器.变量.运算符.条件判断.流程控制.函数.cut ...

  7. ToDoList 案例完整 尚硅谷

    总结ToDoList案例: 1.组件化编码流程: (1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突. (2).实现动态组件:考虑好数据的存放位置,数据是一个组件再用,还是一些组件 ...

  8. 尚硅谷Redis6基础教程-秒杀案例中库存遗留问题

    尚硅谷redis6基础教程中视频24-27的秒杀案例,使用Redis乐观锁解决了超卖问题,但是也产生了库存遗留问题.引入Lua脚本,解决了超卖和库存遗留.Lua脚本为什么解决了库存遗留问题???

  9. 【HBase学习笔记-尚硅谷-Java API shell命令 谷粒微博案例】

    HBase学习笔记 HBase 一.HBase简介 1.HBase介绍 2.HBase的逻辑结构和物理结构 3.数据模型 4.基本架构 二.快速入门 1.配置HBase 2.命令 三.API 1.获取 ...

最新文章

  1. C/C++反序输出字符串总结
  2. 如何备份被独占文件?
  3. Angular中父组件通过ViewChild调用子组件的方法
  4. JavaScript实现isPowerOfTwo算法(附完整源码)
  5. CVE-2018-4407 苹果设备远程溢出漏洞
  6. Objective-C使用位运算设计可复选的枚举
  7. linux系统备份和恢复
  8. 计算机黑屏策略,小黑w7系统诊断策略服务已被禁用的还原教程
  9. 各种好用的开源库。快点进来,包你喜欢~^_^
  10. ZooKeeper系列(3):znode说明和znode状态
  11. babel插件入门-AST
  12. (H2与HBase)面向行or面向列的存储模型?
  13. 3、plt.figure()和Axes类
  14. 最新最全的微信小程序入门学习教程,微信小程序零基础入门到精通
  15. 桑基图绘制的简易操作
  16. 淘宝美工设计需要掌握什么技能 ?小白如何快速学会美工设计?
  17. 分类模型到底如何选择
  18. AttributeError: module 'torch.nn' has no attribute 'LocalResponseNorm'问题的解决办法
  19. c# 自定义多个SplitContainer 支持点击放大缩小
  20. 基于JAVA汽车租赁平台的设计与实现计算机毕业设计源码+系统+mysql数据库+lw文档+部署

热门文章

  1. 3D立体相册,一个可旋转的立体相册
  2. Android的在线考试app
  3. 嵌入式监控【v4l2采集-vpu编码-live555推流】
  4. 寻找复杂背景下的物体轮廓 (从禾路的博客园整理学习)
  5. PyCharm vs VSCode 到底谁更牛?
  6. 3dsmax快捷键大全
  7. AS打包V1和V2签名,使用乐固加固安装包签名有误 ShieldCode = 40186
  8. vue-router配置路由实现返回上一页,上一页页面数据留存
  9. 在快手工作是一种什么样的体验?
  10. 实现一个小程序分享图 wxml2canvas