by Cynthia Lee

辛西娅·李(Cynthia Lee)

我如何构建Pomodoro Clock应用程序,以及在此过程中学到的课程 (How I built my Pomodoro Clock app, and the lessons I learned along the way)

I embarked on my freeCodeCamp journey in Dec 2017, and am two projects shy of completing the Front-End Development Certificate. This post documents my process of completing the Pomodoro Clock project.

我于2017年12月开始了我的freeCodeCamp之旅,并且是两个未完成前端开发证书的项目。 这篇文章记录了我完成Pomodoro Clock项目的过程。

什么是番茄钟? (What is a Pomodoro Clock?)

The Pomodoro Technique is a time-management framework which is as simple as it is effective - you use a timer to break your work into time blocks (usually 25 minutes), separated by a 5 minute break. After every 4 pomodoros, you can take a longer break.

Pomodoro技术是一个时间管理框架,它非常有效,它很简单-您使用计时器将工作分为多个时间段(通常为25分钟),每个时间段间隔为5分钟。 每4个番茄一次,您可以休息更长的时间。

I had to fulfil the following user stories:

我必须满足以下用户故事:

  • I can start a 25 minute pomodoro, and the timer will go off once 25 minutes has elapsed.我可以开始一个25分钟的番茄,一旦25分钟过去,计时器就会关闭。
  • I can reset the clock for my next pomodoro.我可以为下一个番茄钟重置时钟。
  • I can customise the length of each pomodoro.我可以自定义每个番茄的长度。

设计/布局 (Design / layout)

My design principle is to keep the user interface clean and simple. I loved the idea of using a tomato as the timer. There is a work/break display, timer countdown, and a play/pause button.

我的设计原则是保持用户界面干净简单。 我喜欢使用番茄作为计时器的想法。 有工作/休息时间显示,计时器倒计时和播放/暂停按钮。

Below the timer, I had settings to modify the work and break duration, and a reset button.

在计时器下方,我有一些设置可以修改工作和休息时间,还有一个重置按钮。

我遇到的版面设计问题 (Layout issues I encountered)

I had major issues with getting the tomato image positioned in the background under the other elements. How I wish there was a layout option I could select! ?

在将番茄图像放置在其他元素下的背景中时,我遇到了主要问题。 我多么希望有一个我可以选择的布局选项! ?

One suggestion I found was to save the tomato image on my preferred background colour as a new image, then use that image in the background. The downside to that was that it started to look wonky once I tested the layout responsiveness.

我发现的一个建议是将番茄图像以我喜欢的背景颜色保存为新图像,然后在背景中使用该图像。 不利的一面是,一旦我测试了布局响应能力,它就开始显得古怪。

In the end, I managed to get it right with a combination of absolute positioning, modifying the top and left percentages, and transform.

最后,我设法通过结合absolute positioning ,修改topleft百分比以及进行transform来使其正确。

#status {  position: absolute;  top: 45%;  left:50%;  transform: translate(-50%, -50%);}
.timerDisplay {  position: absolute;  top: 60%;  left: 50%;  transform: translate(-50%, -50%);}
#start-btn {  position: absolute;  bottom: 8%;  left: 48%;  transform: translate(-50%, -50%);}

The bottom settings were fairly straightforward. I used CSS Grid to separate the components into three columns, with the middle column being half the width of the outer columns.

底部设置非常简单。 我使用CSS Grid将组件分为三列,中间的列是外部列的宽度的一半。

.settings {  margin: auto;  width: 80%;  display: grid;  grid-template-columns: 2fr 1fr 2fr;  align-items: center;}

Once again, I used transform to shift the reset button for better alignment.

再次,我使用了transform来移动Reset按钮,以更好地对齐。

构建我的代码-然后将其拆开 (Structuring my code - and then tearing it apart)

I find it helpful to come up with my code structure if I breakdown the requirements:

如果分解要求,我发现提出我的代码结构会有所帮助:

  • The timer will toggle between starting and pausing when I click the ‘start’ button.当我单击“开始”按钮时,计时器将在开始和暂停之间切换。
  • Once the timer reaches zero, an alarm will go off.一旦计时器达到零,警报将响起。
  • A work session is always followed by a break session.工作会议之后总是有休息会议。
  • The work and break durations can be modified.工时和休息时间可以修改。
  • The ‘reset’ button will (you guessed it) reset the timer.“重置”按钮将(您猜对了)重置计时器。

I had previously completed a countdown clock in the Wes Bos JavaScript30 course, so I knew that I could use the setInterval method. I also decided to challenge myself by sticking to vanilla JavaScript, and avoid relying on jQuery.

我之前已经在Wes Bos JavaScript30课程中完成了倒数计时,所以我知道我可以使用setInterval方法。 我还决定通过坚持使用普通JavaScript来挑战自己,并避免依赖jQuery。

And so I started writing my JavaScript code. While I managed to create a functional pomodoro clock, I won’t go through the first version of my code here. This is because I made significant changes to it after receiving constructive feedback from an amazing stranger on Reddit. ?

因此,我开始编写我JavaScript代码。 虽然我设法创建了一个功能性的番茄钟,但在这里我不会浏览代码的第一个版本。 这是因为在收到Reddit上一个令人惊讶的陌生人的建设性反馈后,我对其进行了重大更改。 ?

Yes, nice things do happen on Reddit!

是的,Reddit上确实发生了很多事情!

The main points of the feedback were:

反馈的要点是:

  • setInterval(timer, 1000) takes at least 1000 ms to trigger, but may take longer. So you should check how much time actually elapsed, or your clock can be inaccurate.

    setInterval(timer, 1000)至少需要1000毫秒才能触发,但可能需要更长的时间。 因此,您应该检查实际花费了多少时间,否则您的时钟可能不准确。

  • Group all HTML updates in one section, as this makes your code easier to update and debug.将所有HTML更新分组在一个部分中,因为这使您的代码更易于更新和调试。
  • It is generally a good idea to make the code without thinking about the representation at all.通常,完全不考虑表示形式的情况下编写代码是一个好主意。
  • Be sure about the logic of the timer, and get rid of unnecessary code.确保计时器的逻辑,并清除不必要的代码。
  • Make sure the variable names are descriptive. Leave comments when necessary.确保变量名称具有描述性。 必要时发表评论。

You can view my first commit on GitHub.

您可以在GitHub上查看我的第一次提交。

重构我的代码 (Refactoring my code)

After getting all that valuable feedback, I refactored my code several times until I was satisfied with it.

得到所有有价值的反馈后,我对代码进行了多次重构,直到对它满意为止。

First, I defined all the variables. As I was not using jQuery, I ensured that I captured all my elements using document.querySelector.

首先,我定义了所有变量。 因为我没有使用jQuery,所以确保使用document.querySelector捕获了所有元素。

let countdown = 0; // variable to set/clear intervalslet seconds = 1500; // seconds left on the clocklet workTime = 25;let breakTime = 5;let isBreak = true;let isPaused = true;
const status = document.querySelector("#status");const timerDisplay = document.querySelector(".timerDisplay");const startBtn = document.querySelector("#start-btn");const resetBtn = document.querySelector("#reset");const workMin = document.querySelector("#work-min");const breakMin = document.querySelector("#break-min");

Next, I created the audio element.

接下来,我创建了音频元素。

const alarm = document.createElement('audio'); alarm.setAttribute("src", "https://www.soundjay.com/misc/sounds/bell-ringing-05.mp3");

When the ‘start’ button is clicked, the interval is cleared. A new interval is set if isPaused changes from true to false.

单击“开始”按钮后,间隔将被清除。 如果isPausedtrue更改为false,则会设置一个新间隔。

The ‘reset’ button clears the interval, and resets the variables.

“重置”按钮清除间隔,并重置变量。

startBtn.addEventListener('click', () => {  clearInterval(countdown);  isPaused = !isPaused;  if (!isPaused) {    countdown = setInterval(timer, 1000);  }})
resetBtn.addEventListener('click', () => {  clearInterval(countdown);  seconds = workTime * 60;  countdown = 0;  isPaused = true;  isBreak = true;})

The timer function is where the countdown magic happens. It deducts one second from seconds. If seconds <; 0, the alarm is played, and the function determines if the next countdown should be a work session or break session.

计时器功能是发生倒计时魔术的地方。 它从秒中减去一秒 如果秒< ; 0,将发出警报,并且该功能确定下一个倒数是工作时段还是休息时段。

function timer() {  seconds --;  if (seconds < 0) {    clearInterval(countdown);    alarm.currentTime = 0;    alarm.play();    seconds = (isBreak ? breakTime : workTime) * 60;    isBreak = !isBreak;  }}

Now it’s time to work on the +/- buttons for the work and break durations. Initially, I created an onclick function for every button. While it was functional, there was definitely room for improvement.

现在是时候使用+/-按钮进行工作和休息时间了。 最初,我为每个按钮创建了一个onclick函数。 虽然功能正常,但肯定还有改进的空间。

document.querySelector("#work-plus").onclick = function() {         workDuration < 60 ? workDuration += increment : workDuration;                   }document.querySelector("#work-minus").onclick = function() {         workDuration > 5 ? workDuration -= increment : workDuration;              }document.querySelector("#break-plus").onclick = function() {     breakDuration < 60 ? breakDuration += increment : breakDuration;                     }document.querySelector("#break-minus").onclick = function() {        breakDuration > 5 ? breakDuration -= increment : breakDuration;                  }

That same kind Redditor suggested that I use an associative array, which is essentially a set of key value pairs.

同一种Redditor建议我使用一个关联数组 ,该数组本质上是一组键值对。

let incrementFunctions =    {"#work-plus": function () { workTime = Math.min(workTime + increment, 60)},     "#work-minus": function () { workTime = Math.max(workTime - increment, 5)},     "#break-plus": function () { breakTime = Math.min(breakTime + increment, 60)},     "#break-minus": function () { breakTime = Math.max(breakTime - increment, 5)}};
for (var key in incrementFunctions) {    if (incrementFunctions.hasOwnProperty(key)) {      document.querySelector(key).onclick = incrementFunctions[key];    }}

It’s time to update the HTML!

现在是时候更新HTML了!

I created functions to update the countdown display and button display, and incorporated those functions into an overarching function that also updated the Work/Break status and durations.

我创建了一些用于更新倒数显示和按钮显示的函数,并将这些函数合并到一个总体函数中,该函数还更新了工作/中断状态和持续时间。

Finally, I used document.onclick to run the updateHTML function everytime the user clicks on the page. I also used window.setInterval to run the function 10 times a second for good measure.

最后,每次用户单击页面时,我都使用document.onclick运行updateHTML函数 。 我还使用window.setInterval每秒运行10次该函数以取得良好效果。

function countdownDisplay() {  let minutes = Math.floor(seconds / 60);  let remainderSeconds = seconds % 60;  timerDisplay.textContent = `${minutes}:${remainderSeconds < 10 ? '0' : ''}${remainderSeconds}`;}
function buttonDisplay() {  if (isPaused && countdown === 0) {    startBtn.textContent = "START";  } else if (isPaused && countdown !== 0) {    startBtn.textContent = "Continue";   } else {    startBtn.textContent = "Pause";  }}
function updateHTML() {  countdownDisplay();  buttonDisplay();  isBreak ? status.textContent = "Keep Working" : status.textContent = "Take a Break!";  workMin.textContent = workTime;  breakMin.textContent = breakTime;}
window.setInterval(updateHTML, 100);
document.onclick = updateHTML;

And that’s the wrap up of my project!

这就是我的项目的总结!

You can view my final project here.

您可以在这里查看我的最终项目。

最后的想法 (Final thoughts)

My biggest takeaway from this project is that I should aim for simplicity in terms of code design, because it is a prerequisite for reliability. It will make my code easy to understand, easy to debug, and easy to update.

我从该项目中获得的最大收获是,我应该在代码设计方面追求简单性,因为这是可靠性的前提。 这将使我的代码易于理解,易于调试和易于更新。

I am also reminded of the benefits of paired programming and code reviews, especially when one is new to coding.

我还想起了配对编程和代码审查的好处,特别是在编码是新手时。

There is still so much to learn. But for now, let me reward myself with a plate of Pasta al pomodoro.

还有很多东西要学。 但是现在,让我用一盘意大利面来奖励自己。

翻译自: https://www.freecodecamp.org/news/how-i-built-my-pomodoro-clock-app-and-the-lessons-i-learned-along-the-way-51288983f5ee/

我如何构建Pomodoro Clock应用程序,以及在此过程中学到的课程相关推荐

  1. 构建一个移动应用程序要花多少钱?

    构建一个移动应用程序要花多少钱? How much does it cost to build a mobile app? 不幸的是,对于一个移动应用程序的开发成本应该是多少这个问题,没有一个单一的答 ...

  2. 如何构建虚拟护士应用程序?

    如何构建虚拟护士应用程序? How to build a virtual nurse app like Sensely? 传统上,技术的进步引发了企业的变革.由最先进的计算机软件提供的交互式工具意味着 ...

  3. node mongoose_如何使用Express,Mongoose和Socket.io在Node.js中构建实时聊天应用程序

    node mongoose by Arun Mathew Kurian 通过阿伦·马修·库里安(Arun Mathew Kurian) 如何使用Express,Mongoose和Socket.io在N ...

  4. 电子界卡组构建2019_2018–2019年构建现代Android应用程序的路线图

    电子界卡组构建2019 Kriptofolio应用程序系列-简介 (Kriptofolio app series - Introduction) Welcome to this series of b ...

  5. 构建node.js基础镜像_在Android上构建Node.js应用程序

    构建node.js基础镜像 by Aurélien Giraud 通过AurélienGiraud 在Android上构建Node.js应用程序-第1部分:Termux,Vim和Node.js (Bu ...

  6. 在docker中构建普通java程序_Docker入门-构建第一个Java程序

    原标题:Docker入门-构建第一个Java程序 定制镜像 准备一个没有第三方依赖的java web项目,可能参考示例maven结构项目: session-web.war 把该war上传到安装有doc ...

  7. mega_[MEGA DEAL]完整的Android开发人员课程–构建14个应用程序(91%折扣)

    mega 顶级教练Rob Percival将带您经过31个小时的培训,从编码新手到忍者 嘿,怪胎, 本周,在我们的JCG Deals商店中,我们提供了一个极端的报价. 我们提供的"完整的An ...

  8. 推荐3款 Docker 认证的实用免费插件,帮助您快速构建云原生应用程序!

    出品丨Docker公司(ID:docker-cn) 编译丨小东 每周一.三.五,与您不见不散! Docker 认证技术项目(Docker Certified Technology Program)是为 ...

  9. 用HTML和CSS和JS构建跨平台桌面应用程序的开源库Electron的介绍以及搭建HelloWorld

    场景 Electron介绍 Electron是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库. Electron通过将Chromium和Node.js ...

最新文章

  1. 【Dlib】使用dlib_face_recognition_resnet_model_v1.dat无法实现微调fune-tuning
  2. android 代码设置居右_android如何让textview文字居右
  3. Markdown文章转化为富文本文章
  4. Qt+Phonon的另一种选择
  5. 在Visual Studio 2010中创建多项目(解决方案)模板【三】
  6. Atitit.提升api兼容性的方法 v3 q326
  7. 小米自动化运维平台演进设计思路
  8. centos eclipse 安装
  9. Python版冒泡法排序算法
  10. C++多重继承时调用相应的父类函数
  11. JDK动态代理简单实现
  12. 基于角色的权限管理系统设计思路
  13. GPRS DTU是什么?其工作原理是什么? (转自aerkate)
  14. 基于VUMAT复合材料夹层结构冲击仿真
  15. 【高德地图API】Web地图开发系列(一)
  16. 阿里云-物联网MQConsumerSTS 订阅失效问题
  17. 中国大学生计算机设计大赛二等奖
  18. 微信小程序可横向滑动展开菜单
  19. 大鱼计算机谱 音乐,周深演唱大鱼简谱
  20. springcloud豪猪

热门文章

  1. Android adb使用总结记录
  2. 人脸扫描Canvas动画
  3. 三阶魔方入门基础教程
  4. idea修改中文字体
  5. 批处理使用技巧:批量修改文件名
  6. 【定位原理揭秘第三期】室内定位技术原理揭秘
  7. 为了摸鱼,我开发了一个工具网站
  8. autojs编写的支付宝支付模板,带toast弹窗,自定义控件,界面上插入图片,功能非常强大和完善值得学习
  9. 沧海桑田:Linux 系统启动的演进模型与发展变化
  10. 电瓶车行驶过程中突然无动力,加速没反应,怎么办?