[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

這是原來的, 現在我復制`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>
```
結果就變成了這樣...

然后, 我們為每一塊分配一個`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>
```
這個時候再刷新...

樣式錯了...
再來調調樣式...
```css
.task-list,
.task-done,
.task-deleted {
margin: 10px 0;
}
```

現在就恢復正常了, 不過背景應該區分開...
```css
.task-done .task-item {
background: #ccc;
}
.task-deleted .task-item {
background: #a0a0a0;
}
```

我們還需要給`已完成`加上刪除線
```css
.task-done .task-content {
text-decoration: line-through;
}
```

`已完成` 不應該都是打鉤的嗎?
```html
<span><input checked type="checkbox" /></span>
```

`已完成`不應該有編輯按鈕吧, 點擊 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>
```

垃圾桶那一塊, `編輯`應該改成`還原`吧, 點擊`還原`, 哪來的回哪去, 點擊`刪除`,`徹底刪除`
看來我們需要新的圖標...

```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>
```

又要重新下載, 新增一個也需要全部再選擇一遍? 豈不是很麻煩?
是需要重新下載, 但是不麻煩, 因為阿里圖標支持新建項目, 來管理圖標

當然, 你也可以, 在原有`iconfont.css`的基礎上, 加上新的 css`iconfont.css`

前提是, 類名不要重復...


如果兩個圖標, 都叫`remove`, 但是內容不同怎么辦呢?
改 class 就好...

回收站不應該有`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>
```

又對不齊了... 
試試 css 的`visibility: hidden;`?
```css
.task-deleted input[type="checkbox"] {
visibility: hidden;
}
```

完美 
不過... 貌似`已完成`的 hover 背景, 不是很明顯...

```css
.task-done .task-item:hover {
background: #fffafa;
}
```

這回好多了...
到目前為止, 樣式就調理的差不多了, 不過眼尖的同學可能會發現, 文字和圖標, 好像不在一條直線上...

因為文字和圖標的行高不一致...


設置一致的行高即可
```css
.iconfont {
float: right;
margin-right: 10px;
line-height: 21px;
}
```

# 開始 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");
}
});
```

沒有問題...
然后我們開始改對象
先寫一個改對象的函數...
```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();
});
}
```

成功!!!
試了一下`取消完成`功能, 也是可以的

現在`未完成`和`已完成`的互轉已經實現了!!!
接下來是未完成和`邏輯刪除`的互轉
在`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);
}
});
// 代碼省略...
```
試一下效果

沒有問題...
然后, 同理, 是被刪除 task 的還原
```javascript
// 監聽已刪除的還原按鈕
$(".task-deleted .icon-undo").on("click", function() {
changeObj($(this).attr("index"), "isDel", 0);
showTask();
});
```
其他代碼不用改, 試了一下, 也沒有問題...

現在就剩下, 已完成和刪除的互轉了, 加油!!!
首先, 我們需要給`已完成`并且`已刪除`的 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;
}
```
我們看一下效果...

前三項是有刪除線的
那么我們現在可以寫 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 的注釋去掉, 然后看一下效果...
沒有問題

試試還原? 也沒有問題!

最后, 請大家思考一個問題
如下圖

能不能, 把刪除內容區域的`已完成`和`未完成`進行分組呢? 比如`已完成`在上, `未完成`在下?
機智如你, 一定會有答案的!!! 
最后, 完整代碼
```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