使用 HTML、CSS 和 Javascript 构建番茄钟计时器
在本教程中,我们将编写一个番茄钟计时器。⏲
我偶然发现了由 Amy Dutton 和 James Q Quick 为这个假期创建的 Advent Of CSS 和 Advent of JS 挑战。我决定今年参加这个小挑战,会很有趣!
以下是我在第一天挑战中所学到的知识和面临的挑战。😥
什么是番茄工作法计时器?
番茄工作法是由弗朗西斯科·西里洛于20世纪80年代末发明的一种时间管理方法。它使用一个计时器将工作时间划分成几个时间段,通常每25分钟,中间穿插一些短暂的休息。每个时间段被称为一个“番茄”,源于意大利语“番茄”,以西里洛大学时期使用过的番茄形厨房计时器命名。——维基百科
简单来说,番茄钟是一款简单的应用程序,可以帮助我们集中注意力,提高效率。它可以安排交替的工作和休息时间。
挑战规格
用户应该能够:
- 单击“开始”链接/按钮启动计时器。
- 一旦用户点击“开始”,“开始”字样将变为“停止”。然后,用户可以点击“停止”按钮来停止计时器。
- 单击齿轮图标可更改计时器的长度(分钟和秒)。
- 一旦计时器结束,环就会从红色变为绿色。
- 可以使用任何框架、库、工具,或者可以保留旧的 CSS 和 Vanilla JS。
我决定继续使用我的老朋友,纯 CSS 和 Vanilla JS 🤞🏻
那么,现在是时候编写一些代码了!
方法:HTML
我们将首先创建一个简单的 HTML 结构来显示计时器和开始/停止以及设置按钮(用于调整时间)
<div class="container">
<div class="outerRing">
<div class="timer">
<!-- Timer elements -->
</div>
</div>
</div>
Acontainer
包含计时器的所有内容。
在 里面container
,我们有两个div
。
一个用于outerRing
显示进度条。
第二个用于timer
显示倒计时、开始/停止和设置按钮。
<div id="time">
<span id="minutes">00</span>
<span id="colon">:</span>
<span id="seconds">10</span>
</div>
<div id="stsp">START</div>
<span id="setting"><i class="fas fa-cog"></i></span>
divtime
显示倒计时,带有minutes
和seconds
<span>
。
以下是完整的 HTML 代码。
<div class="container">
<div class="outerRing">
<div class="timer">
<div id="time">
<span id="minutes">00</span>
<span id="colon">:</span>
<span id="seconds">10</span>
</div>
<div id="stsp">START</div>
<span id="setting"><i class="fas fa-cog"></i></span>
</div>
</div>
</div>
方法:添加 CSS
首先,设置: root
变量。然后container
使用 将布局添加到页面的中心display: grid
。
将外圈与计时器设置为相差和容器15px
之间的圆圈。outerRing
timer
.outerRing {
display: grid;
place-items: center;
width: 415px;
height: 415px;
border-radius: 50%;
box-shadow: -5px 14px 44px #000000,
5px -16px 50px rgba(255, 255, 255, 0.15);
background: var(--normal-ring);
}
/* Width and Height difference btwn .outerRing & .timer is 15px,
where our progress bar will be displayed */
.timer {
width: 400px;
height: 400px;
border-radius: 50%;
background: var(--timer-bg);
box-shadow: inset 0px 0px 114px rgba(0, 0, 0, 0.45);
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
padding: 8rem;
}
outerRing
是我们将使用该conic-gradient()
函数显示进度条的地方。
圆锥渐变如何通过动画实现
我们将使用conic-gradient()
Javascript 中的颜色来为进度条制作动画。
以下是完整的 CSS 代码。
@import url("https://fonts.googleapis.com/css2?
family=Bebas+Neue&family=Montserrat:wght@700&display=swap");
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--bg: #2b2a30;
--normal-ring: #17171a;
--red-ring: #9d0000;
--green-ring: #00aa51;
--timer-bg: radial-gradient(
71.4% 71.4% at 51.7% 28.6%,
#3a393f 0%,
#17171a 100%
);
--font-timer: "Bebas Neue", cursive;
--font-stsp: "Montserrat", sans-serif;
--font-clr: #ffffff;
}
body {
background: var(--bg);
min-height: 100vh;
overflow: hidden;
}
.container {
height: 600px;
width: 600px;
background-color: transparent;
position: absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
display: grid;
place-items: center;
}
.outerRing {
display: grid;
place-items: center;
width: 415px;
height: 415px;
border-radius: 50%;
box-shadow: -5px 14px 44px #000000,
5px -16px 50px rgba(255, 255, 255, 0.15);
background: var(--normal-ring);
}
.timer {
width: 400px;
height: 400px;
border-radius: 50%;
background: var(--timer-bg);
box-shadow: inset 0px 0px 114px rgba(0, 0, 0, 0.45);
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
padding: 8rem;
}
#time {
width: 300px;
text-align: center;
margin: 3rem 0 0 0;
}
#time span {
display: inline;
color: var(--font-clr);
font-family: var(--font-timer);
font-size: 7rem;
letter-spacing: 0.1em;
text-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
}
#stsp {
color: var(--font-clr);
cursor: pointer;
font-family: Montserrat;
font-weight: bold;
font-size: 1rem;
line-height: 1.25rem;
text-align: center;
letter-spacing: 0.6em;
margin: 1rem 0;
text-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
}
#setting {
cursor: pointer;
margin-top: 1rem;
width: 25px;
height: 25px;
color: #585858;
box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.25);
}
方法:添加 Javascript
首先,让我们完成计时器的组成部分,如计时器显示、启动/停止按钮和设置按钮。
- 设置按钮
获取Setting
、Minutes
和Seconds
元素。同时,声明一个toggleSettings
变量来跟踪Settings
按钮的点击。
const minElem = document.querySelector("#minutes"),
secElem = document.querySelector("#seconds"),
setting = document.querySelector("#setting");
let toggleSettings = false;
处理按钮click
上的事件Settings
。此外,还要处理和元素onblur
的事件。Minutes
Seconds
setting.onclick = function () {
if (!toggleSettings) {
toggleSettings = true;
minElem.contentEditable = true;
minElem.style.borderBottom = `1px dashed #ffffff50`;
secElem.contentEditable = true;
secElem.style.borderBottom = `1px dashed #ffffff50`;
} else {
resetValues();
}
};
minElem.onblur = function () {
resetValues();
};
secElem.onblur = function () {
resetValues();
};
该函数处理为和resetValues
重新分配的值。minutes
seconds
- 开始/停止按钮
将minutes
和声明seconds
为let
变量,因为我们将操作它们来显示计时器。
const startStop = document.querySelector("#stsp");
let minutes = document.querySelector("#minutes").innerHTML,
seconds = document.querySelector("#seconds").innerHTML;
当我们点击START
按钮时,首先会检查minutes
和seconds
不等于0。然后文本将变为STOP
并调用该startStopProgress
函数。
该startStopProgress
函数将检查计时器进度并更新进度条和计时器显示。
如果是STOP
按钮,使用相同的功能清除进度并将文本改回START
。
startStop.onclick = function () {
if (startStop.innerHTML === "START") {
if (!(parseInt(minutes) === 0 && parseInt(seconds) === 0)) {
startStop.innerHTML = "STOP";
startStopProgress();
} else {
alert("Enter the Time Value in your Timer!");
}
} else {
startStop.innerHTML = "START";
startStopProgress();
}
};
- 进度条
我们将使用它setInterval()
来运行有助于跟踪进度的代码。
function startStopProgress() {
if (!progress) {
progress = setInterval(progressTrack, speed);
} else {
clearInterval(progress);
progress = null;
progressStart = 0;
progressBar.style.background = `conic-gradient(
#17171a 360deg,
#17171a 360deg
)`;
}
}
计算剩余分钟数和剩余秒数来更新计时器。
另外,根据计时器的总时间,计算计时器上的度/秒。
Degree/Second = 360 / Total time of the timer in minutes.
使用conic-gradient()
和计算出的度/秒,更新 DOM。
function progressTrack() {
progressStart++;
secRem = Math.floor((progressEnd - progressStart) % 60);
minRem = Math.floor((progressEnd - progressStart) / 60);
secElem.innerHTML = secRem.toString().length == 2 ? secRem : `0${secRem}`;
minElem.innerHTML = minRem.toString().length == 2 ? minRem : `0${minRem}`;
progressBar.style.background = `conic-gradient(
#9d0000 ${progressStart * degTravel}deg,
#17171a ${progressStart * degTravel}deg
)`;
if (progressStart == progressEnd) {
progressBar.style.background = `conic-gradient(
#00aa51 360deg,
#00aa51 360deg
)`;
clearInterval(progress);
startStop.innerHTML = "START";
progress = null;
progressStart = 0;
}
}
这是完整的 Javascript 代码,
const progressBar = document.querySelector(".outerRing"),
minElem = document.querySelector("#minutes"),
secElem = document.querySelector("#seconds"),
startStop = document.querySelector("#stsp"),
setting = document.querySelector("#setting");
let minutes = document.querySelector("#minutes").innerHTML,
seconds = document.querySelector("#seconds").innerHTML,
progress = null,
progressStart = 0,
progressEnd = parseInt(minutes) * 60 + parseInt(seconds),
speed = 1000,
degTravel = 360 / progressEnd,
toggleSettings = false,
secRem = 0,
minRem = 0;
function progressTrack() {
progressStart++;
secRem = Math.floor((progressEnd - progressStart) % 60);
minRem = Math.floor((progressEnd - progressStart) / 60);
secElem.innerHTML = secRem.toString().length == 2 ? secRem : `0${secRem}`;
minElem.innerHTML = minRem.toString().length == 2 ? minRem : `0${minRem}`;
progressBar.style.background = `conic-gradient(
#9d0000 ${progressStart * degTravel}deg,
#17171a ${progressStart * degTravel}deg
)`;
if (progressStart == progressEnd) {
progressBar.style.background = `conic-gradient(
#00aa51 360deg,
#00aa51 360deg
)`;
clearInterval(progress);
startStop.innerHTML = "START";
progress = null;
progressStart = 0;
}
}
function startStopProgress() {
if (!progress) {
progress = setInterval(progressTrack, speed);
} else {
clearInterval(progress);
progress = null;
progressStart = 0;
progressBar.style.background = `conic-gradient(
#17171a 360deg,
#17171a 360deg
)`;
}
}
function resetValues() {
if (progress) {
clearInterval(progress);
}
minutes = document.querySelector("#minutes").innerHTML;
seconds = document.querySelector("#seconds").innerHTML;
toggleSettings = false;
minElem.contentEditable = false;
minElem.style.borderBottom = `none`;
secElem.contentEditable = false;
secElem.style.borderBottom = `none`;
progress = null;
progressStart = 0;
progressEnd = parseInt(minutes) * 60 + parseInt(seconds);
degTravel = 360 / progressEnd;
progressBar.style.background = `conic-gradient(
#17171a 360deg,
#17171a 360deg
)`;
}
startStop.onclick = function () {
if (startStop.innerHTML === "START") {
if (!(parseInt(minutes) === 0 && parseInt(seconds) === 0)) {
startStop.innerHTML = "STOP";
startStopProgress();
} else {
alert("Enter the Time Value in your Timer!");
}
} else {
startStop.innerHTML = "START";
startStopProgress();
}
};
setting.onclick = function () {
if (!toggleSettings) {
toggleSettings = true;
minElem.contentEditable = true;
minElem.style.borderBottom = `1px dashed #ffffff50`;
secElem.contentEditable = true;
secElem.style.borderBottom = `1px dashed #ffffff50`;
} else {
resetValues();
}
};
minElem.onblur = function () {
resetValues();
};
secElem.onblur = function () {
resetValues();
};
哇,就是它!🤩🤩
结论!
我们已经成功使用 HTML、CSS 和 Javascript 创建了番茄工作法计时器。
我们可以扩展它来添加更多功能,例如“暂停”按钮等,
如果您有任何问题,请参阅下面的完整代码,
欲查看更多此类文章,请访问The Introvert Coder并在Twitter上关注我。
感谢您的阅读,祝您编码愉快!
文章来源:https://dev.to/sansk/build-a-pomodoro-timer-using-html-css-and-javascript-53do