大致步骤如下:

  • 1.创建新工程
  • 2.在 components 里分别创建 TodoList 的头部组件(TodoHeader.vue)、主体组件(TodoMain.vue)以及底部组件(TodoFooter.vue)
  • 3.在三个组件里分别完成其页面结构和样式,并在 App.vue 里分别引入三个组件并注册和使用,再引入需要的样式文件,最后启动项目效果如下:

  • 4. 把待办任务, 展示到页面TodoMain.vue组件上并关联选中状态, 设置相关样式:

App.vue – 准备数组通过 v-bind 传入TodoMain.vue内

在 TodoMain.vue 里通过 props 接收并通过 v-for 循环展示数据 ,并且 通过 v-model 绑定复选框选中状态,根据选中状态, 通过动态 class 设置完成划线样式

App.vue

<TodoMain :arr="list"></TodoMain>data () {return {// 准备数据list: [{ id: 100, name: "吃饭", isDone: true },{ id: 201, name: "睡觉", isDone: false },{ id: 103, name: "打豆豆", isDone: true },],}}

TodoMain.vue

<template><ul class="todo-list"><!-- completed: 完成的类名 --><li :class="{completed: obj.isDone}" v-for="obj in arr" :key="obj.id"><div class="view"><input class="toggle" type="checkbox" v-model="obj.isDone" /><label>{{obj.name}}</label><button class="destroy"></button></div></li></ul></template><script>
export default {name: 'TodoMain',// 接收父类传过来的数据props: ['arr']
}
</script>

  • 5.添加功能--输入任务敲击回车, 新增待办任务

首先,在 TodoHeader.vue  的输入框里绑定回车键盘事件并通过 v-model 获取输入框里的值

其次,通过子传父($emit), 把待办任务加到 App.vue 的数组list里

然后,原数组改变, 所有用到的地方都会更新

最后,输入框为空, 提示用户必须输入内容

TodoHeader.vue

    <!-- 添加回车键盘事件 通过 v-model 获取输入框里的值--><input class="new-todo"placeholder="输入任务名称-回车确认"autofocus@keydown.enter="downFn"v-model="task" />data () {return {task: ''}},methods: {downFn () {// 判断输入框里的数据是否为空if (this.task.trim().length === 0) {alert("任务名不能为空");return;}// 将子类的方法传递给父类this.$emit('create', this.task)// 敲完回车后清空输入框里的数据,便于下次输入this.task = ''}}

  • 6.删除功能-点击任务后的x, 删除当前这条任务

首先,在 TodoMain.vue 里给 x标签绑定一个点击事件,并传入id进行区分

然后,通过子传父的形式,把需要删除的任务对应的id传入App.vue里,在list数组里删除对应的数据

TodoMain.vue

 <!-- 给删除标签注册点击事件并传入对应的id进行区分 -->
<button class="destroy" @click="delFn(obj.id)"></button>methods: {delFn (id) {// 子传父this.$emit('del', id)}}

App.vue

<TodoMain :arr="list" @del="deleteFn"></TodoMain>// 删除任务deleteFn (theId) {// 通过传入过来的 id 找到 list 数组里对应的 idconst index = this.list.findIndex(obj => {obj.id === theId})// 删除数据this.list.splice(index, 1)}

  • 7.底部统计--统计当前任务的条数

首先,在App.vue中 –通过 v-bind 将数据传递给TodoFooter.vue

然后,在 TodoFooter.vue 里通过 props 接收,这里可以直接在标签上显示 / 定义计算属性用于显示都可以

原数组只要改变, 所有用到此数组的地方都会更新

App.vue

<TodoFooter :farr="list"></TodoFooter>

TodoFooter.vue

    <!-- <span class="todo-count">剩余<strong>{{farr.length}}</strong></span> --><!-- 或者通过计算属性获取 --><span class="todo-count">剩余<strong>{{count}}</strong></span>// 接收父类传递过来的数据props: ['farr'],// 计算属性,返回任务的数量computed: {count(){return this.farr.length}}

  • 8.数据切换--点击底部切换 – 点谁谁有边框、对应切换不同数据显示

首先在TodoFooter.vue – 定义isSel – 值为all, yes, no其中一种

然后,在对应的li标签的a标签上通过动态class分别判断谁应该有类名selected

其次,给li标签的a标签上绑定点击事件,实现点击修改isSel的值然后谁就高亮显示

再者,通过子传父, 把类型isSel传到App.vue中,在App.vue中先通过 getSel: 'all' 保存到中转的变量上

最后,再定义计算属性showArr,利用中转变量配合list进行筛选,将筛选的结果返回给 showArr ,再通过 showArr 传递到展示区域TodoMain.vue和统计区域TodoFooter.vue

TodoFooter.vue,

    <ul class="filters" @click="fn"><!-- 判断谁应该有高亮样式用户点击要切换isSel里保存的值--><li><a :class="{selected: isSel === 'all'}" @click="isSel='all'" href="javascript:;" >全部</a></li><li><a :class="{selected: isSel === 'no'}" @click="isSel='no'" href="javascript:;">未完成</a></li><li><a :class="{selected: isSel === 'yes'}" @click="isSel='yes'" href="javascript:;" >已完成</a></li></ul>data () {return {isSel: 'all' // 全部-all,已完成-yes,未完成-no}},methods: {fn(){this.$emit('changeType', this.isSel)}}

app.vue,

<TodoMain :arr="showArr" @del="deleteFn"></TodoMain>
<TodoFooter :farr="showArr" @changeType="typeFn"></TodoFooter>getSel: 'all'typeFn(str){ // 这里 str=all/yes/nothis.getSel = str}computed: {// 定义 showArr 数组,通过list配合条件筛选而来showArr(){if(this.getSel === 'yes'){return this.list.filter(obj => obj.isDone  === true)}else if(this.getSel === 'no'){return this.list.filter(obj => obj.isDone  === false)}else{return this.list}}}

  • 9.清空已完成--点击右下角链接标签, 清除已完成任务

首先,在 TodoFooter.vue 里给清空标签绑定点击事件

然后,通过子传父传递给 App.vue – 一个清空方法

最后,在 App.vue  里过滤未完成的覆盖list数组 (不考虑恢复)

TodoFooter.vue ,

    <!-- 清除已完成 --><button class="clear-completed" @click="clearFn">清除已完成</button>clearFn(){// 触发父类App.vue里事件对应celarF方法this.$emit('clear')}

App.vue ,

<TodoFooter :farr="showArr" @changeType="typeFn" @clear="clearF"></TodoFooter>clearF(){// 清除已完成的任务this.list = this.list.filter(obj => obj.isDone == false)}
  • 10.数据缓存--

首先,在App.vue – 侦听list数组改变 – 深度侦听

然后,覆盖式存入到本地 – 注意本地只能存入JSON字符串

最后,当刷新页面 – list应该默认从本地取值 – 要考虑无数据情况空数组

App.vue ,

  // 数据缓存watch: {list: {deep: true,handler(){localStorage.setItem('todoList', JSON.stringify(this.list))}}}data () {return {// 准备数据// list: [//   { id: 100, name: "吃饭", isDone: true },//   { id: 201, name: "睡觉", isDone: false },//   { id: 103, name: "打豆豆", isDone: true },// ],// 默认从本地取值list: JSON.parse(localStorage.getItem('todoList')) || [],getSel: 'all'}},

  • 11.全选功能--点击全选 – 小选框受到影响、小选框都选中(手选) – 全选自动选中状态

TodoHeader.vue – 通过 v-model 关联全选的状态,然后通过计算属性 - isAll

App.vue – 传入数组list – 在isAll的set里影响小选框

isAll的get里统计小选框最后状态, 影响isAll – 影响全选状态

考虑无数据情况空数组 – 全选不应该勾选

TodoHeader.vue ,

<input id="toggle-all"class="toggle-all"type="checkbox"v-model="isAll">computed: {isAll: {set(checked){// 只有 true/false// 影响数组里每个小选框绑定的 isDone 属性this.arr.forEach(obj => {obj.isDone = checked})},get(){// 小选框统计状态去影响全选框// 如果没有数据直接返回 false 不要让全选处于勾选状态return this.arr.length !== 0 && this.arr.every(obj => obj.isDone === true)}}},props: ['arr']

App.vue,

 <TodoHeader @create="createFn" :arr="list"></TodoHeader>

源码:可能略有改动

App.vue

<template><div class="todoapp"><TodoHeader :arr="list" @create="createFn"></TodoHeader><TodoMain :arr="showArr" @del="deleteFn"></TodoMain><TodoFooter :farr="showArr" @changeType="typeFn"@clear="clearFun"></TodoFooter></div>
</template><script>
// 1. 目标: 创建工程-准备相关组件文件-标签+样式 (静态)
// 1.0 样式引入
import "./styles/base.css"
import "./styles/index.css"
// 1.1 组件引入
import TodoHeader from './components/TodoHeader'
import TodoMain from './components/TodoMain'
import TodoFooter from './components/TodoFooter'
export default {// 1.2 组件注册components: {TodoHeader,TodoMain,TodoFooter},// 2. 目标: 铺设待办任务// 2.0 - 准备数据data(){return {// 8.1 默认从本地取值list: JSON.parse(localStorage.getItem('todoList')) || [],// 6.4 先中转接收类型字符串getSel: "all" // 默认显示全部}},methods: {createFn(taskName){ // 添加任务// 3.3 push到数组里let id = this.list.length == 0 ? 100 : this.list[this.list.length - 1].id + 1this.list.push({id: id,name: taskName,isDone: false})},deleteFn(theId){ // 删除任务let index = this.list.findIndex(obj => obj.id === theId)this.list.splice(index, 1)},typeFn(str){ // 'all' 'yes' 'no' // 修改类型this.getSel = str},clearFun(){ // 清除已完成this.list = this.list.filter(obj => obj.isDone == false)}},// 6.5 定义showArr数组 - 通过list配合条件筛选而来computed: {showArr(){if (this.getSel === 'yes') { // 显示已完成return this.list.filter(obj => obj.isDone === true)} else if (this.getSel === 'no') { // 显示未完成return this.list.filter(obj => obj.isDone === false)} else {return this.list // 全部显示}}},// 8. 目标: 数据缓存watch: {list: {deep: true,handler(){// 8.0 只要list变化 - 覆盖式保存到localStorage里localStorage.setItem('todoList', JSON.stringify(this.list))}}}
}
</script>

TodoHeader.vue

<template><header class="header"><h1>todos</h1><!-- 9. 目标: 全选状态9.0 v-model关联全选状态页面变化(勾选true, 未勾选false) -> v-model -> isAll变量--><input id="toggle-all" class="toggle-all" type="checkbox" v-model="isAll" /><label for="toggle-all"></label><!-- 3.0 键盘事件-回车按键3.1 输入框 - v-model获取值--><inputclass="new-todo"placeholder="输入任务名称-回车确认"autofocus@keydown.enter="downFn"v-model="task"/></header>
</template><script>
// 3. 目标 - 新增任务
export default {data() {return {task: "",};},methods: {downFn() {if (this.task.trim().length === 0) {alert("任务名不能为空");return;}// 3.2(重要) - 当前任务名字要加到list数组里// 子传父技术this.$emit("create", this.task);this.task = "";},},// 9.1 定义计算属性computed: {isAll: {set(checked) {// 只有true / false// 9.3 影响数组里每个小选框绑定的isDone属性this.arr.forEach((obj) => (obj.isDone = checked));},get() {// 9.4 小选框统计状态 -> 全选框// 9.5 如果没有数据, 直接返回false-不要让全选勾选状态return (this.arr.length !== 0 && this.arr.every((obj) => obj.isDone === true));},},},// 9.2 父 -> 子 list数组props: ["arr"],
};
</script>

TodoMain.vue

<template><ul class="todo-list"><!-- 2.2 循环任务-关联选中状态-铺设数据 --><!-- completed: 完成的类名 --><li :class="{completed: obj.isDone}" v-for="obj in arr" :key='obj.id'><div class="view"><input class="toggle" type="checkbox" v-model="obj.isDone"/><label>{{ obj.name }}</label><!-- 4.0 注册点击事件 --><button class="destroy" @click="delFn(obj.id)"></button></div></li></ul>
</template><script>
// 4. 目标: 删除list里数据
export default {// 2.1 定义propsprops: ['arr'],methods: {delFn(id){// 4.1 子传父this.$emit('del', id)}}
}
</script>

TodoFooter.vue

<template><footer class="footer"><span class="todo-count">剩余<strong>{{ count }}</strong></span><ul class="filters" @click="fn"><li><!-- 6.1 判断谁应该有高亮样式: 动态class6.2 用户点击要切换isSel里保存的值--><a :class="{selected: isSel === 'all'}" href="javascript:;" @click="isSel='all'">全部</a></li><li><a :class="{selected: isSel === 'no'}" href="javascript:;" @click="isSel='no'">未完成</a></li><li><a :class="{selected: isSel === 'yes'}" href="javascript:;" @click="isSel='yes'">已完成</a></li></ul><!-- 7. 目标: 清除已完成 --><!-- 7.0 点击事件 --><button class="clear-completed" @click="clearFn">清除已完成</button></footer>
</template><script>
// 5. 目标: 数量统计
export default {// 5.0 props定义props: ['farr'],// 5.1 计算属性 - 任务数量computed: {count(){return this.farr.length}},// 6. 目标: 点谁谁亮// 6.0 变量isSeldata(){return {isSel: 'all' // 全部:'all', 已完成'yes', 未完成'no'}},methods: {fn(){ // 切换筛选条件// 6.3 子 -> 父 把类型字符串传给App.vue this.$emit("changeType", this.isSel)},clearFn(){ // 清空已完成任务// 7.1 触发App.vue里事件对应clearFun方法this.$emit('clear')}}
}
</script>

样式文件略

vue--实现todo案例相关推荐

  1. 【Vue知识点- No4.】vue组件、组件通信、Todo案例

    知识点自测 this指向 let obj = {fn: function(){// this指向此函数的调用者},fn () {// this指向当前函数的调用者 (如果都是在vue里, this指向 ...

  2. Vue实现Todo List

    基于Vue实现的Todo List 实现效果 完成功能 代码 传值解读 实现效果 完成功能 Vue 的基础案例 Vue 的组件 Vue 父组件向子组件传值 Vue 子组件向父组件传值 Vue 的动态样 ...

  3. Vue版todolist案例

    Vue版todolist案例 todolist – 记录你的待办事项 <!DOCTYPE html> <html><head><meta charset=&q ...

  4. vue本地存储案例_本地化还是创意适应? 流氓游戏街的案例研究

    vue本地存储案例 关于游戏<流氓街头> (About the game Streets of Rogue) In 2017 tinyBuild released Streets of R ...

  5. axios vue 回调函数_Vue 02 —— Vue 入门小案例~使用 Axios 中的GET、POST请求

    作为后端攻城狮,写前端代码是一种什么体验? 相信不少人和 @Python大星 一样,有写过前端代码的经历. 记录一下,Vue 框架开发中"啼笑皆非"的故事,非专业前端人员,该案例无 ...

  6. Vue学习小案例--分页组件封装

    文章目录 Vue学习小案例--分页组件封装 修改成Vue(使用组件) Vue学习小案例–分页组件封装 index.html <!DOCTYPE html> <html lang=&q ...

  7. 【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Table表格增删查改、Pagination分页、搜索框

    文章目录 目标 代码 0.结构 1.按钮-删除 2.按钮-编辑 3.debug 4.样式 5.分页Pagination:功能 6.分页Pagination:样式 7.搜索框:功能 8.搜索框:样式 总 ...

  8. 【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Form表单填写、Dialog对话框弹出

    文章目录 目标 代码 0.页面结构 1.新增按钮和弹出表单:结构 2.新增按钮和弹出表单:点击新增弹出表单 3.表单样式 4.表单验证 5.表单的提交和取消功能:接口.mock相关准备 6.表单的提交 ...

  9. 基于vue的todolist案例

    前言:todolist案例真的算是经典了,不管你是学习原生js,还是学习jq,还是学习vue,亦或者是react,todolist是练习必不可少的练习demo了,下面我们来看看这个案例.需要完整代码的 ...

  10. Vue模仿todo超详细讲解(附源码)

    Vue模仿todo超详细讲解(附源码) 一.todo基本DOM结构 二.todo功能需求分析 1.新增任务 2.点击变成完成状态 3.点击删除 4.双击进入编辑以及修改保存 5.底部的状态筛选 6.l ...

最新文章

  1. 重磅丨AI公共政策成全球热点,美国ITI发布《人工智能政策原则》
  2. 第一阶段团队成员贡献打分
  3. 不同Unix环境下date计算日期的用法
  4. tensorflow从入门到精通100讲(七)-TensorFlow房价预估使用Keras快速构建模型
  5. python安装与开发环境搭建实验总结_python实验一:python环境配置
  6. 希尔伯特曲线 java_Java中空间填充Hilbert曲线的递推算法
  7. linux输出文字的颜色特效
  8. 现在有一个整数数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数...
  9. golang开发环境配置及Beego框架安装
  10. 详解 Solidity 事件Event
  11. 白话文:几个例子马上看懂typescript基础类型
  12. DSP方案山景AP8224C2芯片可烧录适用USB声卡降噪麦克风
  13. 用Python爬虫爬取广州大学教务系统的成绩(内网访问)
  14. CSI-RS资源配置
  15. 复制粘贴到word文档中的表格超出页面该怎么办
  16. github followers-following相互比较
  17. HTML5 1.4 列表
  18. 备赛脱脂经验分享_敲黑板,备赛这几招如果你还不知道,赶快学起来吧!
  19. python Flask web 框架 (十七)
  20. ubuntu挂载gpt硬盘

热门文章

  1. DAA指令和DAS指令
  2. photoshop笔刷导入_200最好的免费Photoshop笔刷下载
  3. 如何查找计算机的键盘,怎么打开软键盘?各个系统打开软键盘的方法大全
  4. 电子邮箱账号申请注册,公司邮件系统哪个好?工作邮箱哪个好?
  5. nrf2401数据传输原理
  6. 设置文字渐变颜色在IOS系统上不显示问题
  7. 世界最美的40个小镇,中国上榜的竟是它们
  8. C++ ifstream
  9. Pytorch报错:AttributeError: ‘version_info‘ object has no attribute ‘__version__‘
  10. 超详细BootLoader原理分析