June 24th, 2021

JavaScript: создание цветных часов

Решил задачу «Цветные часы с использованием setInterval» к подразделу 1.7 «Изменение документа» второй части учебника по JavaScript.

Часы должны выглядеть на HTML-странице в браузере примерно так:



Это картинка, а не действующий экземпляр. В постах ЖЖ скрипты запрещены (см. вопрос № 14 из справки ЖЖ). Действующий экземпляр можно пощупать на странице данной задачи в обсуждаемом учебнике.

Часы, минуты и секунды на HTML-страницу должен вывести наш скрипт, а кнопки на HTML-странице уже имеются, они реализованы на языке HTML:
<input type="button" onclick="clockStart()" value="Старт">
<input type="button" onclick="clockStop()" value="Стоп">
Функции clockStart и clockStop мы тоже должны написать.

При загрузке HTML-страницы с часами они должны сразу же начать тикать и показывать текущее для нашего компьютера время. При нажатии на кнопку «Стоп» тикание часов должно остановиться. При нажатии на кнопку «Старт» тикание часов должно возобновиться с временного момента нажатия на кнопку «Старт».

Итак, сначала я решил просто вывести строку с нулями на HTML-страницу в нужном месте. Тело (HTML-элемент body) нашей HTML-страницы состоит из двух кнопок, как показано выше. Если вставить текст с текущим временем в самое начало тела данной HTML-страницы, то он попадет именно туда, куда нужно. Пишем код:
document.body.insertAdjacentHTML("afterbegin", "00:00:00<br>");
Метод insertAdjacentHTML я выбрал для того, чтобы можно было вставлять на HTML-страницу HTML-теги именно как HTML-теги, а не как текст. То, что потребуется вставлять HTML-теги, выяснилось сразу же, потому что, как мы видим на картинке выше, кнопки располагаются на следующей строке под часами, минутами и секундами, а это значит, что требуется перенос строки, который можно выполнить с помощью HTML-тега br.

На HTML-странице в браузере получили следующее:



По условию задачи для стилизации (в нашем случае — простая раскраска разными цветами часов, минут и секунд) следует использовать HTML/CSS. Чтобы разметить для стилизации кусочки строки (у нас часы, минуты и секунды представляют собой кусочки строки "00:00:00<br>") в языке HTML обычно используют тег span. Тут об этом подробнее:

https://developer.mozilla.org/ru/docs/Web/HTML/Element/span

Стиль отдельного кусочка строки можно описать либо в самом теге span в свойстве style:
document.body.insertAdjacentHTML("afterbegin",
    '<span style="color: #ff0000;">00</span>:' +
    '<span style="color: #008000;">00</span>:' +
    '<span style="color: #0000ff;">00</span><br>');

Либо можно назначить каждому кусочку строки (часы, минуты и секунды) отдельный тип (класс), а стили классов описать, к примеру, в заголовочной части (тег head) нашей HTML-страницы (этот метод считается более систематичным):
document.body.insertAdjacentHTML("afterbegin",
    '<span class="hours">00</span>:' +
    '<span class="minutes">00</span>:' +
    '<span class="seconds">00</span><br>');
Возможное содержание заголовочной части нашей HTML-страницы:
<head>
  <meta charset="utf-8">
  <style>
    span.hours   { color: #ff0000; }
    span.minutes { color: #008000; }
    span.seconds { color: #0000ff; }
  </style>
</head>

Значения #ff0000, #008000 и #0000ff соответствуют цветам red (красный), green (зеленый) и blue (синий). Подробнее об этом можно почитать тут:

https://ru.wikipedia.org/wiki/HTML-цвета

После такой стилизации на HTML-странице в браузере получаем следующее:



Теперь займемся реализацией, собственно, часов. Очевидно, что для этого мы будем каждую секунду вписывать на HTML-страницу новое значение времени, затирая предыдущее значение. Для этого нам хорошо бы иметь некий HTML-элемент (контейнер), который будет содержать значение времени и в который мы будем записывать новое значение времени, затирая предыдущее. Я решил, что таким контейнером может стать тот же HTML-элемент span, который обсуждался выше.

То есть сначала мы вставим на HTML-страницу контейнер, а затем будем вставлять в него каждую секунду текущее время, затирая предыдущее значение. Меняем код:
// вставляем на HTML-страницу контейнер
document.body.insertAdjacentHTML("afterbegin", '<span id="container"></span><br>');

// вставляем в контейнер текущее время
insertTimeStr(container);

function insertTimeStr(cont) {
    let now = new Date();      // получение текущей отметки времени

    let h = now.getHours(),    // выделение из нее значений часов,
        m = now.getMinutes(),  // минут и секунд
        s = now.getSeconds();

    if (h < 10) h = "0" + h;   // если значение состоит из одной цифры,
    if (m < 10) m = "0" + m;   // добавляем перед ним символ нуля
    if (s < 10) s = "0" + s;

    cont.innerHTML = '<span class="hours">'   + h + "</span>" + ":" +
                     '<span class="minutes">' + m + "</span>" + ":" +
                     '<span class="seconds">' + s + "</span>";
}
Вставку текущего времени в контейнер я выделил в отдельную функцию insertTimeStr.

Теперь на HTML-странице в браузере мы получим то, что требовалось. Однако, часы пока не тикают, а лишь показывают текущее время нашего компьютера на момент загрузки HTML-страницы.

Чтобы добавить тиканье, будем каждую секунду делать вставку текущего времени в указанный контейнер с помощью функции setInterval:
let timerId = setInterval(insertTimeStr, 1000, container);

С этим кодом уже можно написать и функции clockStart и clockStop для кнопок.

Итоговый код:
// вставляем на HTML-страницу контейнер
document.body.insertAdjacentHTML("afterbegin", '<span id="container"></span><br>');

// вставляем в контейнер текущее время
insertTimeStr(container);
// начиная с момента через секунду и далее каждую секунду,
// вставляем в контейнер текущее время
let timerId = setInterval(insertTimeStr, 1000, container);

function insertTimeStr(cont) {
    let now = new Date();      // получение текущей отметки времени

    let h = now.getHours(),    // выделение из нее значений часов,
        m = now.getMinutes(),  // минут и секунд
        s = now.getSeconds();

    if (h < 10) h = "0" + h;   // если значение состоит из одной цифры,
    if (m < 10) m = "0" + m;   // добавляем перед ним символ нуля
    if (s < 10) s = "0" + s;

    cont.innerHTML = '<span class="hours">'   + h + "</span>" + ":" +
                     '<span class="minutes">' + m + "</span>" + ":" +
                     '<span class="seconds">' + s + "</span>";
}

function clockStart() {
    clearInterval(timerId);
    timerId = setInterval(insertTimeStr, 1000, container);
}

function clockStop() {
    clearInterval(timerId);
}

Функция clockStop удаляет из планировщика текущее задание по ежесекундной вставке текущего времени в контейнер, поэтому тиканье часов останавливается. Функция clockStart удаляет текущее задание из планировщика (на случай, если кнопку «Старт» нажмут при уже тикающих часах) и ставит новое, с помощью того же кода, что и при загрузке HTML-страницы.