[TOC]
# 前情回顾
上一节课, 我们做了 jquery 备忘清单(1.0)
1. 输入内容在 input 框中回车, 或者点击蓝色按钮, 可以把内容插入备忘内容区
需要确定回车的 keyCode(13)
1. 最后插入的排在最上面
数组 unshift
1. 如果文字内容过长, 展示时要有省略号
字符串 slice
1. 页面刷新或者重启浏览器, 内容不丢失
localStorage
## 昨天 html, css, js 的完整代码
```html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="stylesheet" href="css/style.css" />
<link rel="stylesheet" type="text/css" href="css/iconfont.css" />
<script src="js/jquery.js"></script>
<script src="js/index.js"></script>
<title>备忘清单</title>
</head>
<body>
<!-- 总容器开始 -->
<div class="container">
<h1 class="myTitle">我的备忘清单</h1>
<!-- 输入框和按钮开始 -->
<div class="add-task">
<input
type="text"
placeholder="写下你的备忘吧..."
name="content"
/>
<button>添加备忘</button>
</div>
<!-- 输入框和按钮结束 -->
<!-- 清单列表开始 -->
<div class="task-list">
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
</div>
<!-- 清单列表结束 -->
</div>
<!-- 总容器结束 -->
</body>
</html>
```
```css
* {
margin: 0;
padding: 0;
outline: none;
-webkit-transition: background 200ms;
-moz-transition: background 200ms;
-ms-transition: background 200ms;
-o-transition: background 200ms;
transition: background 200ms;
}
body {
background: #00334b;
color: #fff;
}
h1.myTitle {
text-align: center;
margin: 20px;
}
.container {
margin: 0 auto;
/* background: red; */
max-width: 600px;
}
.task-item {
background: #fff;
color: #333;
margin-bottom: 3px;
cursor: pointer;
padding: 10px;
border-radius: 3px;
}
.task-item:hover {
background: #ddd;
}
.iconfont {
float: right;
margin-right: 10px;
}
input[type="text"] {
background: #ddd;
float: left;
width: 84%;
margin-right: 1%;
padding: 10px;
-moz-box-sizing: border-box; /*Firefox3.5+*/
-webkit-box-sizing: border-box; /*Safari3.2+*/
-o-box-sizing: border-box; /*Opera9.6*/
-ms-box-sizing: border-box; /*IE8*/
box-sizing: border-box;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
}
input[type="text"]:focus,
input[type="text"]:hover {
background: #eee;
}
.add-task button {
width: 15%;
background: rgb(3, 174, 255);
}
.add-task button:hover {
background: rgb(77, 195, 251);
}
input[type="text"],
.add-task button {
border: 0;
height: 100%;
}
.add-task {
height: 37px;
}
.task-list {
margin: 10px 0;
}
input,
button {
border-radius: 3px;
}
.task-content {
margin-left: 5px;
}
.iconfont:hover {
filter: drop-shadow(0 0 0 black);
}
```
```javascript
$(function() {
/* 声明变量 */
if (localStorage.getItem("task_list")) {
aTaskList = JSON.parse(localStorage.getItem("task_list"));
} else {
aTaskList = [];
}
showTask();
/* 声明函数 */
function showTask() {
var taskHTML = "";
for (var i = 0; i < aTaskList.length; i++) {
taskHTML += '<div class="task-item">';
taskHTML += '<span><input type="checkbox"></span>' + "\n";
taskHTML +=
'<span class="task-content">' + aTaskList[i] + "</span>";
taskHTML += '<span><i class="iconfont icon-del"></i></span>';
taskHTML += '<span><i class="iconfont icon-edit"></i></span>';
taskHTML += "</div>";
}
$(".task-list").html(taskHTML);
}
/* 逻辑代码 */
$("[name=content]").on("keypress", function(ev) {
if (ev.keyCode === 13 && compressContent($(this).val())) {
aTaskList.unshift(compressContent($(this).val()));
localStorage.setItem("task_list", JSON.stringify(aTaskList));
$(this).val("");
showTask();
}
});
$(".add-task button").on("click", function() {
if (compressContent($("[name=content]").val())) {
aTaskList.unshift(compressContent($("[name=content]").val()));
localStorage.setItem("task_list", JSON.stringify(aTaskList));
$("[name=content]").val("");
showTask();
}
});
// 文字过多, 就显示省略号
function compressContent(str) {
if (str.length >= 30) {
return str.slice(0, 30) + "···";
} else {
return str;
}
}
});
```
# 备忘清单 2.0
1. 主要内容分三块, 未完成, 已完成, 逻辑删除(回收站)
1. 三者之间可以互相转化
# 整理样式
首先, 我们需要把 html 的内容区分成三块, 每一块给一个不同的 class
![1545050410028](https://box.kancloud.cn/4340f5e055a924a90671830cdb9fd746_688x334.png)
这是原来的, 现在我复制`class`为`task-list`的 html 代码
```html
<div class="task-list">
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
</div>
<div class="task-list">
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
</div>
<div class="task-list">
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
</div>
```
结果就变成了这样...
![1545050507188](https://box.kancloud.cn/409d572eaa5bcb08bc52bf9711fd9845_678x710.png)
然后, 我们为每一块分配一个`class`, 第一块是`task-list` 这个就不用变了...
分别是`task-list`,`task-done`,`task-deleted`
```html
<div class="task-list"><!-- 代码省略 --></div>
<div class="task-done"><!-- 代码省略 --></div>
<div class="task-deleted"><!-- 代码省略 --></div>
```
这个时候再刷新...
![1545050757786](https://box.kancloud.cn/1458501ab49067407440f59fb8a308fa_662x760.png)
样式错了...
再来调调样式...
```css
.task-list,
.task-done,
.task-deleted {
margin: 10px 0;
}
```
![1545050869825](https://box.kancloud.cn/8ab94d620dd5dc3fa4c542fa0b1d1cd0_734x766.png)
现在就恢复正常了, 不过背景应该区分开...
```css
.task-done .task-item {
background: #ccc;
}
.task-deleted .task-item {
background: #a0a0a0;
}
```
![1545051427438](https://box.kancloud.cn/96c77f9da74ebc31729ce45ba7c944ef_666x782.png)
我们还需要给`已完成`加上删除线
```css
.task-done .task-content {
text-decoration: line-through;
}
```
![1545051938418](https://box.kancloud.cn/37665b7627193a59d4f5e3444dda96a7_641x229.png)
`已完成` 不应该都是打钩的吗?
```html
<span><input checked type="checkbox" /></span>
```
![1545052079345](https://box.kancloud.cn/0960bbc376f83188dbcc7fa8ea11dcfc_631x233.png)
`已完成`不应该有编辑按钮吧, 点击 checkbox, 返回`未完成`, 点击垃圾桶, 扔到`回收站`
```html
<div class="task-item">
<span><input checked type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
</div>
```
![1545052204693](https://box.kancloud.cn/264498b3fd632516cf9e7430bc39e19c_622x228.png)
垃圾桶那一块, `编辑`应该改成`还原`吧, 点击`还原`, 哪来的回哪去, 点击`删除`,`彻底删除`
看来我们需要新的图标...
![1545053249266](https://box.kancloud.cn/273d9fda145c90d314d7b52c6a8ebafc_571x254.png)
```html
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-remove"></i></span>
<span><i class="iconfont icon-undo"></i></span>
</div>
```
![1545053482379](https://box.kancloud.cn/f5b94fdd1f941336d828e0f87c92f7d2_615x237.png)
又要重新下载, 新增一个也需要全部再选择一遍? 岂不是很麻烦?
是需要重新下载, 但是不麻烦, 因为阿里图标支持新建项目, 来管理图标
![1545053418314](https://box.kancloud.cn/08d728debaea5bd1f8a09f2b9912f7be_789x306.png)
当然, 你也可以, 在原有`iconfont.css`的基础上, 加上新的 css`iconfont.css`
![1545102393112](https://box.kancloud.cn/9f6f569f2af7b196680653ef36662e01_375x173.png)
前提是, 类名不要重复...
![1545102432104](https://box.kancloud.cn/a789502f5790244842eadfd3b041ee12_993x718.png)
![1545102447421](https://box.kancloud.cn/e14b5b6b777a3d76740e20e356cf5308_1338x726.png)
如果两个图标, 都叫`remove`, 但是内容不同怎么办呢?
改 class 就好...
![1545102499762](https://box.kancloud.cn/086da09f75574f782d60f75c6cdda392_1326x693.png)
回收站不应该有`checkbox`吧...
那把他们干掉...
```html
<div class="task-item">
<!-- <span><input type="checkbox" /></span> -->
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-remove"></i></span>
<span><i class="iconfont icon-undo"></i></span>
</div>
```
![1545053575793](https://box.kancloud.cn/a1b6fff43cfe487c29f7ed6bef243a55_633x468.png)
又对不齐了... ![img](https://box.kancloud.cn/277f0a542bd933a004a93cbc95162a2e_300x292.jpg)
试试 css 的`visibility: hidden;`?
```css
.task-deleted input[type="checkbox"] {
visibility: hidden;
}
```
![1545053869471](https://box.kancloud.cn/77c93696a41512a49421e976212fded2_627x463.png)
完美 ![img](https://box.kancloud.cn/49dfbb31317e2f224ff6316373e4f48d_440x440.jpg)
不过... 貌似`已完成`的 hover 背景, 不是很明显...
![1545053962095](https://box.kancloud.cn/44b59d10bd391cf9972c9fabd8a86908_631x229.png)
```css
.task-done .task-item:hover {
background: #fffafa;
}
```
![1545054220097](https://box.kancloud.cn/4bf1a2426df7b5c5c4340bc3500daea3_628x230.png)
这回好多了...
到目前为止, 样式就调理的差不多了, 不过眼尖的同学可能会发现, 文字和图标, 好像不在一条直线上...
![1545055557111](https://box.kancloud.cn/f70fcb85449549cf51cfbb586603ef96_628x51.png)
因为文字和图标的行高不一致...
![1545059123108](https://box.kancloud.cn/5c16b6a35f32f218b91c57dd93c0f706_273x76.png)
![1545059238916](https://box.kancloud.cn/7ad366432e13784b3d4712e4c9740eea_260x86.png)
设置一致的行高即可
```css
.iconfont {
float: right;
margin-right: 10px;
line-height: 21px;
}
```
![1545058160555](https://box.kancloud.cn/a7ad19c1e84cb81bba7431ee809d3ef0_979x85.png)
# 开始 js
搞定了样式, 我们就可以写 js 了.
首先, 我们要操作单个的`task-item`, 那我们就需要准确的定位...
所以我们需要一个索引`index`
同时, 我们还需要一些属性, 标记他的状态 `done`, `delete`
所以我们需要一个对象...
包含`index,done,delete.content`
同时我们之前又是遍历的数组, 所以我们需要`数组装对象`
首先, 我们需要`index`, 数组的`index`, 因为数组自带索引, 我们就不用新建变量来保存索引了, 直接用就好
`index`的作用, 是告诉程序, 我们现在操作的是数组中的哪个元素
然后, 我们每次添加内容, 就不再是单纯的保存内容了, 而是保存一个对象, 然后压入数组...
所以, 我们需要修改新增`task-item`的两个函数
```javascript
$("[name=content]").on("keypress", function(ev) {
if (ev.keyCode === 13) {
var oTaskItem = {
content: $(this).val(),
isDel: 0,
isDone: 0
};
aTaskList.unshift(oTaskItem);
localStorage.setItem("task_list", JSON.stringify(aTaskList));
$(this).val("");
showTask();
}
});
$(".add-task button").on("click", function() {
var oTaskItem = {
content: compressContent($("[name=content]").val()),
isDel: 0,
isDone: 0
};
aTaskList.unshift(oTaskItem);
localStorage.setItem("task_list", JSON.stringify(aTaskList));
$("[name=content]").val("");
showTask();
});
```
当然, 展示的相关函数, 也要变...
```javascript
function showTask() {
var taskHTML = "";
aTaskList.forEach(function(value, key) {
taskHTML += '<div index="' + key + '" class="task-item">';
if (value.isDone) {
taskHTML +=
'<span><input index="' +
key +
'" checked type="checkbox"></span>' +
"\n";
} else {
taskHTML +=
'<span><input index="' +
key +
'" type="checkbox"></span>' +
"\n";
}
taskHTML += '<span class="task-content">' + value.content + "</span>";
taskHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-del"></i></span>';
taskHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-edit"></i></span>';
taskHTML += "</div>";
});
$(".task-list").html(taskHTML);
}
```
如果属性`isDone` 是 1(true)的话, 就让`checkbox`选中...
同理, 当 checkbox 被选中时, 我们也需要让对象的`isDone`变成 1, 所以我们需要监听 checkbox
先写一下监听, 打印`index`
```javascript
// 监听checkbox
$("input[type=checkbox]").click(function() {
if (!$(this).attr("checked")) {
console.log($(this).attr("index"));
$(this).attr("checked", "checked");
} else {
$(this).removeAttr("checked");
}
});
```
![1545064018002](https://box.kancloud.cn/d614927ca5cd48883f95f28550bd1125_1920x811.png)
没有问题...
然后我们开始改对象
先写一个改对象的函数...
```javascript
function changeObj(index, property, value) {
var obj = aTaskList[index];
obj[property] = value;
aTaskList[index] = obj;
localStorage.setItem("task_list", aTaskList);
}
```
然后在 checkbox 改变时, 调用它
```javascript
$("input[type=checkbox]").on("click", function() {
console.log("hello");
if (!$(this).attr("checked")) {
changeObj($(this).attr("index"), "isDone", 1);
$(this).attr("checked", "checked");
} else {
changeObj($(this).attr("index"), "isDone", 0);
$(this).removeAttr("checked");
}
showTask();
});
```
然而, 发现, 只能点击一次...
问题在于, 重新写入 html 代码后, 原来的代码就没有了.
所以需要把监听, 写在动态生成 html()代码之后
```javascript
function showTask() {
console.log(aTaskList);
var taskHTML = "";
aTaskList.forEach(function(value, key) {
taskHTML += '<div index="' + key + '" class="task-item">';
if (value.isDone) {
taskHTML +=
'<span><input index="' +
key +
'" checked type="checkbox"></span>' +
"\n";
} else {
taskHTML +=
'<span><input index="' +
key +
'" type="checkbox"></span>' +
"\n";
}
taskHTML += '<span class="task-content">' + value.content + "</span>";
taskHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-del"></i></span>';
taskHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-edit"></i></span>';
taskHTML += "</div>";
});
$(".task-list").html(taskHTML);
// 监听checkbox
$("input[type=checkbox]").on("click", function() {
console.log("hello");
if (!$(this).attr("checked")) {
changeObj($(this).attr("index"), "isDone", 1);
$(this).attr("checked", "checked");
} else {
changeObj($(this).attr("index"), "isDone", 0);
$(this).removeAttr("checked");
}
showTask();
});
}
```
checkbox 已经监听, 对象已经改变, 剩下的就是把不同类型的 task, 分到不同组里...
```javascript
function showTask() {
console.log(aTaskList);
$(".task-list").html("");
$(".task-done").html("");
aTaskList.forEach(function(value, key) {
if (!value.isDone && !value.isDel) {
var taskHTML = "";
taskHTML += '<div index="' + key + '" class="task-item">';
taskHTML +=
'<span><input index="' +
key +
'" type="checkbox" /></span>' +
"\n";
taskHTML +=
'<span class="task-content">' + value.content + "</span>";
taskHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-del"></i></span>';
taskHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-edit"></i></span>';
taskHTML += "</div>";
$(".task-list").append(taskHTML);
}
if (value.isDone && !value.isDel) {
var taskHTML = "";
taskHTML += '<div index="' + key + '" class="task-item">';
taskHTML +=
'<span><input index="' +
key +
'" checked type="checkbox" /></span>';
taskHTML +=
'<span class="task-content">' + value.content + "</span>";
taskHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-del"></i></span>';
taskHTML += "</div>";
$(".task-done").append(taskHTML);
}
});
// 监听checkbox
$("input[type=checkbox]").on("click", function() {
console.log("hello");
if (!$(this).attr("checked")) {
changeObj($(this).attr("index"), "isDone", 1);
$(this).attr("checked", "checked");
} else {
changeObj($(this).attr("index"), "isDone", 0);
$(this).removeAttr("checked");
}
showTask();
});
}
```
![1545066339514](https://box.kancloud.cn/1e3cd5033cc10ac1159fe47de41bb59b_704x742.png)
成功!!!
试了一下`取消完成`功能, 也是可以的
![1545066480937](https://box.kancloud.cn/49a255cea7780acf1d67c2ef87f8b597_696x733.png)
现在`未完成`和`已完成`的互转已经实现了!!!
接下来是未完成和`逻辑删除`的互转
在`showTask()`函数下
```javascript
// 监听未完成的删除按钮
$(".task-item .icon-del").on("click", function() {
changeObj($(this).attr("index"), "isDel", 1);
showTask();
});
```
还要写删除的展示...
```javascript
// 代码省略...
$(".task-deleted").html("");
aTaskList.forEach(function(value, key) {
// 代码省略...
if (!value.isDone && value.isDel) {
var taskHTML = "";
taskHTML += '<div index="' + key + '" class="task-item">';
taskHTML +=
'<span><input index="' + key + '" type="checkbox" /></span>';
taskHTML += '<span class="task-content">' + value.content + "</span>";
taskHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-remove"></i></span>';
taskHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-undo"></i></span>';
taskHTML += "</div>";
$(".task-deleted").append(taskHTML);
}
});
// 代码省略...
```
试一下效果
![1545067207480](https://box.kancloud.cn/dfa5d98d818ebee886f402d9e0fcfbec_635x507.png)
没有问题...
然后, 同理, 是被删除 task 的还原
```javascript
// 监听已删除的还原按钮
$(".task-deleted .icon-undo").on("click", function() {
changeObj($(this).attr("index"), "isDel", 0);
showTask();
});
```
其他代码不用改, 试了一下, 也没有问题...
![1545067429144](https://box.kancloud.cn/7b0212e2203e1028e185a729fda06855_668x506.png)
现在就剩下, 已完成和删除的互转了, 加油!!!
首先, 我们需要给`已完成`并且`已删除`的 task 加上删除线
先把 js 注释掉, 免得影响我们的内容
```html
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="stylesheet" href="css/style.css" />
<link rel="stylesheet" type="text/css" href="css/iconfont.css" />
<script src="js/jquery.js"></script>
<!-- <script src="js/index.js"></script> -->
<title>备忘清单</title>
```
然后, 给元素增加一个 class`is-deleted`, 并且设置样式
```html
<span><input type="checkbox" /></span>
<span class="task-content is-deleted">item content 1</span>
<span><i class="iconfont icon-remove"></i></span>
<span><i class="iconfont icon-undo"></i></span>
```
```css
.task-done .task-content,
.is-deleted {
text-decoration: line-through;
}
```
我们看一下效果...
![1545067754678](https://box.kancloud.cn/292e365936b61f4d2e961ca6e7c3591a_728x822.png)
前三项是有删除线的
那么我们现在可以写 js 了...
先来`已完成`转`已删除`
```javascript
// 监听已完成的删除按钮
$(".task-done .icon-del").on("click", function() {
changeObj($(this).attr("index"), "isDel", 1);
showTask();
});
```
```javascript
function showTask() {
// 代码省略...
if (value.isDone && value.isDel) {
var taskHTML = "";
taskHTML += '<div index="' + key + '" class="task-item">';
taskHTML +=
'<span><input index="' + key + '" type="checkbox" /></span>';
taskHTML +=
'<span class="task-content is-deleted">' +
value.content +
"</span>";
taskHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-remove"></i></span>';
taskHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-undo"></i></span>';
taskHTML += "</div>";
$(".task-deleted").append(taskHTML);
}
// 代码省略...
}
```
我们把 js 的注释去掉, 然后看一下效果...
没有问题
![1545068075421](https://box.kancloud.cn/3c41df409dcf4310fed26987cc619148_679x509.png)
试试还原? 也没有问题!
![1545068165360](https://box.kancloud.cn/e9f845ee629c2728ca73ec267212e5c5_695x513.png)
最后, 请大家思考一个问题
如下图
![1545068218115](https://box.kancloud.cn/73c629817785639e18deeb6ca288d012_719x530.png)
能不能, 把删除内容区域的`已完成`和`未完成`进行分组呢? 比如`已完成`在上, `未完成`在下?
机智如你, 一定会有答案的!!! ![img](https://box.kancloud.cn/c4a8975b9cf77e04bd9e518db0ee4aa8_240x240.jpg)
最后, 完整代码
```html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="stylesheet" href="css/style.css" />
<link rel="stylesheet" type="text/css" href="css/iconfont.css" />
<link rel="stylesheet" type="text/css" href="css/iconfont_2.css" />
<script src="js/jquery.js"></script>
<script src="js/index.js"></script>
<title>备忘清单</title>
</head>
<body>
<!-- 总容器开始 -->
<div class="container">
<h1 class="myTitle">我的备忘清单</h1>
<!-- 输入框和按钮开始 -->
<div class="add-task">
<input
type="text"
placeholder="写下你的备忘吧..."
name="content"
/>
<button>添加备忘</button>
</div>
<!-- 输入框和按钮结束 -->
<!-- 清单列表开始 -->
<div class="task-list">
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
<span><i class="iconfont icon-edit"></i></span>
</div>
</div>
<div class="task-done">
<div class="task-item">
<span><input checked type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
</div>
<div class="task-item">
<span><input checked type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
</div>
<div class="task-item">
<span><input checked type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
</div>
<div class="task-item">
<span><input checked type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
</div>
<div class="task-item">
<span><input checked type="checkbox" /></span>
<span class="task-content">item content 1</span>
<span><i class="iconfont icon-del"></i></span>
</div>
</div>
<div class="task-deleted">
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="is-deleted task-content">item content 1</span>
<span><i class="iconfont icon-remove"></i></span>
<span><i class="iconfont icon-undo"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="is-deleted task-content">item content 1</span>
<span><i class="iconfont icon-remove"></i></span>
<span><i class="iconfont icon-undo"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="is-deleted task-content">item content 1</span>
<span><i class="iconfont icon-remove"></i></span>
<span><i class="iconfont icon-undo"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="is-deleted task-content">item content 1</span>
<span><i class="iconfont icon-remove"></i></span>
<span><i class="iconfont icon-undo"></i></span>
</div>
<div class="task-item">
<span><input type="checkbox" /></span>
<span class="is-deleted task-content">item content 1</span>
<span><i class="iconfont icon-remove"></i></span>
<span><i class="iconfont icon-undo"></i></span>
</div>
</div>
<!-- 清单列表结束 -->
</div>
<!-- 总容器结束 -->
</body>
</html>
```
```css
* {
margin: 0;
padding: 0;
outline: none;
-webkit-transition: background 200ms;
-moz-transition: background 200ms;
-ms-transition: background 200ms;
-o-transition: background 200ms;
transition: background 200ms;
}
body {
background: #00334b;
color: #fff;
}
h1.myTitle {
text-align: center;
margin: 20px;
}
.container {
margin: 0 auto;
/* background: red; */
max-width: 600px;
}
.task-item {
background: #fff;
color: #333;
margin-bottom: 3px;
cursor: pointer;
padding: 10px;
border-radius: 3px;
}
.task-item:hover {
background: #ddd;
}
.iconfont {
float: right;
margin-right: 10px;
line-height: 21px;
}
input[type="text"] {
background: #ddd;
float: left;
width: 84%;
margin-right: 1%;
padding: 10px;
-moz-box-sizing: border-box; /*Firefox3.5+*/
-webkit-box-sizing: border-box; /*Safari3.2+*/
-o-box-sizing: border-box; /*Opera9.6*/
-ms-box-sizing: border-box; /*IE8*/
box-sizing: border-box;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
}
input[type="text"]:focus,
input[type="text"]:hover {
background: #eee;
}
.add-task button {
width: 15%;
background: rgb(3, 174, 255);
}
.add-task button:hover {
background: rgb(77, 195, 251);
}
input[type="text"],
.add-task button {
border: 0;
height: 100%;
}
.add-task {
height: 37px;
}
.task-done .task-item {
background: #ccc;
}
.task-deleted .task-item:hover {
background: #ddd;
}
.task-done .task-item:hover {
background: #fff;
}
.task-deleted .task-item {
background: #a9a7a7;
}
.task-done,
.task-deleted,
.task-list {
margin: 10px 0;
}
.task-done .task-content,
.is-deleted {
text-decoration: line-through;
}
.task-deleted input[type="checkbox"] {
visibility: hidden;
}
input,
button {
border-radius: 3px;
}
.task-content {
margin-left: 5px;
}
.iconfont:hover {
filter: drop-shadow(0 0 0 black);
}
```
```javascript
// 相当于$(document).ready(), html代码, 加载完之后执行, 不会出现找不到对象的情况
$(function() {
// 变量初始化, 判断, 如果缓存里有数据, 取出到aTaskList, 注意缓存需要解析, 否则直接取是一个字符串
// 不管有没有数据, aTaskList都是数组, 我们下面操作的就是数组
if (localStorage.getItem("task-list")) {
// 解析用的是JSON.parse
var aTaskList = JSON.parse(localStorage.getItem("task-list"));
} else {
// 如果缓存中没有数据, 则直接空数组
var aTaskList = [];
}
// 展示html代码包裹以后的数据, 刷新内容区
// 进入页面的时候会调一次, 更新数组和缓存后, 也会调用
showTask();
// 监听输入框的回车事件, 获取输入框的内容, 更新数组, 更新缓存, 刷新内容区
$(".add-task input[name=content]").on("keypress", function(ev) {
// 先判断, 回车, 并且输入框里有内容, 则进行逻辑操作(往下走)
// 回车的keyCode的是13, 使用===来比较
if (ev.keyCode === 13 && $(this).val()) {
// 声明一个对象, 用来存储输入框里的内容(content)
// 还有其他的属性
// isDel, 用来标记是否逻辑删除, 1 for yes, 0 for no
// isDone, 用来标记是否已完成, 1 for yes, 0 for no
var oTaskItem = {
content: compressContent($(this).val()), // 存储input框里的内容, compressContent函数, 压缩内容, 超过长度加···
isDel: 0, // 标记已删除
isDone: 0 // 标记已完成
};
updateData(oTaskItem); // 更新数组, 更新缓存, 刷新内容区
// 清空input输入区的内容
$(this).val("");
}
});
$(".add-task button").on("click", function() {
if ($(".add-task input[name=content]").val()) {
// 声明一个对象, 用来存储输入框里的内容(content)
// 还有其他的属性
// isDel, 用来标记是否逻辑删除, 1 for yes, 0 for no
// isDone, 用来标记是否已完成, 1 for yes, 0 for no
var oTaskItem = {
content: compressContent(
$(".add-task input[name=content]").val()
), // 存储input框里的内容, compressContent函数, 压缩内容, 超过长度加···
isDel: 0, // 标记已删除
isDone: 0 // 标记已完成
};
updateData(oTaskItem); // 更新数组, 更新缓存, 刷新内容区
// 清空input输入区的内容
$(".add-task input[name=content]").val("");
}
});
// 更新内容区
// 数组和缓存变化后, 会调用, 刷新页面也会调用
function showTask() {
// 为什么置空(初始值为空字符串), 因为后面是追加, 所以追加之前, 内容最好为空, 其他特殊需求另说
// 保持数据类型一致, 是个好习惯, 通过给初始值, 来确定变量的数据类型
// 这里如果不给初始值, 会出现undefined字符串
var doneHTML = ""; // 已完成内容区的html代码
var taskHTML = ""; // 未完成内容区的html代码
var delHTML = ""; // 已删除内容区的html代码
console.log(aTaskList);
// forEach遍历数组, 参数是一个函数, 函数有两个参数, 一个是value, 一个是key, 注意一下顺序问题, value在前, key在后
aTaskList.forEach(function(value, key) {
// 动态拼接html, 然后写入
if (!value.isDone && !value.isDel) {
// 未完成时, 进入
taskHTML += '<div index="' + key + '" class="task-item">';
taskHTML +=
'<span><input index="' +
key +
'" type="checkbox" /></span>' +
"\n"; // 为什么有个\n, 为了保证和原来的html一致, 这个并不是必须的
taskHTML +=
'<span class="task-content">' + value.content + "</span>";
taskHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-del"></i></span>';
taskHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-edit"></i></span>';
taskHTML += "</div>";
}
if (value.isDone && !value.isDel) {
// 已完成, 进入
doneHTML += '<div index="' + key + '" class="task-item">'; // key的目的: key是对象在数组中的下标, 用来标记对象在数组中的位置
doneHTML +=
'<span><input checked index="' +
key +
'" type="checkbox" /></span>' +
"\n";
doneHTML +=
'<span class="task-content">' + value.content + "</span>";
doneHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-del"></i></span>';
doneHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-edit"></i></span>';
doneHTML += "</div>";
}
if (value.isDel) {
// 已删除, 进入
delHTML += '<div index="' + key + '" class="task-item">';
delHTML +=
'<span><input index="' +
key +
'" type="checkbox" /></span>';
// 加删除线, 方式二, 直接判断, 修改html
if (value.isDone) {
delHTML +=
'<span class="task-content is-deleted">' +
value.content +
"</span>";
} else {
delHTML +=
'<span class="task-content">' +
value.content +
"</span>";
}
delHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-remove"></i></span>';
delHTML +=
'<span><i index="' +
key +
'" class="iconfont icon-undo"></i></span>';
delHTML += "</div>";
}
});
$(".task-done").html(doneHTML); // 写入"已完成区"的html代码, 原来的都覆盖了
$(".task-list").html(taskHTML); // 写入"未完成区"的html代码, 原来的都覆盖了
$(".task-deleted").html(delHTML); // 写入"已删除区"的html代码, 原来的都覆盖了
// 监听复选框
$("input[type=checkbox]").click(function() {
if (!$(this).attr("checked")) {
// 未选中状态 ==> 已选中, 修改对象属性, isDone ==> 1
aTaskList[$(this).attr("index")]["isDone"] = 1; // 实际上更新了的数组
} else {
// 已选中状态 ==> 未选中, 修改对象属性, isDone ==> 0
aTaskList[$(this).attr("index")]["isDone"] = 0; // 实际上更新了的数组
}
updateData(); // 牵涉到方法重载, 参数个数不同, 干不同的事
});
// 监听未完成区的删除按钮(小垃圾桶)
$(".task-item .icon-del").on("click", function() {
// 修改当前对象的isDel属性为1
aTaskList[$(this).attr("index")]["isDel"] = 1;
// 改为1之后, html代码也要相应的改变
updateData();
});
// 监听已删除区的还原按钮
$(".task-deleted .icon-undo").on("click", function() {
// 修改当前对象的isDel属性为1
aTaskList[$(this).attr("index")]["isDel"] = 0;
// 改为1之后, html代码也要相应的改变
updateData();
});
// 监听已完成区的删除按钮
$(".task-done .icon-del").on("click", function() {
// 修改当前对象的isDel属性为1
aTaskList[$(this).attr("index")]["isDel"] = 1;
// 改为1之后, html代码也要相应的改变
updateData();
});
}
// 内容压缩, 如果超过30个, 就截取30, 加上省略号, 如果不超过30, 原路返回
function compressContent(str) {
if (str.length >= 30) {
return str.slice(0, 30) + "···";
} else {
return str;
}
}
// 组合操作, 更新数组, 更新缓存, 更新html内容
function updateData(obj) {
if (arguments.length) {
// 把对象添加到数组, unshift, 保证最后添加的, 在第一个
aTaskList.unshift(obj);
}
// 更新完数组, 更新缓存, 保持数组中的数据和缓存中一致
localStorage.setItem("task-list", JSON.stringify(aTaskList));
// 刷新内容区
showTask();
// // 动态添加删除线(方式一)
// aTaskList.forEach(function(value, key) {
// if (value.isDone) {
// $(".task-item[index=" + key + "] .task-content").addClass("is-deleted");
// }
// });
}
});
```
# 请问大家几个问题
1. 中文和英文长度不一致, 怎么办?
2. 压缩后, 最后一个字符恰好是标点, 怎么办?
3. 对象加入数组时, 如果用 push, 在展示时, 如何让最后添加的对象, 第一个展示?
4. 能不能, 把删除内容区域的已完成和未完成进行分组呢? 比如已完成在上, 未完成在下?
- 每日单词
- JavaScript 入门
- JavaScript 基础
- JavaScript 基础回顾
- JavaScript 函数
- 匿名函数,多维数组,数据类型转换
- JavaScript 类型转换, 变量作用域
- js 运算符(一)
- js 运算符(二)
- js 流程控制语句
- JavaScript 扫盲日
- JavaScript 牛刀小试(一)
- JavaScript 牛刀小试(二)
- JavaScript 再谈函数
- JavaScript-BOM
- JavaScript-定时器(一)
- JavaScript-定时器(二)
- 番外-轮播图源码
- JavaScript 轮播图和 DOM 简介
- JavaScript-DOM 基础-NODE 接口-属性
- JavaScript-DOM 基础-NODE 接口-方法
- NodeList-接口-HTMLCollection-接口
- Document 节点
- CSS 复习与扩展(一)
- CSS 复习与扩展(二)
- 走进 jQuery 的世界
- 使用 jquery
- 使用 jquery-2
- jquery 中高级
- jquery 备忘清单-1
- jquery 备忘清单-2
- 聊聊 json
- jquery 备忘清单-3