Hvordan jeg byggede min Pomodoro Clock-app og de lektioner, jeg lærte undervejs

Jeg startede på min freeCodeCamp-rejse i december 2017 og er to projekter genert over at udfylde Front-End Development Certificate. Dette indlæg dokumenterer min proces med at gennemføre Pomodoro Clock-projektet.

Hvad er et Pomodoro-ur?

Pomodoro-teknikken er en tidsstyringsramme, der er så enkel som den er effektiv - du bruger en timer til at opdele dit arbejde i tidsblokke (normalt 25 minutter), adskilt af en pause på 5 minutter. Efter hver 4 pomodoros kan du tage en længere pause.

Jeg var nødt til at opfylde følgende brugerhistorier:

  • Jeg kan starte en 25-minutters pomodoro, og timeren går ud, når der er gået 25 minutter.
  • Jeg kan nulstille uret til min næste pomodoro.
  • Jeg kan tilpasse længden af ​​hver pomodoro.

Design / layout

Mit designprincip er at holde brugergrænsefladen ren og enkel. Jeg elskede ideen om at bruge en tomat som timeren. Der er et arbejde / pause display, timer nedtælling og en play / pause knap.

Under timeren havde jeg indstillinger til at ændre arbejdets og pausens varighed og en nulstillingsknap.

Layoutproblemer, jeg stødte på

Jeg havde store problemer med at få tomatbilledet placeret i baggrunden under de andre elementer. Hvordan ville jeg ønske, at der var en layoutmulighed, jeg kunne vælge! ?

Et forslag, jeg fandt, var at gemme tomatbilledet på min foretrukne baggrundsfarve som et nyt billede og derefter bruge billedet i baggrunden. Ulempen ved det var, at det begyndte at se skævt ud, når jeg testede layoutresponsiviteten.

Til sidst lykkedes det mig at få det rigtigt med en kombination af absolute positioning, ændring af topog leftprocenter og 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%);}

Bundindstillingerne var ret ligetil. Jeg brugte CSS Grid til at adskille komponenterne i tre kolonner, hvor den midterste kolonne var halv bredden af ​​de ydre kolonner.

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

Igen brugte jeg til transformat skifte nulstillingsknappen for bedre justering.

Strukturere min kode - og derefter rive den fra hinanden

Jeg finder det nyttigt at komme med min kodestruktur, hvis jeg nedbryder kravene:

  • Timeren skifter mellem start og pause, når jeg klikker på knappen 'start'.
  • Når timeren når nul, går en alarm.
  • En arbejdssession efterfølges altid af en pause.
  • Arbejds- og pausetiden kan ændres.
  • Knappen 'nulstil' nulstiller (du gættede det) timeren.

Jeg havde tidligere gennemført et nedtællingsur i Wes Bos JavaScript30-kurset, så jeg vidste, at jeg kunne bruge setIntervalmetoden. Jeg besluttede også at udfordre mig selv ved at holde mig til vanille JavaScript og undgå at stole på jQuery.

Og så begyndte jeg at skrive min JavaScript-kode. Mens det lykkedes mig at oprette et funktionelt pomodoro-ur, vil jeg ikke gennemgå den første version af min kode her. Dette skyldes, at jeg lavede betydelige ændringer i det efter at have modtaget konstruktiv feedback fra en fantastisk fremmed på Reddit. ?

Ja, der sker gode ting på Reddit!

Hovedpunkterne i feedbacken var:

  • setInterval(timer, 1000)tager mindst 1000 ms at udløse, men det kan tage længere tid. Så du skal kontrollere, hvor meget tid der faktisk er gået, eller dit ur kan være unøjagtigt.
  • Gruppér alle HTML-opdateringer i et afsnit, da dette gør din kode lettere at opdatere og fejle.
  • Det er generelt en god ide at lave koden uden overhovedet at tænke på repræsentationen.
  • Vær sikker på logikken for timeren, og slip af med unødvendig kode.
  • Sørg for, at variabelnavne er beskrivende. Efterlad kommentarer, når det er nødvendigt.

Du kan se min første forpligtelse på GitHub.

Refactoring min kode

Efter at have fået al den værdifulde feedback refaktoriserede jeg min kode flere gange, indtil jeg var tilfreds med den.

Først definerede jeg alle variablerne. Da jeg ikke brugte jQuery, sørgede jeg for, at jeg fangede alle mine elementer ved hjælp af 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");

Dernæst oprettede jeg lydelementet.

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

Når der klikkes på startknappen, ryddes intervallet. Et nyt interval indstilles, hvis det isPausedskifter fra sand til falsk .

Knappen 'nulstil' rydder intervallet og nulstiller variablerne.

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.

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.

document.querySelector("#work-plus").onclick = function() { workDuration  5 ? workDuration -= increment : workDuration; }document.querySelector("#break-plus").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.

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!

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.

Endelig plejede jeg document.onclickat køre opdateringHTML-funktionen hver gang brugeren klikker på siden. Jeg plejede også window.setIntervalat køre funktionen 10 gange i sekundet for godt mål.

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;

Og det er afslutningen på mit projekt!

Du kan se mit afsluttende projekt her.

Afsluttende tanker

Min største takeaway fra dette projekt er, at jeg skal sigte mod enkelhed med hensyn til kodedesign, fordi det er en forudsætning for pålidelighed. Det vil gøre min kode let at forstå, let at debugge og let at opdatere.

Jeg mindes også om fordelene ved parret programmering og kodevurderinger, især når man er ny til kodning.

Der er stadig så meget at lære. Men lige nu, lad mig belønne mig selv med en tallerken Pasta al pomodoro.