数字时钟

经验创意 · 26 次浏览
困困君 创建于 11小时28分钟前

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>系统时钟</title>
    <style>
        html, body {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
            background: transparent;
            font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
        }

        .card {
            width: 100%;
            height: 100%;
            box-sizing: border-box;
            border-radius: 18px;
            background: linear-gradient(135deg, #242732 0%, #15171d 100%);
            border: 1px solid rgba(135, 206, 250, 0.2);
            box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.1),
                        inset 0 0 20px rgba(135, 206, 250, 0.05);
            color: #ffffff;
            display: flex;
            flex-direction: column;
            position: relative;
            user-select: none;
        }

        .header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 12px 16px;
            height: 24px;
        }

        .drag-area {
            flex: 1;
            height: 100%;
            display: flex;
            align-items: center;
            font-size: 13px;
            font-weight: 500;
            color: rgba(255, 255, 255, 0.6);
            cursor: move;
        }

        .drag-area::before {
            content: '';
            display: inline-block;
            width: 6px;
            height: 6px;
            border-radius: 50%;
            background: rgba(135, 206, 250, 0.4);
            margin-right: 8px;
            box-shadow: 0 0 4px rgba(135, 206, 250, 0.6);
        }

        .actions {
            display: flex;
            gap: 8px;
            z-index: 2;
        }

        button {
            background: rgba(255, 255, 255, 0.06);
            border: 1px solid rgba(255, 255, 255, 0.1);
            color: rgba(255, 255, 255, 0.85);
            padding: 4px 12px;
            border-radius: 6px;
            cursor: pointer;
            font-family: inherit;
            font-size: 12px;
            font-weight: bold;
            transition: all 0.2s ease;
            outline: none;
        }

        button:hover {
            background: rgba(255, 255, 255, 0.15);
            border-color: rgba(135, 206, 250, 0.4);
            color: #fff;
        }

        button:active {
            background: rgba(255, 255, 255, 0.08);
            border-color: rgba(135, 206, 250, 0.2);
        }

        .clock-content {
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            padding-bottom: 20px;
            cursor: default;
        }

        .time-row {
            display: flex;
            align-items: baseline;
            font-variant-numeric: tabular-nums;
            text-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
        }

        #timeHourMin {
            font-size: clamp(3rem, 18vw, 5.5rem);
            font-weight: 600;
            letter-spacing: 2px;
            line-height: 1;
            color: #ffffff;
        }

        #timeSec {
            font-size: clamp(1.2rem, 6vw, 2rem);
            color: rgba(135, 206, 250, 0.8);
            margin-left: 8px;
            font-weight: 400;
        }

        #timeAmPm {
            font-size: clamp(0.9rem, 4vw, 1.2rem);
            color: rgba(255, 255, 255, 0.5);
            margin-left: 6px;
            font-weight: bold;
        }

        .date-row {
            font-size: clamp(0.85rem, 4vw, 1.1rem);
            color: rgba(255, 255, 255, 0.6);
            margin-top: 12px;
            letter-spacing: 1px;
            background: rgba(0, 0, 0, 0.2);
            padding: 4px 12px;
            border-radius: 20px;
            border: 1px solid rgba(255, 255, 255, 0.05);
        }

        .resize-handle {
            position: absolute;
            bottom: 4px;
            right: 4px;
            width: 16px;
            height: 16px;
            cursor: se-resize;
            color: rgba(255, 255, 255, 0.2);
            transition: color 0.2s;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .resize-handle:hover {
            color: rgba(135, 206, 250, 0.6);
        }
    </style>
</head>
<body>
    <div class="card">
        <div class="header">
            <div class="drag-area" data-yanm-drag="true">数字时钟</div>
            <div class="actions">
                <button id="formatToggle">24H</button>
            </div>
        </div>
        
        <div class="clock-content">
            <div class="time-row">
                <span id="timeHourMin">00:00</span>
                <span id="timeSec">00</span>
                <span id="timeAmPm"></span>
            </div>
            <div class="date-row" id="dateStr">加载中...</div>
        </div>

        <div class="resize-handle" data-yanm-resize="true">
            <svg viewBox="0 0 10 10" style="width:10px; height:10px; fill:currentColor;">
                <polygon points="10,10 10,7 7,10" />
                <polygon points="10,5 10,2 2,10 5,10" />
            </svg>
        </div>
    </div>

    <script>
        const STATE_KEY = 'yanm_clock_state';
        let state = { format24: true };

        const btnToggle = document.getElementById('formatToggle');
        const elHourMin = document.getElementById('timeHourMin');
        const elSec = document.getElementById('timeSec');
        const elAmPm = document.getElementById('timeAmPm');
        const elDate = document.getElementById('dateStr');

        function updateUI() {
            btnToggle.textContent = state.format24 ? '24H' : '12H';
        }

        function saveState() {
            // 1. 内存已更新
            const val = JSON.stringify(state);
            // 2. 本地兜底 (增加 try...catch 避免由于安全限制导致脚本崩溃)
            try {
                localStorage.setItem(STATE_KEY, val);
            } catch(e) {
                console.warn('localStorage 不可用', e);
            }
            // 3. 宿主保存
            if (window.yanm) {
                window.yanm.invoke('state.set', { key: STATE_KEY, value: val }).catch(console.error);
            }
        }

        function loadLocalState() {
            try {
                const local = localStorage.getItem(STATE_KEY);
                if (local) {
                    Object.assign(state, JSON.parse(local));
                }
            } catch(e) {
                console.warn('读取 localStorage 失败', e);
            }
            updateUI();
        }

        function loadRemoteState() {
            if (window.yanm) {
                window.yanm.invoke('state.get', { key: STATE_KEY })
                    .then(res => {
                        if (res) {
                            try {
                                Object.assign(state, JSON.parse(res));
                                updateUI();
                                try {
                                    localStorage.setItem(STATE_KEY, JSON.stringify(state));
                                } catch(e) {}
                            } catch(e) {}
                        }
                    })
                    .catch(console.error);
            }
        }

        btnToggle.addEventListener('click', () => {
            state.format24 = !state.format24;
            updateUI();
            saveState();
        });

        const days = ['日', '一', '二', '三', '四', '五', '六'];
        
        function tick() {
            const now = new Date();
            let h = now.getHours();
            const m = now.getMinutes();
            const s = now.getSeconds();
            
            let ampmStr = '';
            if (!state.format24) {
                ampmStr = h >= 12 ? 'PM' : 'AM';
                h = h % 12;
                if (h === 0) h = 12;
            }
            
            const hStr = h.toString().padStart(2, '0');
            const mStr = m.toString().padStart(2, '0');
            const sStr = s.toString().padStart(2, '0');
            
            elHourMin.textContent = `${hStr}:${mStr}`;
            elSec.textContent = sStr;
            elAmPm.textContent = ampmStr;
            
            const year = now.getFullYear();
            const month = now.getMonth() + 1;
            const date = now.getDate();
            const day = now.getDay();
            
            elDate.textContent = `${year}年${month}月${date}日 星期${days[day]}`;
        }

        // 初始化序列
        loadLocalState();
        
        // 立即执行一次渲染当前时间
        tick();
        
        // 改用 setInterval 每秒刷新,避免 WebView2 在后台挂起 requestAnimationFrame
        setInterval(tick, 1000);

        function initYanm(retryCount = 0) {
            if (window.yanm) {
                loadRemoteState();
                return;
            }
            if (retryCount < 50) {
                setTimeout(() => initYanm(retryCount + 1), 100);
            }
        }
        
        initYanm();
    </script>
</body>
</html>


回复内容
暂无回复
回复主贴