赛博朋克风格炫酷时钟:HTML5+CSS3+JavaScript打造未来感时间显示界面
·
一、前言
在当今前端开发领域,创造令人印象深刻的视觉体验已成为吸引用户的重要手段。本文将深入解析一个赛博朋克风格的炫酷时钟界面,展示如何结合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-shadow和box-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变换增强用户体验
这种类型的项目不仅具有视觉冲击力,也是学习前端高级技术的绝佳实践。开发者可以在此基础上扩展功能、优化性能,或将其整合到更大的应用中作为亮点组件。
更多推荐


所有评论(0)