界面如下图所示:
暂且不说UI,谈谈已实现的功能:
1. 添加计划
2. 修改计划状态
3. 删除计划
4. 缓存数据
源代码如下:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ToDoList</title>
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div class="box">
<div class="header">
<h1>TodoList</h1>
<div class="header-right">
<input type="text" id="input" placeholder="今天要做什么?" />
<button id="header-right-button">添加</button>
</div>
</div>
<div class="content">
<h2>未完成</h2>
<ul id="todo">
</ul>
<h2>已完成</h2>
<ul id="finish">
</ul>
</div>
</div>
<script type="text/javascript" src="./index.js"></script>
</body>
</html>
style.css
* {
margin: 0;
border: 0;
}
body {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
min-height: 100vh;
background-color: #eeeeee;
}
.box {
width: 35%;
height: 300px;
background-color: white;
}
.header {
display: inline-flex;
color: #007acc;
width: 100%;
height: 50px;
position: relative;
border: 2px solid #007acc;
border-radius: 5px 5px 0px 0px;
background-color: white;
}
.header>h1 {
margin-left: 5px;
margin-top: 5px;
}
.header-right {
width: 70%;
margin-left: auto;
height: 50px;
}
#input {
background-color: white;
border: 1px solid #007acc;
width: 80%;
height: 40px;
margin-top: 5px;
margin-left: 5px;
border-radius: 5px;
box-sizing: border-box;
outline: none;
padding-left: 5px;
padding-right: 5px;
}
#header-right-button {
height: 40px;
width: 15%;
border-radius: 5px;
background-color: white;
border: 1px solid #007acc;
outline: none;
}
.content {
width: 100%;
border: 2px solid #007acc;
border-top: 0;
padding-bottom: 10px;
border-radius: 0px 0px 5px 5px;
background-color: white;
}
.content h2 {
color: #007acc;
margin: 5px;
margin-top: 0;
font-weight: 400;
}
ul {
width: 100%;
min-height: 100px;
}
li {
display: inline-flex;
border: 1px solid #007acc;
height: 40px;
width: 93%;
margin-left: -5%;
padding-left: 5px;
padding-right: 5px;
border-left: 5px solid #007acc;
position: relative;
border-radius: 5px;
margin-bottom: 5px;
}
li>input {
position: relative;
top: 25%;
height: 1.5em;
width: 1.5em;
margin-right: 5px;
}
li>p {
font-size: 16px;
line-height: 40px;
color: #252526;
}
li>img {
width: 25px;
height: 25px;
margin-top: 7.5px;
margin-left: auto;
}
index.js
/*
* author: sweet
* date: 2021年8月24日
* descript: 实现一个简易的ToDoList
* */
let ul_todo = document.getElementById("todo");
let ul_finish = document.getElementById("finish");
let inputPlan = document.getElementById("input");
let buttonPlan = document.getElementById("header-right-button");
/*
* 添加计划
* @param {localStorage中的key} e
* @param {计划内容} text
* @param {计划完成状态} status
*/
function sw_addPlan(e, text, status) {
let todoText;
let date;
if (e) { // 非首次加载,赋参数值
date = e;
todoText = text;
} else { // 首次加载赋新值
todoText = inputPlan.value;
if (!todoText) {
return;
}
date = "sweet-" + Date.now();
}
let li = document.createElement("li");
let input = document.createElement("input");
let p = document.createElement("p");
let img = document.createElement("img");
li.id = date;
input.type = "checkbox";
input.className = "checkbox";
p.className = "todo-text";
p.innerHTML = todoText;
img.src = "./resources/trash.png";
img.className = "deletePlan";
input.addEventListener("change", sw_handleChange);
img.addEventListener("click", sw_deletePlan);
if (status) {
ul_finish.appendChild(li);
input.checked = true;
} else {
ul_todo.appendChild(li);
}
li.appendChild(input);
li.appendChild(p);
li.appendChild(img);
if (!e) {
let storageData = {
text: todoText,
finished: false
}
localStorage.setItem(date, JSON.stringify(storageData));
}
if (localStorage.getItem("firstLoad") === 'true') {
localStorage.setItem("firstLoad", false);
}
}
/*
* 处理输入框事件
*/
function sw_handleSubmit() {
sw_addPlan();
inputPlan.value = ''; //清空输入框
}
/*
* 处理复选框状态修改
*/
function sw_handleChange(e) {
//得到复选框的父节点,然后把它加给finish
let li = e.target.parentNode;
let ul = li.parentNode.id;
let p_node = li.children[1];
let data = {
text: p_node.innerHTML,
finished: true
}
if (ul === 'todo') {
ul_todo.removeChild(li);
ul_finish.appendChild(li);
} else {
ul_finish.removeChild(li);
ul_todo.appendChild(li);
data.finished = false;
}
localStorage.setItem(li.id, JSON.stringify(data));
}
/*
* 处理添加计划按钮点击事件
*/
function sw_handleClick() {
sw_addPlan();
inputPlan.value = ''; //清空输入框
}
/*
* 删除计划
*/
function sw_deletePlan(e) {
let li = e.target.parentNode;
let ul = li.parentNode.id;
if (ul === 'todo') {
ul_todo.removeChild(li);
} else {
ul_finish.removeChild(li);
}
localStorage.removeItem(li.id); //也要从localStorage中删除
}
/*
* 监听键盘按下
*/
function debounce(fn) {
let timeout = null;
return function () {
clearTimeout(timeout);
timeout = setTimeout(() => {
fn.call(this, arguments);
}, 200);
}
}
/*
*处理键盘按下
*/
function handleEnter(args) {
let e = args[0];
if (e.keyCode === 13) {
sw_handleSubmit();
}
}
/**
* 判断页面是否重加载,便于用户刷新页面后值仍存在
*/
function sw_firstLoad() {
if (localStorage.getItem("firstLoad") === 'false') { //页面重新加载
for (let i = 0; i < localStorage.length; i++) { //将localStorage中的值给页面
let key = localStorage.key(i);
if (key.indexOf("sweet") !== -1) { //拿到存储数据
let data = JSON.parse(localStorage.getItem(key));
sw_addPlan(key, data.text, data.finished);
}
}
inputPlan.value = ''; //清空输入框
} else { //首次加载页面为空
localStorage.setItem("firstLoad", true);
}
}
sw_firstLoad();
inputPlan.addEventListener("keydown", debounce(handleEnter));
buttonPlan.addEventListener("click", sw_handleClick);
代码中用到了一个图片资源trash.png,需要源代码的可以在github或csdn资源处自取: