Создание useCooldown для Vue 3: умный таймер с сохранением состояния

от автора

в
Время чтения: 2 мин.

Что делает useCooldown?

Функция useCooldown создает таймер обратного отсчета с двумя ключевыми особенностями:

  1. Сохранение состояния — продолжает отсчет даже после перезагрузки страницы
  2. Реактивность — автоматически обновляет интерфейс при изменении времени

Основной функционал

import { useCountdown, useStorage } from '@vueuse/core'
import { onMounted, watch } from 'vue'

export function useCooldown(seconds = 0, storageKey = 'cooldown') {
  const cooldownEnd = useStorage(storageKey, 0)

  const getRemainingSeconds = () => {
    const now = Math.floor(Date.now() / 1000)
    return Math.max(0, cooldownEnd.value - now)
  }

  const { remaining, start: startCountdown } = useCountdown(getRemainingSeconds())

  const start = (value = seconds) => {
    const now = Math.floor(Date.now() / 1000)
    cooldownEnd.value = now + value
    startCountdown(value)
  }

  watch(remaining, (value) => {
    const now = Math.floor(Date.now() / 1000)
    cooldownEnd.value = now + value
  })

  onMounted(() => {
    const remainingSeconds = getRemainingSeconds()
    if (remainingSeconds > 0) {
      start(remainingSeconds)
    }
  })

  return { cooldown: remaining, start }
}

Параметры функции

  • seconds (по умолчанию 0) — начальное время отсчета в секундах
  • storageKey (по умолчанию ‘cooldown’) — ключ для хранения состояния

Возвращаемые значения

  • cooldown — реактивное число, оставшееся время в секундах
  • start — функция для запуска/перезапуска таймера

Пример использования

Базовый пример

<script setup>
import { useCooldown } from './useCooldown'

const { cooldown, start } = useCooldown(60)

function handleClick() {
  if (cooldown > 0) return
  console.log('Action performed!')
  start() // Запускаем 60-секундный таймер
}
</script>

<template>
  <button @click="handleClick" :disabled="cooldown > 0">
    {{ cooldown > 0 ? `Доступно через ${cooldown} сек.` : 'Выполнить действие' }}
  </button>
</template>

Пример с несколькими таймерами

<script setup>
import { useCooldown } from './useCooldown'

const emailTimer = useCooldown(30, 'email-cooldown')
const smsTimer = useCooldown(60, 'sms-cooldown')

function sendEmail() {
  if (emailTimer.cooldown > 0) return
  console.log('Email sent')
  emailTimer.start()
}

function sendSMS() {
  if (smsTimer.cooldown > 0) return
  console.log('SMS sent')
  smsTimer.start(90) // Переопределяем стандартное значение
}
</script>

Кастомное отображение времени

<script setup>
import { computed } from 'vue'
import { useCooldown } from './useCooldown'

const { cooldown, start } = useCooldown(120)

const formattedTime = computed(() => {
  const mins = Math.floor(cooldown / 60)
  const secs = cooldown % 60
  return `${mins}:${secs < 10 ? '0' : ''}${secs}`
})
</script>

<template>
  <button @click="start" :disabled="cooldown > 0">
    {{ cooldown > 0 ? `Ожидание (${formattedTime})` : 'Начать' }}
  </button>
</template>

Особенности реализации

  1. Хранение timestamp — сохраняется момент окончания таймера, а не оставшееся время
  2. Автовосстановление — при загрузке страницы проверяет активный таймер
  3. Синхронизация — постоянно обновляет хранилище при изменении времени

Эта функция готова к использованию в любом проекте на Vue 3 и может быть легко расширена под конкретные нужды.


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Сколько будет 7 + 6?