todolist
代码如下,使用的是rem布局,按照375px的设计稿,锻炼一下rem布局的使用
布局结构:
<div class="main">
<div class="header">
<div class="logo">MyTodo</div>
<input type="text" placeholder="请输入待办事项" id="myInput">
</div>
<div class="doing todo">
<h3><span class="title">正在进行</span><span class="num">0</span></h3>
<div class="list">
</div>
</div>
<div class="done todo">
<h3><span class="title">已完成</span><span class="num">0</span></h3>
<div class="list">
</div>
</div>
</div>
css:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #f1f1f1;
font-size: 16px;
}
.main {
width: 3.75rem;
}
.header {
width: 3.75rem;
height: 0.5rem;
background-color: aquamarine;
display: flex;
justify-content: space-between;
align-items: center;
}
.header>.logo {
width: 1.2rem;
height: 0.5rem;
text-align: center;
line-height: 0.5rem;
font-size: 0.25rem;
font-weight: 900;
}
.header>input {
width: 2.2rem;
height: 0.3rem;
margin: 0 0.2rem;
border-radius: 0.05rem;
border: none;
outline: none;
padding: 0 0.1rem;
}
.todo h3 {
display: flex;
justify-content: space-between;
align-items: center;
height: 0.6rem;
line-height: 0.6rem;
padding: 0 0.1rem;
}
.todo .list {
padding: 0 0.1rem;
}
.todo .todoItem {
display: flex;
align-items: center;
height: 0.38rem;
margin: 0.05rem 0;
background-color: rgb(187, 209, 248);
border-left: 0.03rem solid green;
border-radius: 0.05rem;
overflow: hidden;
}
.todo .todoItem>input {
width: 0.25rem;
height: 0.25rem;
margin: 0 0.15rem;
}
.todo .todoItem>.content {
width: 2.5rem;
}
.todo .todoItem>.delete {
background-color: rgb(233, 149, 54);
padding: 0.02rem 0.05rem;
border-radius: 0.1rem;
cursor: pointer;
}
.done .todoItem {
opacity: 0.3;
/* 利用滤镜 */
-webkit-filter: grayscale(1);
}
接下来就是比较重要的js代码。
先不考虑本地存储。大体思路就是:所有的事件列表都存放在一个数组中,无论是删除,还是添加,或者已完成事件与未完成时间的切换,都是对该数组中每一个对象或对象的属性进行修改。
添加: 获取输入框内的内容,添加到数组中,重新渲染,清空输入框。
切换: 使用事件代理,监听change事件,通过自定义的data-index属性获取到勾选的是数组中的哪一个对象,并修改其isDone属性值。重新渲染。
删除: 同样使用事件代理,监听click事件,但不是所有的点击都触发,只有当点击了删除按钮那个div才会触发,获取到自定义的data-index通过数组的splice方法删除当前点击的对象,重新渲染。
渲染操作: 清除原来的内容,循环事件数组,判断每个对象的isDone属性值为ture还是false。若为true:说明是已完成事件,添加到已完成事件列表中;若为false,则相反。
基本代码如下:
<script>
var html = document.querySelector('html');
var myInput = document.querySelector('#myInput');
var doingList = document.querySelector('.doing .list');
var doneList = document.querySelector('.done .list');
var mainDiv = document.querySelector('.main'); //找到mian这个div,用于删除功能的事件委托
var todoList = []; //专门用来存储所有事项,包括完成与未完成
function setRem() {
var screenWidth = window.innerWidth; //获取屏幕宽
var rem1 = screenWidth / 3.75; //屏幕的宽度/设计稿占满全屏幕所需的rem数量,就可以得到1rem为多少像素。
html.style.fontSize = rem1 + 'px';
};
//用来将todoList数组中的所有待办事件对象渲染到界面中
function render() {
// 每次渲染之前先清除原来的内容
doingList.innerHTML = '';
doneList.innerHTML = '';
//循环所有事件列表,判断是否完成,添加到不同的列表中
todoList.forEach(function(item, index) {
var doDiv = document.createElement('div');
doDiv.className = 'todoItem';
if (item.isDone) {
//已完成事件列表
doDiv.innerHTML = `
<input type="checkbox" checked data-index="${index}">
<div class="content">${item.content}</div>
<div class="delete" data-index="${index}">删除</div>
`
doneList.appendChild(doDiv);
} else {
// 未完成事件列表
doDiv.innerHTML = `
<input type="checkbox" data-index="${index}">
<div class="content">${item.content}</div>
<div class="delete" data-index="${index}">删除</div>
`
doingList.appendChild(doDiv);
}
})
}
setRem();
window.onresize = function() {
setRem();
};
//监听输入,输入回车的时候,获取输入框内容并添加到正在进行列表中
myInput.addEventListener('keyup', function(e) {
if (e.key == 'Enter') {
//这个对象用来存储新添加的事项,
var obj = {
content: myInput.value,
isDone: false
};
todoList.push(obj); //将新的事项添加到数组中
render();
myInput.value = '';
}
});
// 使用事件代理,通过在渲染列表时自定义的data-index属性,来获取到当前点击的是第几个事件,也就是获取索引值
doingList.addEventListener('change', function(e) {
var index = parseInt(e.target.dataset.index); //获取索引值,因为是字符串,所以需要取整
todoList[index].isDone = true;
render();
});
doneList.addEventListener('change', function(e) {
var index = parseInt(e.target.dataset.index); //获取索引值,因为是字符串,所以需要取整
console.log(index);
todoList[index].isDone = false;
render();
});
//删除功能
mainDiv.addEventListener('click', function(e) {
var index = parseInt(e.target.dataset.index);
//只有当点击的是删除按钮,也就是删除那个div时,才会进行下一步操作。
if (e.target.className == 'delete') {
todoList.splice(index, 1);
render();
}
})
</script>
接下来考虑本地存储。
其实也不复杂,想要将数据存到本地,只需要在render函数中为localStorage添加一个属性,值为todoList这个数组即可。
但是要注意,本地存储只能存字符串形式,不能存储对象数组,因此需要将其转化为json字符串,取出时也是同样的道理,做相反操作。
最后再加上数值的控制逻辑,完整的代码如下:
<script>
var html = document.querySelector('html');
var myInput = document.querySelector('#myInput');
var doingList = document.querySelector('.doing .list');
var doneList = document.querySelector('.done .list');
var doingNum = document.querySelector('.doing .num');
var doneNum = document.querySelector('.done .num');
var mainDiv = document.querySelector('.main'); //找到mian这个div,用于删除功能的事件委托
//判断本地存储中是否已经存在数据
if (localStorage.todoList == undefined) {
var todoList = []; //专门用来存储所有事项,包括完成与未完成
} else {
var todoList = JSON.parse(localStorage.todoList); //将json字符串转换为对象
render();
}
function setRem() {
var screenWidth = window.innerWidth; //获取屏幕宽
var rem1 = screenWidth / 3.75; //屏幕的宽度/设计稿占满全屏幕所需的rem数量,就可以得到1rem为多少像素。
html.style.fontSize = rem1 + 'px';
};
//用来将todoList数组中的所有待办事件对象渲染到界面中
function render() {
//将事件列表放到本地存储中,因为本次存储只能存储字符串,因此json可以很好的解决这个问题
localStorage.todoList = JSON.stringify(todoList); //将json对象转化为字符串
// 每次渲染之前先清除原来的内容
doingList.innerHTML = '';
doneList.innerHTML = '';
doingNum.innerHTML = 0;
doneNum.innerHTML = 0;
//循环所有事件列表,判断是否完成,添加到不同的列表中
todoList.forEach(function(item, index) {
var doDiv = document.createElement('div');
doDiv.className = 'todoItem';
if (item.isDone) {
//已完成事件列表
doDiv.innerHTML = `
<input type="checkbox" checked data-index="${index}">
<div class="content">${item.content}</div>
<div class="delete" data-index="${index}">删除</div>
`
doneList.appendChild(doDiv);
doneNum.innerHTML = parseInt(doneNum.innerHTML) + 1;
} else {
// 未完成事件列表
doDiv.innerHTML = `
<input type="checkbox" data-index="${index}">
<div class="content">${item.content}</div>
<div class="delete" data-index="${index}">删除</div>
`
doingList.appendChild(doDiv);
doingNum.innerHTML = parseInt(doingNum.innerHTML) + 1;
}
})
}
setRem();
window.onresize = function() {
setRem();
};
//监听输入,输入回车的时候,获取输入框内容并添加到正在进行列表中
myInput.addEventListener('keyup', function(e) {
if (e.key == 'Enter') {
//这个对象用来存储新添加的事项,
var obj = {
content: myInput.value,
isDone: false
};
todoList.push(obj); //将新的事项添加到数组中
render();
myInput.value = '';
}
});
// 使用事件代理,通过在渲染列表时自定义的data-index属性,来获取到当前点击的是第几个事件,也就是获取索引值
doingList.addEventListener('change', function(e) {
var index = parseInt(e.target.dataset.index); //获取索引值,因为是字符串,所以需要取整
todoList[index].isDone = true;
render();
});
doneList.addEventListener('change', function(e) {
var index = parseInt(e.target.dataset.index); //获取索引值,因为是字符串,所以需要取整
console.log(index);
todoList[index].isDone = false;
render();
});
//删除功能
mainDiv.addEventListener('click', function(e) {
var index = parseInt(e.target.dataset.index);
//只有当点击的是删除按钮,也就是删除那个div时,才会进行下一步操作。
if (e.target.className == 'delete') {
todoList.splice(index, 1);
render();
}
})
</script>