前言
码上掘金月赛又又又又开始了,我又来参加了,这次的赛题分为动画和 Todolist
。这两个赛题方向其实都可以试试,不过我最后还是选择了 Todolist
,主要是因为动画做过太多次了,Todolist
没有做过。
因此本文将手把手教你如何实现一个高级且不复杂的 Todolist
。
码上掘金
下面是 Todolist
的最终效果,辛苦各位给我的作品点个赞👍吧~
Todolist 结构
大体结构如下所示。
往大了说,总共分为主体部分和完成任务框部分两个部分;往小了说,可以分为四个部分,主题选择,轮播文字,添加任务框以及完成任务框。接下来我们将会从这几个部分分别介绍。
主体部分
主体部分由主题选择、轮播文字、添加任务构成,包含网页标题和一些提示信息,以及更换主题和添加任务的功能。其实在主体部分,还有一个隐藏模块:待办事项列表,用于展示待完成的任务,每个任务包含一个图标、任务内容、定时器、收藏和删除功能。
主题选择
我设定了一个默认主题颜色和四个自选主题颜色,增加主题颜色选择是为了丰富 Todolist
的个性化设置,让它看起来不那么单调。下面是相关代码,关于 css 部分这里不展示,大家可以前往码上掘金查看,我们主要介绍是如何实现切换主题的。
<div class="right-header">
<span>Happy-day</span>
<select class="theme">
<option value="">更换主题</option>
<option value="1">水蜜桃汽水</option>
<option value="2">珊瑚莓果</option>
<option value="3">抹茶牛油果</option>
<option value="4">雾霾潮汐</option>
</select>
</div>
//获取切换主题的select节点
let changeTheme = document.querySelector('.theme');
changeTheme.onchange = function() {
let theme = changeTheme.value;
let top = document.querySelector('.top');
let done = document.querySelector('.done-list');
if(theme == 1) {
top.style.backgroundColor = '#de907b';
done.style.backgroundColor = '#e6c5b4';
changeTheme.style.backgroundColor = '#de907b'
} else if(theme == 2) {
top.style.backgroundColor = '#c2858a';
done.style.backgroundColor = '#e1b2b1';
changeTheme.style.backgroundColor = '#c2858a';
}else if(theme == 3) {
top.style.backgroundColor = '#85b892';
done.style.backgroundColor = '#588d6a';
changeTheme.style.backgroundColor = '#85b892';
}else if(theme == 4) {
top.style.backgroundColor = '#93c4d4';
done.style.backgroundColor = '#4a87a1';
changeTheme.style.backgroundColor = '#93c4d4';
}
}
在这一部分我们使用了 select 下拉菜单标签,下拉菜单中有四个选项,分别是水蜜桃汽水、珊瑚莓果、抹茶牛油果和雾霾潮汐,用于更换 Todolist
主题。
然后通过 js 代码来实现主题切换的功能。当页面上的主题 changeTheme 的值发生变化时,会触发该函数的执行。函数首先获取当前选中的主题值 theme,然后根据不同的主题值,改变页面上的顶部和已完成列表的背景颜色,以及主题下拉框的背景颜色。比如说,当主题值为 1 时,顶部的背景颜色为淡橙色,已完成列表的背景颜色为浅粉色,主题下拉框的背景颜色也为淡橙色,后续以此类推。
轮播文字
在 Todolist
里添加轮播文字的效果和添加主题选择的效果是一致的,都是为了丰富 Todolist
。
<div class="line">
<ul id="pao">
<li>每天一个TodoList</li>
<li>二十一天一个习惯</li>
<li>让我们之后顶峰相见</li>
<li>每天一个TodoList</li>
</ul>
</div>
father();
var speed = 0;
function father() {
var pao = document.getElementById('pao');
var time = setInterval(() => {
pao.style.top = -(speed += 1) + 'px';
if(speed >= 60) {
speed = 0;
}
}, 150)
pao.onmouseover = function() {
clearInterval(time);
}
pao.onmouseout = function() {
father();
}
}
我们定义一个 father 函数,该函数获取 id 为 pao 的元素,即我们需要轮播的文字,然后使用 setInterval 函数每 150 毫秒将该元素的 top 属性设置为当前速度,初始速度为 0,速度每次加 1,直到达到 60 后重新设置为 0。同时,该函数还添加了鼠标移入和移出事件,当鼠标移入时,清除定时器,当鼠标移出时,重新调用 father 函数,即重新开始动画,这样带来的效果就是当鼠标放在轮播文字上时就会暂停轮播,移开便会重新开始。
添加任务
在这一部分,创建了一个节点模板,用于复制添加的待办事项。这样就可以将创建好的任务加入到下面即将提到的待办事项列表当中。
<div class="new-task">
<div class="add" onclick="put()">
<img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1704ba71b63043b5b3dd80241be7ff46~tplv-k3u1fbpfcp-watermark.image?">
</div>
<input id="input" type="text" placeholder="Add Task">
</div>
function put() {
let newTask = input.value;
let tempLate = document.querySelector('.todo-template');
let newTaskContainer = tempLate.cloneNode(true);
let newTaskNode = newTaskContainer.querySelector('.todo-item');
newTaskNode.querySelector('.todo-text').innerText = newTask;
let fistToDo = document.querySelector('.todo-list .todo-item');
if(newTask.trim() == '') {
alert('输入内容不能为空!!!')
} else {
document.querySelector('.todo-list').insertBefore(newTaskNode, fistToDo);
}
input.value = '';
let state = 0;
let icon = newTaskNode.querySelector('.todo-icon');
icon.onclick = function() {
if(icon.src.includes('9514554df20f460eb495b00589805c37')) {
state = 1;
icon.setAttribute('src', 'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b0bde014a51b46e6a7f6c320f550f552~tplv-k3u1fbpfcp-watermark.image?')
let todoText = icon.parentElement.parentElement.querySelector('.todo-text');
todoText.style.textDecoration = 'none';
newTaskNode.style.backgroundColor = '#cecbcc';
let fistToDo = document.querySelector('.todo-list .todo-item');
document.querySelector('.todo-list').insertBefore(icon.parentElement.parentElement, fistToDo);
let fatherNode = icon.parentElement.parentElement;
let childNode = fatherNode.querySelector('.timer')
childNode.style.display = 'block';
} else {
state = 2;
icon.setAttribute('src', 'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9514554df20f460eb495b00589805c37~tplv-k3u1fbpfcp-watermark.image?')
let todoText = icon.parentElement.parentElement.querySelector('.todo-text');
todoText.style.textDecoration = 'line-through';
newTaskNode.style.backgroundColor = '#fffecf';
document.querySelector('.done-list').appendChild(icon.parentElement.parentElement);
let fatherNode = icon.parentElement.parentElement;
let childNode = fatherNode.querySelector('.timer')
childNode.style.display = 'none';
}
};
let col = document.querySelector('.collect img');
col.onclick = function() {
if(col.src.includes('e5798c2f760a47d994abe68479dfadd1')) {
col.setAttribute('src', 'https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1b3748852f9e41668db4315fd29327d5~tplv-k3u1fbpfcp-watermark.image?')
} else {
col.setAttribute('src', 'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e5798c2f760a47d994abe68479dfadd1~tplv-k3u1fbpfcp-watermark.image?')
}
}
let del = document.querySelector('.delete');
del.onclick = function() {
console.log(1);
let parentNode = newTaskNode.parentElement;
parentNode.removeChild(newTaskNode);
}
let timeSelect = document.getElementById('timerSelect');
let time = 0;
timeSelect.onchange = function() {
time = timeSelect.value;
console.log(time);
if(time != null) {
let timer = setInterval(() => {
time--;
if(time == 0) {
alert("该任务完成时间已到");
clearInterval(timer);
} else if(state == 2) {
clearInterval(timer)
}
}, 1000);
}
}
}
别看它代码多,其实内部逻辑还是比较简单的。这是一个名为 put
的函数,它的作用是向待办事项列表中添加新的任务。
首先,它获取用户输入的任务内容,并创建一个新的任务节点。如果用户输入的内容为空,则会弹出一个警告框。否则,将新任务节点插入到待办事项列表中。然后,它添加了一个切换点击事件,使得当用户点击任务图标时,可以切换任务的状态。如果任务状态为已完成,则将任务节点从待办事项列表中移动到已完成列表中。如果任务状态为未完成,则将任务节点移回待办事项列表中。
接下来,它添加了一个收藏点击事件,使得当用户点击收藏图标时,可以切换收藏状态。然后,它添加了一个删除点击事件,使得当用户点击删除图标时,可以删除该任务节点。最后,它添加了一个时间选择器,这里有点像前面我们提到的主题选择器。它可以使得用户可以选择任务的完成时间。
待办事项列表
这一部分就是由上面提及到的节点模板所创建的。由于代码比较冗长,所以这里只展示其中一部分代码,其余代码大家可以前往码上掘金查看。
<div class="todo-template">
<div class="todo-item">
<div class="todo-item-icon">
<img class="todo-icon" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b0bde014a51b46e6a7f6c320f550f552~tplv-k3u1fbpfcp-watermark.image?" alt="">
</div>
<div class="todo-content">
<div class="todo-text"></div>
</div>
<div class="timer">
<img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a199ee566b954754ab31adcaf438c8ff~tplv-k3u1fbpfcp-watermark.image?" alt="">
<select class="todo-timer" id="timerSelect">
<option></option>
<option value="60">60s</option>
<option value="120">120s</option>
<option value="180">180s</option>
</select>
</div>
<div class="collect">
<img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1b3748852f9e41668db4315fd29327d5~tplv-k3u1fbpfcp-watermark.image?" alt="">
</div>
<div class="delete">
<img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/eda49ba3a6b041ffa40ee3ea16104dda~tplv-k3u1fbpfcp-watermark.image?" alt="">
</div>
</div>
</div>
这是一个待办事项的模板,包括以下几个部分:todo-item
代表一个待办事项,包含图标、内容、定时器、收藏和删除按钮。todo-item-icon
代表待办事项的图标。todo-content
代表待办事项的内容区域,包括待办事项的文字描述。timer
代表待办事项的定时器,可以设置一个时间,表示在规定的时间内完成此事项。todo-timer
代表定时器的选择器,可以选择一个时间,用来设置定时器的时间。collect
代表待办事项的收藏按钮,一般用来收藏重要的待办事项,方便查找和管理。delete
代表待办事项的删除按钮,可以删除已完成或不需要的待办事项。
然后再来介绍一下 js 部分( js 部分代码可以前往码上掘金查看)。当用户按下键盘上的键时,会执行其中的代码。其中,if 语句判断用户按下的是回车键( keyCode 为 13)。首先获取输入框中的内容,然后获取模板节点,使用 cloneNode 方法将模板节点复制一份,并添加到待办事项列表中。复制完成后,修改复制节点中的待办事项文本和删除按钮的样式。最后,判断输入内容是否为空,如果为空,则弹出提示框,否则将新节点插入到待办事项列表中,并清空输入框中的内容。下面给大家展示一下效果。
虽然 js 代码看着比较多,但是里面很多都是复用的,自己手把手将这个 Todolist
玩一下,就会发现其实实现的逻辑并不难。
总结
以上就是整个 Todolist
的实现过程了,由于代码部分比较多,所以更详细的代码可以前往码上掘金查看。看到这里,辛苦各位给我的作品点个赞👍吧~
原文链接:https://juejin.cn/post/7222305855978651705 作者:一条会coding的Shark