ДЛЯ ТЕХ, КТО ПРЯМО СЕЙЧАС ХОЧЕТ СЕБЯ ПОПРОБОВАТЬ ВО FRONTEND👇
Даем пошаговую инструкцию того, как сделать компонент для таймера обратного отсчета на сайт💡
Потребность в нем возникает довольно часто, например, отсчет до старта продаж или до конца срока действия акции и пр.
Скоро «ЧЁРНАЯ ПЯТНИЦА», сделайте обратный отсчёт для интернет-магазина.
В качестве фремворка будем использовать VueJS 3 версии, но под любой другой фремворк его адаптировать будет не сложно.
ЭТАП 1
Сначала создадим демонстрационный проект для тестирования нашего компонента.
Для этого нужно будет установить среду для сборки NodeJS c официального сайта: https://nodejs.org/ru
Также будем использовать IDE VSCode, ее тоже можно скачать бесплатно с официального сайта: https://code.visualstudio.com
Создаем новую папку для проектов открываем ее в vscode и запускаем в нем терминал.
В терминале вбиваем команду для создания нового проекта vuejs (попутно он предложит установить утилиту vue-create, а потом предложит указать название проекта и другие опции - там пока можно везде выбрать No):
```sh
npm create vue@latest
```
Переходим в терминале в папку проекта:
```sh
cd название проекта
```
Устанавливаем локально зависимости:
```sh
npm i
```
Далее для локального запуска проекта нужно будет вбить в терминал:
```sh
npm run dev
```
Запустится локальный стенд и будет указана ссылка, по которой можно посмотреть результат (по мере обновления кода и его сохранения стенд будет автоматически обновляться).
ЭТАП 2
Теперь создадим компонент Timer.vue в папке /src/components/ со следующим содержимым:
```js
// Timer.vue
<script setup>
</script>
<template>
<div class="timer">
12 дн. 5 ч. 32 мин. 48 сек.
</div>
</template>
```
В нем сразу добавим блок с примером отображения результата.
Добавим теперь его на главный экран, чтобы можно было наблюдать результат:
```js
// App.vue
<script setup lang="ts">
import Timer from './components/Timer.vue'
</script>
<template>
<main>
<Timer />
</main>
</template>
```
При запуске приложения должно получиться следующее:
Так как мы хотим сделать компонент переиспользуемым, добавим параметр - целевая дата (до которой нужно отсчитывать время)
```js
// App.vue
...
<main>
<Timer target-date="2024-06-01T12:53:44Z" />
</main>
...
```
Дата в формате ISO и обязательно UTC, так как момент времени един для всех часовых поясов.
В самом компоненте таймера добавим чтение этого параметра:
```js
// Timer.vue
...
const props = defineProps({ targetDate: String })
const target = new Date(props.targetDate)
...
```
ЭТАП 3
Теперь создадим реактивный объект, который будет хранить все данные об оставшемся времени до целевой даты.
И инициализируем его нулевыми значениями:
```js
// Timer.vue
...
// объект с нулевыми значениями
const nullDiff = {
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
}
// реактивная переменная для хранения вычисленных значений (изначально хранит данные из nullDiff)
const diff = reactive(nullDiff)
...
```
Добавим в верстку теперь данные из этой переменной:
```js
// Timer.vue
...
<template>
<div class="timer">
{{ diff.days }} дн. {{ diff.hours }} ч. {{ diff.minutes }} мин. {{ diff.seconds }} сек.
</div>
</template>
...
```
Теперь реализуем функцию для вычисления значений таймера:
```js
// Timer.vue
...
const updateDiff = () => {
const now = new Date() // сохраняем в переменную текущее время
const result = new Date(target.getTime() - now.getTime()) // вычисляем разницу в миллисекундах и преобразуем в формат даты для удобного чтения отдельных позиций: дней, часов и т д
// если дата находится в прошлом, то пусть таймер отображает нулевые значения
if (result <= 0) {
Object.assign(diff, nullDiff)
return
}
// из разницы (которая была преобразована в формат даты) достаем все позиции
Object.assign(diff, {
days: result.getUTCDate() - 1, // так как у формата даты минимальное значение 1, необходимо вычесть единицу
hours: result.getUTCHours(),
minutes: result.getUTCMinutes(),
seconds: result.getUTCSeconds(),
})
}
...
```
Поясним, зачем мы разницу в миллисекундах преобразуем в формат даты.
Команда target.getTime() возвращает количество миллисекунд до этого момента, начиная с 1 января 1970 года.
Когда мы берем разницу target.getTime() - now.getTime(), мы результат получаем тоже в мс.
Доставать оттуда значения дней, часов и пр. довольно сложно и есть риск ошибиться.
Когда мы преобразуем эту разницу снова в Date, то получаем что-то вроде даты 1970-01-14Т22:21:15.
Отсюда уже легко вычленить отдельные позиции.
Теперь при обновлении страницы получим актуальное значение таймера до выбранной даты.
Однако секунды остановились и не меняются.
Для этого необходимо завести встроенный таймер (буду называть его js-таймер, чтобы не путать), чтобы он каждую секунду обновлял значение:
```js
// Timer.vue
...
const UPDATE_INTERVAL = 1000 // инервал обновления 1000 миллисекунл = 1 секунда
const timerID = 0 // id js-таймер, для того чтобы потом можно было его удалить
onMounted(() => {
// при монтировании компонента создадим js-таймер, который будет запускать функцию обновления нашего таймера
const timerID = setInterval(updateDiff, UPDATE_INTERVAL)
updateDiff() // запускаем функцию первый раз, чтобы пользователь сразу видел актуальное время
})
onUnmounted(() => {
// при удалении компонента удаляем js-таймер
clearInterval(timerID)
})
...
```
В итоге получаем рабочий таймер, который отсчитывает время до определенного момента.
Когда он дойдет до конца, то остановится:
Вот полный код компонента:
```js
// Timer.vue
<script setup>
import { reactive, onMounted, onUnmounted } from 'vue'
const props = defineProps({ targetDate: String })
const target = new Date(props.targetDate)
// вычисление значений таймера
const nullDiff = {
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
}
const diff = reactive(nullDiff)
const updateDiff = () => {
const now = new Date()
const result = new Date(target.getTime() - now.getTime())
if (result <= 0) {
Object.assign(diff, nullDiff)
return
}
console.log(result)
Object.assign(diff, {
days: result.getUTCDate() - 1,
hours: result.getUTCHours(),
minutes: result.getUTCMinutes(),
seconds: result.getUTCSeconds(),
})
}
// обновление таймера
const UPDATE_INTERVAL = 1000 //ms
const timerID = 0
onMounted(() => {
const timerID = setInterval(updateDiff, UPDATE_INTERVAL)
updateDiff()
})
onUnmounted(() => {
clearInterval(timerID)
})
</script>
<template>
<div class="timer">
{{ diff.days }} дн. {{ diff.hours }} ч. {{ diff.minutes }} мин. {{ diff.seconds }} сек.
</div>
</template>
...
```
Таймер - один из простых элементов, попробуйте его сделать по нашей инструкции.
Если в процессе написания кода возникнут вопросы, пишите их в комментариях.
Наш эксперт поможет исправить ошибки✔️