惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Schneier on Security
博客园_首页
量子位
博客园 - 司徒正美
S
SegmentFault 最新的问题
J
Java Code Geeks
小众软件
小众软件
博客园 - 【当耐特】
The Register - Security
The Register - Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Microsoft Azure Blog
Microsoft Azure Blog
G
Google Developers Blog
Blog — PlanetScale
Blog — PlanetScale
T
Tailwind CSS Blog
博客园 - Franky
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
G
GRAHAM CLULEY
Cyberwarzone
Cyberwarzone
腾讯CDC
Apple Machine Learning Research
Apple Machine Learning Research
V
Visual Studio Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
The Hacker News
The Hacker News
aimingoo的专栏
aimingoo的专栏
V
Vulnerabilities – Threatpost
P
Palo Alto Networks Blog
Scott Helme
Scott Helme
L
LINUX DO - 热门话题
F
Full Disclosure
D
DataBreaches.Net
Martin Fowler
Martin Fowler
Cisco Talos Blog
Cisco Talos Blog
L
LINUX DO - 最新话题
云风的 BLOG
云风的 BLOG
C
Check Point Blog
T
Threatpost
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
W
WeLiveSecurity
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
有赞技术团队
有赞技术团队
Hugging Face - Blog
Hugging Face - Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
Lohrmann on Cybersecurity
Last Week in AI
Last Week in AI
T
Tor Project blog
T
Troy Hunt's Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
Security Affairs
SecWiki News
SecWiki News

追梦人物的博客

0x05:Merkle Tree & Patricia Trie 0x04:ECDSA - 以太坊设计与实现 LeetCode 105 从前序与中序遍历构造二叉树 迭代算法原理 + 完整证明 0x03:Address - 以太坊设计与实现 0x02:Secp256k1 - 以太坊设计与实现 0x00:专栏开篇 - 以太坊设计与实现 0x01:RLP 编码 - 以太坊设计与实现 Bellman-Ford 算法原理及其在 DeFi 套利中的应用 - 追梦人物的博客 迪杰斯特拉(Dijkstra)最短路径算法原理、实现与证明 - 追梦人物的博客 实战:CEX-DEX 稳定币套利监控程序开发 - 追梦人物的博客 CEX-DEX 稳定币套利模型 - 追梦人物的博客 Uniswap 手续费和协议费机制剖析 - 追梦人物的博客 Uniswap 流动性机制及相关数学原理分析 - 追梦人物的博客 uv 替代 pyenv + pipx + poetry 环境管理实践 Rust 项目从创建到发布 - 追梦人物的博客 VS Code 调试 Python - 追梦人物的博客 比特币跨市场套利的数学模型 - 追梦人物的博客 ERC-20 相关知识点总结 - 追梦人物的博客 Django 老项目如何从 SQLite 迁到 PostgreSQL 自动生成接口文档 - HelloDjango - django REST framework 教程 单元测试 - HelloDjango - django REST framework 教程 限制接口访问频率 - HelloDjango - django REST framework 教程 API 版本管理 - HelloDjango - django REST framework 教程 如何在 Windows 下搭建高效的 django 开发环境 拓展Python Markdown - 追梦人物的博客 加缓存为接口提速 - HelloDjango - django REST framework 教程 基于 drf-haystack 实现文章搜索接口 - HelloDjango 评论接口 - HelloDjango - django REST framework 教程 实现分类、标签、归档日期接口 - HelloDjango - django REST framework 教程 在接口返回Markdown解析后的内容 - HelloDjango - django REST framework 教程 文章详情接口 - HelloDjango - django REST framework 教程 分页 - HelloDjango - django REST framework 教程 使用视图集简化代码 - HelloDjango - django REST framework 教程 用类视图实现首页 API - HelloDjango - django REST framework 教程 实现博客首页文章列表 API - HelloDjango - django REST framework 教程 初始化 RESTful API 风格的博客系统 - HelloDjango django-rest-framework 是什么鬼? - HelloDjango - django REST framework 教程 结束 or 开始? - HelloDjango Coverage.py 统计测试覆盖率 - HelloDjango - Django博客教程(第二版) 单元测试:测试评论应用 - HelloDjango - Django博客教程(第二版) 单元测试:测试 blog 应用 - HelloDjango Django Haystack 全文检索与关键词高亮 - HelloDjango Django 博客实现简单的全文搜索 - HelloDjango - Django博客教程(第二版) 开启 Django 博客的 RSS 功能 - HelloDjango 统计各个分类和标签下的文章数 - HelloDjango - Django博客教程(第二版) 稳定易用的 Django 分页库,完善分页功能 - HelloDjango 通过 Django Pagination 实现简单分页 - HelloDjango 在脚本中使用 ORM:Faker 批量生成测试数据 - HelloDjango Django 官方推荐的姿势:类视图 - HelloDjango - Django博客教程(第二版) Django 使用 union 合并不同模型(Model) 的查询集(QuerySet) 开发博客文章阅读量统计功能 - HelloDjango - Django博客教程(第二版) 使用 Docker 让部署 Django 项目更加轻松 - HelloDjango 使用 Certbot 向 Let's Encrypt 免费申请 HTTPS 证书 - HelloDjango 使用 Fabric 自动化部署 - HelloDjango 博客代码开源啦 - 追梦人物的博客 (赠书)推荐一本django书籍:Django企业开发实战 - 追梦人物的博客 Nginx+Gunicorn+Supervisor 部署 Django 博客应用 - HelloDjango 优化博客功能细节,提升使用体验 - HelloDjango - Django博客教程(第二版) 交流的桥梁:评论功能 - HelloDjango - Django博客教程(第二版) 分类、归档和标签页 - HelloDjango - Django博客教程(第二版) 页面侧边栏:使用自定义模板标签 - HelloDjango - Django博客教程(第二版) 自动生成文章摘要 - HelloDjango - Django博客教程(第二版) Markdown 文章自动生成目录,提升阅读体验 - HelloDjango - Django博客教程(第二版) 让博客支持 Markdown 语法和代码高亮 - HelloDjango 开发博客文章详情页 - HelloDjango - Django博客教程(第二版) 创作后台开启,请开始你的表演 - HelloDjango - Django博客教程(第二版) 博客从“裸奔”到“有皮肤” - HelloDjango - Django博客教程(第二版) Django 的接客之道 - HelloDjango - Django博客教程(第二版) Django 迁移、操作数据库 - HelloDjango - Django博客教程(第二版) 创建 Django 博客的数据库模型 - HelloDjango 开始进入 django 开发之旅 - HelloDjango "空空如也"的博客应用 - HelloDjango - Django博客教程(第二版) 一种自顶而下的Python装饰器设计方法 - 追梦人物的博客 Python提取支付宝和微信支付二维码 - 追梦人物的博客 2018 - 我的学生生涯最后一年回顾 - 追梦人物的博客 筛选练习参考答案 - Vue 2.x Todo 教程练习参考答案 删除todo练习参考答案 - Vue 2.x Todo 教程练习参考答案 编辑todo练习参考答案 - Vue 2.x Todo 教程练习参考答案 添加todo练习参考答案 - Vue 2.x Todo 教程练习参考答案 标为完成练习参考答案 - Vue 2.x Todo 教程练习参考答案 入门仪式_Hello_Vue练习参考答案 - Vue 2.x Todo 教程练习参考答案 组件化todo应用 - Vue 2.x Todo 教程 批量清除todo - Vue 2.x Todo 教程 本地存储 - Vue 2.x Todo 教程 筛选 - Vue 2.x Todo 教程 还剩多少todo未完成 - Vue 2.x Todo 教程 自定义指令实现自动聚焦 - Vue 2.x Todo 教程 全部标为完成 - Vue 2.x Todo 教程 删除todo - Vue 2.x Todo 教程 编辑todo - Vue 2.x Todo 教程 添加todo - Vue 2.x Todo 教程 标为完成 - Vue 2.x Todo 教程 UI - Vue 2.x Todo 教程 显示todo列表 - Vue 2.x Todo 教程 入门仪式:Hello Vue - Vue 2.x Todo 教程 在学习django-rest-framework时收集的学习资料推荐 - 追梦人物的博客 区块链理论与应用研究小组成员招募书 - 追梦人物的博客 Python界网红,豆瓣工程师董伟明加了我的QQ后 - 追梦人物的博客 招募Django学习小组项目组核心成员 - 追梦人物的博客
批量清除todo练习参考答案 - Vue 2.x Todo 教程练习参考答案
2019-01-14 · via 追梦人物的博客

练习一

非常简单,用 if 指令,根据是否存在某类型的 todo 来决定该类型的按钮显示或者隐藏即可,具体的有:

  • 如果不存在未完成的 todo,全部标为完成、进行中的按钮隐藏。
  • 如果不存在已完成的 todo,已完成、清除已完成的按钮隐藏。
  • 若没有 todo,筛选和清除等按钮全隐藏,显示“添加我的第一个 todo”,若不存在未完成的 todo,显示“全部完成,你真是太优秀了”,否则显示“剩余 x 项未完成”。

首先增加两个计算属性,返回全部已完成的 todo 和其数量,同时顺便把 filteredTodos 计算属性重构一下:

computed: {
    ...
    completedTodos: function () {
        return this.todos.filter(todo => todo.completed)
    },
    completedTodosCount: function () {
        return this.completedTodos.length
    },
    filteredTodos: function () {
        if (this.intention === 'ongoing') {
            return this.leftTodos
        } else if (this.intention === 'completed') {
            return this.completedTodos
        } else {
            // 其它未定义的意图我们为其返回全部 todos,
            // 这里面已经包含了 all 意图了
            return this.todos
        }
    }

然后根据这些计算属性判断相应按钮和文字的显示和隐藏即可:

<input v-if="leftTodosCount"
       type="button"
       value="全部标为完成"
       @click="markAllAsCompleted"/>
<span v-if="leftTodosCount">剩余 {{leftTodosCount}} 项未完成 ---</span>
<span v-else-if="completedTodosCount">全部完成,你真是太优秀了!</span>
<span v-else>添加我的第一个todo</span>
<span v-if="todos.length">筛选:
  <input type="button"
         class="selected"
         value="全部"
         @click="intention='all'"/>
  <input v-if="leftTodosCount"
         type="button"
         value="进行中"
         @click="intention='ongoing'"/>
  <input v-if="completedTodosCount"
         type="button"
         value="已完成"
         @click="intention='completed'"/>
  <input v-if="completedTodosCount"
         type="button"
         value="清除已完成"
         @click="clearCompleted"/>
  <input type="button"
         value="清除全部"
         @click="clearAll"/>
</span>

练习二

清除时确认的功能和之前删除单个 todo 的功能类似,代码如下:

clearCompleted: function () {
    if (!confirm('确认清除全部已完成的待办事项?')) {
        return
    }
    this.todos = this.todos.filter(todo => !todo.completed)
},
clearAll: function () {
    if (!confirm('确认清除全部待办事项?')) {
        return
    }
    this.todos = []
}

回收站的功能略微复杂,我们来逐步分析。

首先我们需要改造一下 todo 模型,为其增加一个 removed 属性,这个属性用于标识 todo 是否已经被删除,注意这次删除 todo 时不再是直接从 todos 数组里删除,而是将其移到回收站(增加一个回收站数组用于存放删除的 todo),removed 属性的值会给我们今后为是否删除的 todo 执行不同操作时带来诸多方便,具体修改如下:

data: function () {
    return {
        todos: [],
        recycleBin: [], // 用于存放已经删除的 todo
        newTodoTitle: '',
        editedTodo: null, // 用户暂存编辑前的 todo 状态
        intention: 'all', // 默认为 all
    }
},
methods: {
    addTodo: function () {
        this.todos.push(
            // 修改后的 todo 模型
            {id: id++, title: this.newTodoTitle, completed: false, removed: false}
        );
        this.newTodoTitle = '';
    },
    ...
},

然后当我们删除 todo 或者清除 todo 时,应该把删除的 todo 插入 recycleBin 数组中,以便后续还原,即相应修改 removeTodoclearAllclearCompleted 方法的逻辑:

removeTodo: function (todo) {
    let removedTodo = this.todos.splice(this.todos.indexOf(todo), 1)[0];
    removedTodo.removed = true;
    this.recycleBin.unshift(removedTodo);
},
clearCompleted: function () {
    if (!confirm('确认清除全部已完成的待办事项?')) {
        return
    }
    this.completedTodos.map(todo => todo.removed = true);
    this.recycleBin.unshift(...this.completedTodos);
    this.todos = this.leftTodos;
},
clearAll: function () {
    if (!confirm('确认清除全部待办事项?')) {
        return
    }
    this.todos.map(todo => todo.removed = true);
    this.recycleBin.unshift(...this.todos);
    this.todos = [];
},

要注意熟悉 JavaScript 数组的插入删除等操作,具体请查看 js 的文档,这里不再详细说明。

然后增加一个回收站按钮,点击后进入回收站,显示全部已删除的 todo:

<span v-if="todos.length || recycleBin.length">筛选:
  ...
  <input v-if="recycleBin.length"
         type="button"
         value="回收站"
         @click="intention='removed'"/>
</span>

这里回收站这个按钮和已完成、进行中等筛选按钮是类似的,它对应的 intention 是 removed,相应的要修改计算属性 filteredTodos 的逻辑,当 intention 为 removed 是能返回已删除的数组列表。

filteredTodos: function () {
    if (this.intention === 'ongoing') {
        return this.leftTodos
    } else if (this.intention === 'completed') {
        return this.completedTodos
    } else if (this.intention === 'removed') {
        return this.recycleBin
    } else {
        // 其它未定义的意图我们为其返回全部 todos,
        // 这里面已经包含了 all 意图了
        return this.todos
    }
}

现在看到回收站中的 todo 后面的按钮依然为删除,正确地应该显示为还原按钮,用于还原todo,可以根据 todo removed 属性的值来判断应该显示哪个按钮:

<li v-for='todo in filteredTodos' :key='todo.id'>
  <span :class="{completed: todo.completed}"
        @dblclick="editTodo(todo)">{{ todo.title }}</span>
  <input type="button"
         value="标为完成"
         @click="markAsCompleted(todo)"/>
  <input v-if="todo.removed" type="button" value="还原" @click="restoreTodo(todo)"/>
  <input v-else="todo.removed" type="button" value="删除" @click="removeTodo(todo)"/>
  ...
</li>

还原按钮绑定了一个 restoreTodo 方法,来实现一下:

restoreTodo: function (todo) {
    todo.removed = false;
    this.todos.unshift(todo);
    let pos = this.recycleBin.indexOf(todo);
    this.recycleBin.splice(pos, 1);
},

逻辑很简单,就是将已删除的 todo,从回收站数组移除,然后插入 this.todos,同时要记得将 removed 设置回 false。

类似的,我们还可以实现一次还原全部 todo,清空回收站的功能,其实现方法都大同小异,主要就是对 this.todos 和 recycleBin 数组的操作,请自行实现。

-- EOF --