一、前言

在当今前端开发领域,创造令人印象深刻的视觉体验已成为吸引用户的重要手段。本文将深入解析一个赛博朋克风格的炫酷时钟界面,展示如何结合HTML5、CSS3和JavaScript打造出具有未来科技感的交互式时间显示效果。

二、概述

这个赛博朋克时钟具有以下特点:

  • 霓虹灯风格UI设计:使用鲜艳的霓虹色系(青蓝、粉紫、绿色)

  • 实时时间显示:小时、分钟、秒和日期信息

  • 动态视觉效果:二进制数字雨、数据流、扫描线等背景动画

  • 3D交互体验:鼠标移动产生视角倾斜效果

  • 终端仿真界面:模拟命令行终端的输出效果

  • 响应式交互:点击控制按钮产生粒子爆炸效果

三、实现原理与技术分析

1. 霓虹灯UI设计实现

使用CSS变量定义霓虹色调色板,方便统一管理:

:root {
    --neon-blue: #0ff;
    --neon-pink: #f0f;
    --neon-green: #0f0;
    --neon-purple: #b56bff;
    --dark-bg: #0a0a12;
}

霓虹发光效果通过text-shadowbox-shadow实现:

.time {
    text-shadow: 0 0 15px var(--neon-blue);
    animation: glow 2s ease-in-out infinite alternate;
}

@keyframes glow {
    from { text-shadow: 0 0 10px var(--neon-blue); }
    to { text-shadow: 0 0 20px var(--neon-blue), 0 0 30px var(--neon-blue); }
}

2. 扫描线效果

使用CSS渐变创建经典的CRT显示器扫描线效果:

.scanlines {
    background: linear-gradient(
        rgba(0, 255, 255, 0.05) 50%,
        rgba(0, 0, 0, 0.25) 50%
    );
    background-size: 100% 4px;
    animation: scanline 8s linear infinite;
}

3. 3D透视与交互

利用CSS3的3D变换功能创建立体感:

body {
    perspective: 1000px;
}

.terminal {
    transform-style: preserve-3d;
}

JavaScript处理鼠标移动事件,计算倾斜角度:

interactiveArea.addEventListener('mousemove', (e) => {
    const rect = terminal.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    
    const centerX = rect.width / 2;
    const centerY = rect.height / 2;
    
    const tiltX = (y - centerY) / 20;
    const tiltY = (centerX - x) / 20;
    
    terminal.style.transform = `perspective(1000px) rotateX(${tiltX}deg) rotateY(${tiltY}deg)`;
});

4. 时间更新与齿轮动画

实时更新时间并同步齿轮旋转:

5. 二进制数字雨

function updateTime() {
    const now = new Date();
    const hours = String(now.getHours()).padStart(2, '0');
    const minutes = String(now.getMinutes()).padStart(2, '0');
    const seconds = String(now.getSeconds()).padStart(2, '0');
    
    document.getElementById('time').textContent = `${hours}:${minutes}:${seconds}`;
    
    // 齿轮旋转
    const gears = document.querySelectorAll('.gear');
    gears.forEach((gear, index) => {
        const speed = index === 1 ? -1.5 : 1.5;
        const rotation = (now.getSeconds() * 6 * speed) + (now.getMilliseconds() * 0.006 * speed);
        gear.style.transform = `rotate(${rotation}deg)`;
    });
}

效果

创建经典的《黑客帝国》风格数字雨:

function createBinaryRain() {
    const binaryRain = document.getElementById('binary-rain');
    const cols = Math.floor(window.innerWidth / 20);
    
    for (let i = 0; i < cols; i++) {
        setTimeout(() => {
            createBinaryColumn(i * 20);
        }, i * 100);
    }
}

function createBinaryColumn(left) {
    const col = document.createElement('div');
    col.style.position = 'absolute';
    col.style.left = `${left}px`;
    col.style.top = '0';
    col.style.width = '20px';
    
    binaryRain.appendChild(col);
    
    // 持续添加二进制数字
    const addBinaryDigit = () => {
        const digit = document.createElement('div');
        digit.className = 'binary-digit';
        digit.textContent = Math.random() > 0.5 ? '0' : '1';
        
        const duration = Math.random() * 3 + 2;
        digit.style.animation = `binary-fall ${duration}s linear forwards`;
        
        col.appendChild(digit);
        
        setTimeout(() => digit.remove(), duration * 1000);
        setTimeout(addBinaryDigit, Math.random() * 500 + 100);
    };
    
    addBinaryDigit();
}

6. 数据流效果

创建向上流动的数据粒子效果:

function createDataStream() {
    const dataStream = document.getElementById('data-stream');
    const chars = "01ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$#@%&*";
    
    for (let i = 0; i < 30; i++) {
        setTimeout(() => {
            const particle = document.createElement('div');
            particle.className = 'data-particle';
            
            particle.style.left = `${Math.random() * 100}%`;
            
            let content = '';
            const length = Math.floor(Math.random() * 10) + 5;
            for (let j = 0; j < length; j++) {
                content += chars[Math.floor(Math.random() * chars.length)];
            }
            particle.textContent = content;
            
            const duration = Math.random() * 5 + 3;
            const delay = Math.random() * 5;
            
            particle.style.animation = `matrix-fall ${duration}s linear ${delay}s forwards`;
            dataStream.appendChild(particle);
            
            setTimeout(() => particle.remove(), (duration + delay) * 1000);
        }, i * 300);
    }
}

7. 数据可视化图表

创建动态的数据条形图:

function updateDataVisualization() {
    const container = document.getElementById('data-visualization');
    container.innerHTML = '';
    
    const barCount = 50;
    for (let i = 0; i < barCount; i++) {
        const bar = document.createElement('div');
        bar.className = 'data-bar';
        
        const height = Math.random() * 70 + 10;
        bar.style.height = `${height}px`;
        bar.style.animationDelay = `${Math.random() * 2}s`;
        
        container.appendChild(bar);
    }
}

8. 交互粒子效果

鼠标移动时创建粒子轨迹:

function createMouseParticle(x, y) {
    const particle = document.createElement('div');
    particle.className = 'particle-trail';
    
    particle.style.left = `${x}px`;
    particle.style.top = `${y}px`;
    
    const colors = ['#0ff', '#f0f', '#0f0', '#b56bff'];
    particle.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
    
    document.body.appendChild(particle);
    
    // 淡出效果
    let opacity = 0.8;
    const fadeOut = setInterval(() => {
        opacity -= 0.05;
        particle.style.opacity = opacity;
        
        if (opacity <= 0) {
            clearInterval(fadeOut);
            particle.remove();
        }
    }, 50);
}

四、关键代码解析

1.时间格式化与更新

// 更新时间函数
function updateTime() {
    const now = new Date();
    
    // 格式化时间
    const hours = String(now.getHours()).padStart(2, '0');
    const minutes = String(now.getMinutes()).padStart(2, '0');
    const seconds = String(now.getSeconds()).padStart(2, '0');
    
    // 格式化日期
    const days = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
    const dayName = days[now.getDay()];
    const date = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${dayName}`;
    
    // 更新显示
    document.getElementById('time').textContent = `${hours}:${minutes}:${seconds}`;
    document.getElementById('date').textContent = date;
    
    // 随机颜色变化
    if (Math.random() < 0.1) {
        const colors = ['#0ff', '#f0f', '#0f0', '#b56bff', '#ff6bff'];
        document.getElementById('time').style.color = colors[Math.floor(Math.random() * colors.length)];
    }
}

2.终端消息系统

const terminalMessages = [
    "> 系统时间同步完成",
    "> 量子时钟校准中... 完成度: " + Math.floor(Math.random() * 100) + "%",
    "> 网络时间协议(NTP)已连接",
    // ...更多消息
];

function addTerminalText() {
    const terminal = document.getElementById('terminal-text');
    const randomMessage = terminalMessages[Math.floor(Math.random() * terminalMessages.length)];
    
    const newLine = document.createElement('div');
    newLine.textContent = randomMessage;
    
    terminal.appendChild(newLine);
    
    // 限制行数
    if (terminal.children.length > 10) {
        terminal.removeChild(terminal.children[0]);
    }
    
    terminal.scrollTop = terminal.scrollHeight;
}

五、完整代码


<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>炫酷时钟-水果工作站</title>
    <style>
        :root {
            --neon-blue: #0ff;
            --neon-pink: #f0f;
            --neon-green: #0f0;
            --neon-purple: #b56bff;
            --dark-bg: #0a0a12;
        }
        
        body {
            margin: 0;
            padding: 0;
            background-color: var(--dark-bg);
            overflow: hidden;
            font-family: 'Courier New', monospace;
            color: var(--neon-blue);
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            perspective: 1000px;
        }
        
        .terminal {
            position: relative;
            width: 900px;
            height: 600px;
            background-color: rgba(0, 10, 20, 0.9);
            border: 2px solid var(--neon-blue);
            border-radius: 10px;
            box-shadow: 0 0 30px var(--neon-blue), 
                        inset 0 0 30px rgba(0, 255, 255, 0.3);
            padding: 20px;
            overflow: hidden;
            transform-style: preserve-3d;
            z-index: 10;
        }
        
        .scanlines {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: linear-gradient(
                rgba(0, 255, 255, 0.05) 50%,
                rgba(0, 0, 0, 0.25) 50%
            );
            background-size: 100% 4px;
            pointer-events: none;
            animation: scanline 8s linear infinite;
        }
        
        @keyframes scanline {
            0% { background-position: 0 0; }
            100% { background-position: 0 100%; }
        }
        
        .header {
            display: flex;
            justify-content: space-between;
            border-bottom: 1px solid var(--neon-blue);
            padding-bottom: 10px;
            margin-bottom: 20px;
            text-shadow: 0 0 5px var(--neon-blue);
            font-size: 1.2rem;
        }
        
        .clock-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 60%;
        }
        
        .time {
            font-size: 6rem;
            letter-spacing: 8px;
            margin: 20px 0;
            text-shadow: 0 0 15px var(--neon-blue);
            animation: glow 2s ease-in-out infinite alternate;
            position: relative;
        }
        
        .time::before {
            content: '';
            position: absolute;
            top: -10px;
            left: -10px;
            right: -10px;
            bottom: -10px;
            border: 2px solid var(--neon-blue);
            border-radius: 5px;
            opacity: 0.3;
            pointer-events: none;
            animation: pulse 4s ease-in-out infinite;
        }
        
        .date {
            font-size: 4rem;
            margin-bottom: 30px;
            color: var(--neon-pink);
            text-shadow: 0 0 8px var(--neon-pink);
        }
        
        .gear-container {
            display: flex;
            justify-content: space-around;
            width: 100%;
            margin-top: 30px;
        }
        
        .gear {
            width: 100px;
            height: 100px;
            fill: var(--neon-blue);
            filter: drop-shadow(0 0 8px var(--neon-blue));
            opacity: 0.8;
        }
        
        .gear.small {
            width: 60px;
            height: 60px;
        }
        
        .terminal-text {
            position: absolute;
            bottom: 20px;
            left: 20px;
            right: 20px;
            height: 120px;
            overflow: hidden;
            border-top: 1px solid var(--neon-blue);
            padding-top: 10px;
            font-size: 0.9rem;
            color: var(--neon-green);
        }
        
        .blinking-cursor {
            animation: blink 1s step-end infinite;
        }
        
        @keyframes blink {
            from, to { opacity: 1; }
            50% { opacity: 0; }
        }
        
        @keyframes glow {
            from { text-shadow: 0 0 10px var(--neon-blue); }
            to { text-shadow: 0 0 20px var(--neon-blue), 0 0 30px var(--neon-blue); }
        }
        
        @keyframes pulse {
            0%, 100% { transform: scale(1); opacity: 0.3; }
            50% { transform: scale(1.05); opacity: 0.5; }
        }
        
        .glitch {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"><rect width="100%" height="1" y="50%" fill="%230ff" opacity="0.1"/></svg>');
            opacity: 0;
            pointer-events: none;
            animation: glitch-effect 10s infinite;
        }
        
        @keyframes glitch-effect {
            0%, 100% { opacity: 0; transform: translateX(0); }
            1% { opacity: 0.1; transform: translateX(-5px); }
            2% { opacity: 0; transform: translateX(5px); }
            3% { opacity: 0.1; transform: translateX(0); }
            4% { opacity: 0; }
        }
        
        .controls {
            position: absolute;
            top: 20px;
            right: 20px;
            display: flex;
        }
        
        .control-btn {
            width: 14px;
            height: 14px;
            border-radius: 50%;
            margin-left: 10px;
            cursor: pointer;
            box-shadow: 0 0 5px currentColor;
        }
        
        .close { background-color: #f00; color: #f00; }
        .minimize { background-color: #ff0; color: #ff0; }
        .maximize { background-color: #0f0; color: #0f0; }
        
        .data-stream {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 1;
            overflow: hidden;
        }
        
        .data-particle {
            position: absolute;
            font-family: 'Courier New', monospace;
            font-size: 12px;
            color: rgba(0, 255, 255, 0.7);
            white-space: nowrap;
            text-shadow: 0 0 3px var(--neon-blue);
            transform: translateY(-100%);
        }
        
        .matrix-particle {
            position: absolute;
            font-family: 'Courier New', monospace;
            font-size: 14px;
            color: rgba(0, 255, 0, 0.7);
            opacity: 0;
            animation: matrix-fall linear forwards;
        }
        
        @keyframes matrix-fall {
            0% { transform: translateY(-20px); opacity: 0; }
            10% { opacity: 0.8; }
            90% { opacity: 0.8; }
            100% { transform: translateY(600px); opacity: 0; }
        }
        
        .data-visualization {
            position: absolute;
            bottom: 150px;
            left: 20px;
            right: 20px;
            height: 80px;
            display: flex;
            align-items: flex-end;
            gap: 2px;
        }
        
        .data-bar {
            flex: 1;
            background: linear-gradient(to top, var(--neon-purple), var(--neon-blue));
            border-radius: 2px 2px 0 0;
            box-shadow: 0 0 5px var(--neon-purple);
            min-width: 3px;
            opacity: 0.7;
        }
        
        .binary-rain {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 0;
        }
        
        .binary-digit {
            position: absolute;
            font-family: 'Courier New', monospace;
            color: rgba(0, 255, 0, 0.3);
            font-size: 16px;
            animation: binary-fall linear forwards;
        }
        
        @keyframes binary-fall {
            0% { transform: translateY(-20px); opacity: 0; }
            10% { opacity: 0.5; }
            90% { opacity: 0.5; }
            100% { transform: translateY(600px); opacity: 0; }
        }
        
        .holographic-line {
            position: absolute;
            height: 1px;
            background: linear-gradient(to right, transparent, var(--neon-blue), transparent);
            box-shadow: 0 0 5px var(--neon-blue);
            opacity: 0.3;
            transform-origin: left center;
            animation: hologram-scan 8s linear infinite;
        }
        
        @keyframes hologram-scan {
            0% { transform: rotate(0deg) scaleX(0); opacity: 0; }
            10% { opacity: 0.5; }
            50% { transform: rotate(180deg) scaleX(1); }
            90% { opacity: 0.5; }
            100% { transform: rotate(360deg) scaleX(0); opacity: 0; }
        }
        
        .interactive-area {
            position: absolute;
            width: 100%;
            height: 100%;
            top: 0;
            left: 0;
            z-index: 100;
        }
        
        .particle-trail {
            position: absolute;
            width: 4px;
            height: 4px;
            border-radius: 50%;
            background-color: var(--neon-blue);
            pointer-events: none;
            z-index: 1000;
        }
        
        .circuit-line {
            position: absolute;
            height: 1px;
            background: linear-gradient(to right, transparent, var(--neon-blue), transparent);
            box-shadow: 0 0 5px var(--neon-blue);
            opacity: 0.5;
            transform-origin: left center;
        }
    </style>
</head>
<body>
    <div class="binary-rain" id="binary-rain"></div>
    
    <div class="terminal">
        <div class="glitch"></div>
        <div class="scanlines"></div>
        <div class="data-stream" id="data-stream"></div>
        
        <div class="header">
            <div>CYBERNETIC TIME DISPLAY v4.2.1</div>
            <div>SYSTEM STATUS: <span id="system-status">NOMINAL</span></div>
        </div>
        
        <div class="controls">
            <div class="control-btn close" onclick="closeEffect()"></div>
            <div class="control-btn minimize" onclick="minimizeEffect()"></div>
            <div class="control-btn maximize" onclick="maximizeEffect()"></div>
        </div>
        
        <div class="clock-container">
            <div class="date" id="date"></div>
            <div class="time" id="time"></div>
            
            <div class="data-visualization" id="data-visualization"></div>
            
            <div class="gear-container">
                <svg class="gear" viewBox="0 0 100 100">
                    <path d="M50,15 L50,25 M50,75 L50,85 M15,50 L25,50 M75,50 L85,50" stroke="var(--neon-blue)" stroke-width="3"/>
                    <circle cx="50" cy="50" r="30" fill="none" stroke="var(--neon-blue)" stroke-width="3"/>
                    <circle cx="50" cy="50" r="10" fill="var(--dark-bg)" stroke="var(--neon-blue)" stroke-width="3"/>
                    <path d="M50,30 A20,20 0 0 1 70,50 A20,20 0 0 1 50,70 A20,20 0 0 1 30,50 A20,20 0 0 1 50,30 Z" 
                          fill="none" stroke="var(--neon-blue)" stroke-width="3" stroke-dasharray="5,5"/>
                </svg>
                
                <svg class="gear small" viewBox="0 0 100 100">
                    <path d="M50,20 L50,30 M50,70 L50,80 M20,50 L30,50 M70,50 L80,50" stroke="var(--neon-pink)" stroke-width="3"/>
                    <circle cx="50" cy="50" r="25" fill="none" stroke="var(--neon-pink)" stroke-width="3"/>
                    <circle cx="50" cy="50" r="8" fill="var(--dark-bg)" stroke="var(--neon-pink)" stroke-width="3"/>
                    <path d="M50,25 A25,25 0 0 1 75,50 A25,25 0 0 1 50,75 A25,25 0 0 1 25,50 A25,25 0 0 1 50,25 Z" 
                          fill="none" stroke="var(--neon-pink)" stroke-width="3" stroke-dasharray="3,3"/>
                </svg>
                
                <svg class="gear" viewBox="0 0 100 100">
                    <path d="M50,10 L50,20 M50,80 L50,90 M10,50 L20,50 M80,50 L90,50" stroke="var(--neon-blue)" stroke-width="3"/>
                    <circle cx="50" cy="50" r="35" fill="none" stroke="var(--neon-blue)" stroke-width="3"/>
                    <circle cx="50" cy="50" r="15" fill="var(--dark-bg)" stroke="var(--neon-blue)" stroke-width="3"/>
                    <path d="M50,15 A35,35 0 0 1 85,50 A35,35 0 0 1 50,85 A35,35 0 0 1 15,50 A35,35 0 0 1 50,15 Z" 
                          fill="none" stroke="var(--neon-blue)" stroke-width="3" stroke-dasharray="7,7"/>
                </svg>
            </div>
        </div>
        
        <div class="terminal-text" id="terminal-text"></div>
        
        <div class="interactive-area" id="interactive-area"></div>
    </div>

    <script>
        // 更新时间
        function updateTime() {
            const now = new Date();
            
            // 格式化时间
            const hours = String(now.getHours()).padStart(2, '0');
            const minutes = String(now.getMinutes()).padStart(2, '0');
            const seconds = String(now.getSeconds()).padStart(2, '0');
            
            // 格式化日期
            const days = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
            const dayName = days[now.getDay()];
            const date = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${dayName}`;
            
            // 更新显示
            document.getElementById('time').textContent = `${hours}:${minutes}:${seconds}`;
            document.getElementById('date').textContent = date;
            
            // 随机颜色变化
            if (Math.random() < 0.1) {
                const colors = ['#0ff', '#f0f', '#0f0', '#b56bff', '#ff6bff'];
                document.getElementById('time').style.color = colors[Math.floor(Math.random() * colors.length)];
            }
            
            // 旋转齿轮
            const gears = document.querySelectorAll('.gear');
            gears.forEach((gear, index) => {
                const speed = index === 1 ? -1.5 : 1.5; // 中间的齿轮反向旋转
                const rotation = (now.getSeconds() * 6 * speed) + (now.getMilliseconds() * 0.006 * speed);
                gear.style.transform = `rotate(${rotation}deg)`;
            });
            
            // 随机添加终端文本
            if (Math.random() < 0.4) {
                addTerminalText();
            }
            
            // 更新数据可视化
            updateDataVisualization();
            
            // 随机更新系统状态
            if (Math.random() < 0.05) {
                updateSystemStatus();
            }
        }
        
        // 添加终端文本
        const terminalMessages = [
            "> 系统时间同步完成",
            "> 量子时钟校准中... 完成度: " + Math.floor(Math.random() * 100) + "%",
            "> 网络时间协议(NTP)已连接",
            "> 检测到时间波动: 0.000" + Math.floor(Math.random() * 9) + "s",
            "> 安全协议激活",
            "> 加密时间戳生成",
            "> 启动时间验证序列",
            "> 时空连续性检查通过",
            "> 时间流稳定",
            "> 警告: 检测到微小时间偏差",
            "> 自动校正已应用",
            "> 数据流分析中...",
            "> 接收 " + Math.floor(Math.random() * 1000) + " 个数据包",
            "> 处理速度: " + (Math.random() * 10 + 5).toFixed(2) + " GHz",
            "> 内存使用率: " + Math.floor(Math.random() * 30 + 50) + "%",
            "> 量子加密通道已建立",
            "> 虚拟粒子加速中...",
            "> 数据矩阵重构完成"
        ];
        
        function addTerminalText() {
            const terminal = document.getElementById('terminal-text');
            const randomMessage = terminalMessages[Math.floor(Math.random() * terminalMessages.length)];
            
            // 创建新行
            const newLine = document.createElement('div');
            newLine.textContent = randomMessage;
            
            // 添加到终端
            terminal.appendChild(newLine);
            
            // 限制行数
            if (terminal.children.length > 10) {
                terminal.removeChild(terminal.children[0]);
            }
            
            // 滚动到底部
            terminal.scrollTop = terminal.scrollHeight;
        }
        
        // 创建数据流效果
        function createDataStream() {
            const dataStream = document.getElementById('data-stream');
            const chars = "01ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$#@%&*";
            
            for (let i = 0; i < 30; i++) {
                setTimeout(() => {
                    const particle = document.createElement('div');
                    particle.className = 'data-particle';
                    
                    // 随机位置
                    const left = Math.random() * 100;
                    particle.style.left = `${left}%`;
                    
                    // 随机内容
                    let content = '';
                    const length = Math.floor(Math.random() * 10) + 5;
                    for (let j = 0; j < length; j++) {
                        content += chars[Math.floor(Math.random() * chars.length)];
                    }
                    particle.textContent = content;
                    
                    // 随机动画
                    const duration = Math.random() * 5 + 3;
                    const delay = Math.random() * 5;
                    
                    particle.style.animation = `matrix-fall ${duration}s linear ${delay}s forwards`;
                    particle.style.fontSize = `${Math.random() * 6 + 10}px`;
                    
                    dataStream.appendChild(particle);
                    
                    // 移除元素
                    setTimeout(() => {
                        particle.remove();
                    }, (duration + delay) * 1000);
                }, i * 300);
            }
        }
        
        // 创建二进制雨效果
        function createBinaryRain() {
            const binaryRain = document.getElementById('binary-rain');
            const cols = Math.floor(window.innerWidth / 20);
            
            for (let i = 0; i < cols; i++) {
                setTimeout(() => {
                    createBinaryColumn(i * 20);
                }, i * 100);
            }
        }
        
        function createBinaryColumn(left) {
            const binaryRain = document.getElementById('binary-rain');
            const chars = "01";
            
            const col = document.createElement('div');
            col.style.position = 'absolute';
            col.style.left = `${left}px`;
            col.style.top = '0';
            col.style.width = '20px';
            
            binaryRain.appendChild(col);
            
            // 持续添加二进制数字
            const addBinaryDigit = () => {
                const digit = document.createElement('div');
                digit.className = 'binary-digit';
                digit.textContent = chars[Math.floor(Math.random() * chars.length)];
                digit.style.left = `${Math.random() * 10}px`;
                
                const duration = Math.random() * 3 + 2;
                digit.style.animation = `binary-fall ${duration}s linear forwards`;
                
                col.appendChild(digit);
                
                // 移除元素
                setTimeout(() => {
                    digit.remove();
                }, duration * 1000);
                
                // 随机间隔添加下一个
                setTimeout(addBinaryDigit, Math.random() * 500 + 100);
            };
            
            addBinaryDigit();
        }
        
        // 更新数据可视化
        function updateDataVisualization() {
            const container = document.getElementById('data-visualization');
            container.innerHTML = '';
            
            const barCount = 50;
            for (let i = 0; i < barCount; i++) {
                const bar = document.createElement('div');
                bar.className = 'data-bar';
                
                // 随机高度
                const height = Math.random() * 70 + 10;
                bar.style.height = `${height}px`;
                
                // 随机动画延迟
                bar.style.animationDelay = `${Math.random() * 2}s`;
                
                container.appendChild(bar);
            }
        }
        
        // 更新系统状态
        function updateSystemStatus() {
            const statusElement = document.getElementById('system-status');
            const statuses = [
                { text: "NOMINAL", color: "#0f0" },
                { text: "WARNING", color: "#ff0" },
                { text: "CRITICAL", color: "#f00" },
                { text: "OPTIMAL", color: "#0ff" },
                { text: "STANDBY", color: "#b56bff" }
            ];
            
            const randomStatus = statuses[Math.floor(Math.random() * statuses.length)];
            statusElement.textContent = randomStatus.text;
            statusElement.style.color = randomStatus.color;
            statusElement.style.textShadow = `0 0 10px ${randomStatus.color}`;
            
            // 闪烁效果
            statusElement.style.animation = 'none';
            setTimeout(() => {
                statusElement.style.animation = 'blink 0.5s step-end 3';
            }, 10);
        }
        
        // 创建全息扫描线
        function createHolographicLines() {
            const terminal = document.querySelector('.terminal');
            
            for (let i = 0; i < 5; i++) {
                const line = document.createElement('div');
                line.className = 'holographic-line';
                
                // 随机位置
                line.style.top = `${Math.random() * 100}%`;
                line.style.left = `${Math.random() * 100}%`;
                
                // 随机宽度
                const width = Math.random() * 200 + 100;
                line.style.width = `${width}px`;
                
                // 随机延迟
                line.style.animationDelay = `${Math.random() * 5}s`;
                
                terminal.appendChild(line);
            }
        }
        
        // 创建电路线效果
        function createCircuitLines() {
            const terminal = document.querySelector('.terminal');
            
            // 水平线
            for (let i = 0; i < 3; i++) {
                const line = document.createElement('div');
                line.className = 'circuit-line';
                
                line.style.top = `${Math.random() * 100}%`;
                line.style.left = '0';
                line.style.width = '100%';
                line.style.transform = 'rotate(0deg)';
                
                terminal.appendChild(line);
            }
            
            // 垂直线
            for (let i = 0; i < 3; i++) {
                const line = document.createElement('div');
                line.className = 'circuit-line';
                
                line.style.left = `${Math.random() * 100}%`;
                line.style.top = '0';
                line.style.width = '100%';
                line.style.transform = 'rotate(90deg)';
                
                terminal.appendChild(line);
            }
            
            // 对角线
            for (let i = 0; i < 2; i++) {
                const line = document.createElement('div');
                line.className = 'circuit-line';
                
                line.style.top = '0';
                line.style.left = '0';
                line.style.width = '141%';
                line.style.transform = `rotate(${i === 0 ? 45 : -45}deg)`;
                line.style.transformOrigin = 'left center';
                
                terminal.appendChild(line);
            }
        }
        
        // 交互效果
        function setupInteractivity() {
            const interactiveArea = document.getElementById('interactive-area');
            const terminal = document.querySelector('.terminal');
            
            interactiveArea.addEventListener('mousemove', (e) => {
                const rect = terminal.getBoundingClientRect();
                const x = e.clientX - rect.left;
                const y = e.clientY - rect.top;
                
                // 计算相对于中心的位置
                const centerX = rect.width / 2;
                const centerY = rect.height / 2;
                
                // 计算倾斜角度
                const tiltX = (y - centerY) / 20;
                const tiltY = (centerX - x) / 20;
                
                terminal.style.transform = `perspective(1000px) rotateX(${tiltX}deg) rotateY(${tiltY}deg)`;
                
                // 创建跟随鼠标的粒子轨迹
                createMouseParticle(x, y);
                
                // 随机创建数据流
                if (Math.random() < 0.3) {
                    createDataStream();
                }
            });
            
            interactiveArea.addEventListener('mouseleave', () => {
                terminal.style.transform = 'perspective(1000px) rotateX(0) rotateY(0)';
            });
            
            // 点击效果
            interactiveArea.addEventListener('click', (e) => {
                const rect = terminal.getBoundingClientRect();
                const x = e.clientX - rect.left;
                const y = e.clientY - rect.top;
                
                createClickEffect(x, y);
            });
        }
        
        function createMouseParticle(x, y) {
            const particle = document.createElement('div');
            particle.className = 'particle-trail';
            
            particle.style.left = `${x}px`;
            particle.style.top = `${y}px`;
            particle.style.width = `${Math.random() * 6 + 2}px`;
            particle.style.height = particle.style.width;
            
            // 随机颜色
            const colors = ['#0ff', '#f0f', '#0f0', '#b56bff'];
            particle.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
            
            document.body.appendChild(particle);
            
            // 淡出效果
            let opacity = 0.8;
            const fadeOut = setInterval(() => {
                opacity -= 0.05;
                particle.style.opacity = opacity;
                
                if (opacity <= 0) {
                    clearInterval(fadeOut);
                    particle.remove();
                }
            }, 50);
        }
        
        function createClickEffect(x, y) {
            // 创建冲击波效果
            const ripple = document.createElement('div');
            ripple.style.position = 'absolute';
            ripple.style.left = `${x}px`;
            ripple.style.top = `${y}px`;
            ripple.style.width = '10px';
            ripple.style.height = '10px';
            ripple.style.borderRadius = '50%';
            ripple.style.backgroundColor = '#0ff';
            ripple.style.transform = 'translate(-50%, -50%)';
            ripple.style.boxShadow = '0 0 10px #0ff';
            ripple.style.pointerEvents = 'none';
            
            document.querySelector('.terminal').appendChild(ripple);
            
            // 动画
            let size = 10;
            let opacity = 1;
            const grow = setInterval(() => {
                size += 10;
                opacity -= 0.05;
                
                ripple.style.width = `${size}px`;
                ripple.style.height = `${size}px`;
                ripple.style.opacity = opacity;
                
                if (opacity <= 0) {
                    clearInterval(grow);
                    ripple.remove();
                }
            }, 20);
            
            // 创建数据爆发
            for (let i = 0; i < 10; i++) {
                setTimeout(() => {
                    createDataParticle(x, y);
                }, i * 100);
            }
        }
        
        function createDataParticle(x, y) {
            const particle = document.createElement('div');
            particle.className = 'data-particle';
            
            particle.style.left = `${x}px`;
            particle.style.top = `${y}px`;
            
            const chars = "01ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$#@%&*";
            let content = '';
            const length = Math.floor(Math.random() * 5) + 3;
            for (let j = 0; j < length; j++) {
                content += chars[Math.floor(Math.random() * chars.length)];
            }
            particle.textContent = content;
            
            // 随机方向
            const angle = Math.random() * Math.PI * 2;
            const distance = Math.random() * 100 + 50;
            
            const duration = Math.random() * 2 + 1;
            particle.style.animation = `none`;
            particle.style.transform = `translate(-50%, -50%)`;
            
            document.querySelector('.terminal').appendChild(particle);
            
            // 自定义动画
            let progress = 0;
            const animate = () => {
                progress += 0.02;
                if (progress > 1) {
                    particle.remove();
                    return;
                }
                
                const currentX = x + Math.cos(angle) * distance * progress;
                const currentY = y + Math.sin(angle) * distance * progress;
                const currentOpacity = 1 - progress;
                
                particle.style.left = `${currentX}px`;
                particle.style.top = `${currentY}px`;
                particle.style.opacity = currentOpacity;
                
                requestAnimationFrame(animate);
            };
            
            requestAnimationFrame(animate);
        }
        
        // 控制按钮效果
        function closeEffect() {
            const terminal = document.querySelector('.terminal');
            terminal.style.animation = 'glitch-effect 0.5s';
            
            // 创建爆炸粒子
            for (let i = 0; i < 50; i++) {
                createDataParticle(
                    Math.random() * terminal.offsetWidth,
                    Math.random() * terminal.offsetHeight
                );
            }
            
            setTimeout(() => {
                terminal.style.display = 'none';
                document.body.style.backgroundColor = '#000';
                document.body.innerHTML = `
                    <div style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); 
                    color:#f00;font-size:3rem;text-align:center;text-shadow:0 0 10px #f00;">
                        SYSTEM TERMINATED
                        <div style="font-size:1rem; margin-top:20px; color:#0ff;">Connection lost...</div>
                    </div>
                `;
            }, 500);
        }
        
        function minimizeEffect() {
            const terminal = document.querySelector('.terminal');
            terminal.style.transition = 'all 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55)';
            terminal.style.transform = 'perspective(1000px) translateZ(-500px) scale(0.2) rotateX(60deg)';
            terminal.style.opacity = '0';
            
            setTimeout(() => {
                terminal.style.display = 'none';
                setTimeout(() => {
                    terminal.style.display = 'block';
                    terminal.style.transform = 'perspective(1000px) translateZ(0) scale(1) rotateX(0)';
                    terminal.style.opacity = '1';
                    setTimeout(() => {
                        terminal.style.transition = '';
                    }, 500);
                }, 2000);
            }, 500);
        }
        
        function maximizeEffect() {
            const terminal = document.querySelector('.terminal');
            terminal.style.transition = 'all 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55)';
            
            if (terminal.classList.contains('maximized')) {
                terminal.style.width = '900px';
                terminal.style.height = '600px';
                terminal.classList.remove('maximized');
            } else {
                terminal.style.width = '95vw';
                terminal.style.height = '95vh';
                terminal.classList.add('maximized');
            }
            
            setTimeout(() => {
                terminal.style.transition = '';
            }, 500);
        }
        
        // 初始化
        function init() {
            updateTime();
            setInterval(updateTime, 1000);
            
            setupInteractivity();
            createBinaryRain();
            createHolographicLines();
            createCircuitLines();
            
            // 初始数据流
            setInterval(createDataStream, 2000);
            
            // 初始终端消息
            for (let i = 0; i < 5; i++) {
                setTimeout(addTerminalText, i * 500);
            }
        }
        
        // 启动
        window.onload = init;
    </script>
</body>
</html>

六、总结

这个赛博朋克风格时钟展示了现代前端技术的强大能力,结合了CSS3动画、JavaScript交互和创意UI设计。通过分解实现细节,我们可以看到如何:

  • 使用CSS变量管理设计系统

  • 利用CSS动画创建流畅的视觉效果

  • 通过JavaScript实现复杂的交互逻辑

  • 使用DOM操作创建动态粒子系统

  • 结合3D变换增强用户体验

这种类型的项目不仅具有视觉冲击力,也是学习前端高级技术的绝佳实践。开发者可以在此基础上扩展功能、优化性能,或将其整合到更大的应用中作为亮点组件。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐