在Astro中使用React重构一个全屏时间展示工具

在Astro中使用React重构一个全屏时间展示工具

  1. 我的工具箱 🪜
  2. 5 months ago
  3. 4 min read

全屏时间展示:https://blog.imwarn.com/time/

四年前在码云fork过一个全屏时钟仓库,是大圣老师用来配合早起学习用的,而我简单修改后就放到那儿啦。

倒是近两年开始跟着直播跳操,开始把这个全屏时钟用起来了,习惯性地放在分屏看下时间。很不幸的是,最近Gitee Pages打不开了。打开Time.is用了几天,发现还是更习惯之前的时钟模式。

因此,就在这次Astro版本的博客网站中,使用devv.ai的react传授术,重构了一个全屏时钟。

第一个版本,完全就是主打能用就行,UI是完全没带管的。

fullscreen-time-v1

简要内核

时间的刷新展示

作为一个时钟,最最关键的就是:获取当前时间,然后不断刷新时间的展示。

初始版本使用了setInterval()计时器实现,在这个版本决定改用requestAnimationFrame()来执行时间的获取和刷新任务。

import React, { useEffect, useRef, useState } from 'react'

function Clock() {
    const [currentTime, setCurrentTime] = useState(new Date())

    const updateClock = () => {
        setCurrentTime(new Date())
        requestRef.current = requestAnimationFrame(updateClock)
    }

    useEffect(() => {
        requestRef.current = requestAnimationFrame(updateClock)
        return () => cancelAnimationFrame(requestRef.current)
    }, [])
}

全屏与退出全屏

重构这个时间展示工具就是为了在使用中减少纷杂因素的干扰,所以全屏必不可少。

初始版本使用的document的原始API,通过使用document.documentElement.requestFullscreen()document.fullscreenElement兼容性方案来实现全屏状态的切换,在这个版本用了react-full-screen依赖库来简化DOM的兼容使用,只需要在点击时判断当前全屏状态并给予切换。

import { FullScreen, useFullScreenHandle } from 'react-full-screen'
const handle = useFullScreenHandle()
const handleBodyClick = () => {
    if (handle.active) {
        handle.exit()
    }
    else {
        handle.enter()
    }
}

return (
    <>
        <FullScreen handle={handle}>
            {/* <!----> */}
        </FullScreen>
    </>
)

拓展业务

Time.is还是很强大的,虽然目前好多功能个人是用不到的,但是总会想有亿点点定制,不然也不会自己吭哧瘪肚地复制粘贴代码搞自己的站。为了不让自己想定制的时候还需要去改代码,就需要拓展出来定制的功能。

比如根据语言显示日期/定制不一样的数字显示字体/定制主题配色。

语言切换

const locales = [
    { code: 'en-US', label: 'English (US)' },
    { code: 'zh-CN', label: '中文 (中国)' },
    { code: 'fr-FR', label: 'Français (France)' },
    { code: 'de-DE', label: 'Deutsch (Deutschland)' },
    { code: 'ja-JP', label: '日本語 (日本)' },
]

const [locale, setLocale] = useState(locales[0].code)
const hour = currentTime.getHours().toString().padStart(2, '0')
const minute = currentTime.getMinutes().toString().padStart(2, '0')
const second = currentTime.getSeconds().toString().padStart(2, '0')
const year = currentTime.getFullYear()

const formattedDate = currentTime.toLocaleDateString(locale, {
    weekday: 'long',
    year: 'numeric',
    month: 'long',
    day: 'numeric',
})
const handleLocaleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
    setLocale(event.target.value)
}

定制字体

const fontSchemes = [
    { id: 'default', label: '默认', fontFamily: '', fontWeight: 600 },
    { id: 'timeis', label: 'Time.is', fontFamily: 'TimeTravelerPal', fontWeight: 400 },
]
const [fontScheme, setFontScheme] = useState(fontSchemes[0])
const handleFontChange = (index: number) => {
    setFontScheme(fontSchemes[index])
}

定制主题


const colorSchemes = [
    { background: '#1f1c19', color: '#caccdf' }, // 默认配色
    { background: '#282c34', color: '#61dafb' }, // 深色配色
    { background: '#ffffff', color: '#000000' }, // 浅色配色
    { background: '#ff6347', color: '#ffffff' }, // 番茄配色
    { background: '#4caf50', color: '#ffffff' }, // 绿色配色
]
const [colorScheme, setColorScheme] = useState(colorSchemes[0])
const handleColorChange = (index: number) => {
    setColorScheme(colorSchemes[index])
}
工具 全屏时钟