前言:当人类开始和AI吵架
某天深夜,当我对着IDE疯狂敲击键盘时,突然灵光乍现:"要是能写个程序,把现在的烦恼寄给未来的自己就好了!"
(此时Trae突然从代码编辑器里探出头)
Trae: "您这是想给自己造个数字版时空快递员吗?"
我: "对啊对啊!但是我的CSS连盒子模型都搞不定..."
Trae: "(推了推不存在的黑框眼镜)建议从localStorage开始,再用crypto-js给数据穿层量子护甲。"
功能亮点:不只是"Hello World"的升级版
- 时空快递员模式:支持文字/图片/音频三重时空包裹投递
- 量子加密保险箱:用crypto-js给记忆穿三层纳米防护衣
- 时间炸弹预警系统:倒计时精确到毫秒,CSS粒子爆破特效堪比烟花秀
- 未来时空漫游指南:到达指定日期自动触发《星际迷航》式全息投影
技术实现:当代程序员的炼金术
1. 时空定位引擎(localStorage+crypto-js)
// 加密密钥:比星巴克密码安全指数高3个数量级
const SECRET_KEY = 'time-capsule-secret-key';
// 量子纠缠加密函数
function encryptData(data) {
return CryptoJS.AES.encrypt(JSON.stringify(data), SECRET_KEY).toString();
}
2. 时间坐标系(倒计时计算)
// 浏览器时间扭曲算法
function loadCapsules() {
const capsules = JSON.parse(localStorage.getItem('capsules') || '[]');
capsules.forEach(encryptedCapsule => {
const capsule = decryptData(encryptedCapsule);
const timeLeft = new Date(capsule.openDate) - new Date();
// 当前宇宙与目标宇宙的时间差转换为"天"单位
const days = Math.floor(timeLeft / (1000 * 60 * 60 * 24));
});
}
3. 超维动画系统(CSS粒子爆破)
.particle {
position: absolute;
width: 5px;
height: 5px;
border-radius: 50%;
animation: explode 0.5s ease-out forwards;
}
@keyframes explode {
0% { transform: scale(1); opacity: 1; }
100% { transform: scale(3); opacity: 0; }
}
主要对话:Trae发挥神力
我:"创意时间胶囊 功能亮点: 用户输入文字、图片或音频(录音功能),设定未来某天打开。 数据加密存储(crypto-js 加密后存入 localStorage)。 到达指定日期后,触发惊喜动画(CSS 粒子爆破、音效)。 技术实现: JS 计算当前时间与目标时间差,动态倒计时。 CSS 动画模拟“胶囊打开”效果。 示例:用户写下“2025年7月1日给未来的自己”,到那天打开时播放预设的语音和文字。"
我:"CSS样式可以帮我改的更加美观,淡蓝色主题"
开发历程:一场与浏览器的拉锯战
Trae: "建议用MediaRecorder API实现语音捕获"
我: "那玩意会不会吃内存啊?"
Trae: "放心,它只会吃你设置的音频类型,比如audio/wav"
我: "那用户权限怎么处理?"
Trae: "(甩出代码)试试这个优雅的Promise链:navigator.mediaDevices.getUserMedia({ audio: true })"
源码大赏:当代程序员的《清明上河图》
完整源码如下(已通过量子计算机验证无bug):
index.html
<!-- 时空胶囊主控面板 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>创意时间胶囊</title>
<link rel="stylesheet" href="styles.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
</head>
<body>
<div class="container">
<h1>创意时间胶囊⏱️</h1>
<div class="capsule-form">
<div class="input-group">
<label for="message">写下你想对未来的自己说的话:</label>
<textarea id="message" rows="4" placeholder="在这里输入你的消息..."></textarea>
</div>
<div class="input-group">
<label for="openDate">选择打开日期:</label>
<input type="datetime-local" id="openDate">
</div>
<div class="input-group">
<label for="audioInput">录制语音(可选):</label>
<button id="recordButton">开始录音</button>
<audio id="audioPreview" controls style="display: none;"></audio>
</div>
<button id="createCapsule" class="primary-button">创建时间胶囊🥰</button>
</div>
<div class="capsule-list">
<h2>我的时间胶囊⏲️</h2>
<div id="capsules"></div>
</div>
</div>
<div id="particles" class="particles"></div>
<script src="script.js"></script>
</body>
</html>
script.js(加密/录音核心逻辑)
// 时空扭曲初始化
// 加密密钥
const SECRET_KEY = 'time-capsule-secret-key';
// 录音相关变量
let mediaRecorder;
let audioChunks = [];
let isRecording = false;
// DOM 元素
const recordButton = document.getElementById('recordButton');
const audioPreview = document.getElementById('audioPreview');
const createCapsuleButton = document.getElementById('createCapsule');
const capsulesContainer = document.getElementById('capsules');
// 初始化录音功能
async function initRecording() {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = (event) => {
audioChunks.push(event.data);
};
mediaRecorder.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
const audioUrl = URL.createObjectURL(audioBlob);
audioPreview.src = audioUrl;
audioPreview.style.display = 'block';
};
} catch (err) {
console.error('录音初始化失败:', err);
alert('无法访问麦克风,请确保已授予权限。');
}
}
// 切换录音状态
function toggleRecording() {
if (!mediaRecorder) return;
if (!isRecording) {
audioChunks = [];
mediaRecorder.start();
recordButton.textContent = '停止录音';
isRecording = true;
} else {
mediaRecorder.stop();
recordButton.textContent = '开始录音';
isRecording = false;
}
}
// 加密数据
function encryptData(data) {
return CryptoJS.AES.encrypt(JSON.stringify(data), SECRET_KEY).toString();
}
// 解密数据
function decryptData(encryptedData) {
const bytes = CryptoJS.AES.decrypt(encryptedData, SECRET_KEY);
return JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
}
// 创建时间胶囊
function createCapsule() {
const message = document.getElementById('message').value;
const openDate = document.getElementById('openDate').value;
const audioUrl = audioPreview.src;
if (!message || !openDate) {
alert('请填写消息和打开日期!');
return;
}
const capsule = {
message,
openDate,
audioUrl,
createdAt: new Date().toISOString()
};
const encryptedCapsule = encryptData(capsule);
const capsules = JSON.parse(localStorage.getItem('capsules') || '[]');
capsules.push(encryptedCapsule);
localStorage.setItem('capsules', JSON.stringify(capsules));
alert('时间胶囊创建成功!');
loadCapsules();
resetForm();
}
// 重置表单
function resetForm() {
document.getElementById('message').value = '';
document.getElementById('openDate').value = '';
audioPreview.style.display = 'none';
audioPreview.src = '';
}
// 加载时间胶囊列表
function loadCapsules() {
const capsules = JSON.parse(localStorage.getItem('capsules') || '[]');
capsulesContainer.innerHTML = '';
capsules.forEach((encryptedCapsule, index) => {
const capsule = decryptData(encryptedCapsule);
const openDate = new Date(capsule.openDate);
const now = new Date();
const capsuleElement = document.createElement('div');
capsuleElement.className = 'capsule-item';
if (openDate <= now) {
capsuleElement.innerHTML = `
<h3>已到打开时间!</h3>
<p>${capsule.message}</p>
${capsule.audioUrl ? `<audio src="${capsule.audioUrl}" controls></audio>` : ''}
<button onclick="openCapsule(${index})">打开胶囊</button>
`;
} else {
const timeLeft = openDate - now;
const days = Math.floor(timeLeft / (1000 * 60 * 60 * 24));
capsuleElement.innerHTML = `
<h3>等待打开中...</h3>
<p>距离打开还有 ${days} 天</p>
<p>创建时间:${new Date(capsule.createdAt).toLocaleString()}</p>
`;
}
capsulesContainer.appendChild(capsuleElement);
});
}
// 打开时间胶囊
function openCapsule(index) {
const capsules = JSON.parse(localStorage.getItem('capsules') || '[]');
const capsule = decryptData(capsules[index]);
// 创建粒子效果
createParticles();
// 播放音效
const audio = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-magical-coin-win-1936.mp3');
audio.play();
// 显示消息
alert(`来自过去的消息:\n\n${capsule.message}`);
// 从存储中移除已打开的胶囊
capsules.splice(index, 1);
localStorage.setItem('capsules', JSON.stringify(capsules));
loadCapsules();
}
// 创建粒子效果
function createParticles() {
const particlesContainer = document.getElementById('particles');
particlesContainer.innerHTML = '';
for (let i = 0; i < 50; i++) {
const particle = document.createElement('div');
particle.className = 'particle';
particle.style.left = `${Math.random() * 100}%`;
particle.style.top = `${Math.random() * 100}%`;
particle.style.backgroundColor = `hsl(${Math.random() * 360}, 100%, 50%)`;
particlesContainer.appendChild(particle);
}
setTimeout(() => {
particlesContainer.innerHTML = '';
}, 1000);
}
// 事件监听
recordButton.addEventListener('click', toggleRecording);
createCapsuleButton.addEventListener('click', createCapsule);
// 初始化
initRecording();
loadCapsules();
// 定期检查胶囊状态
setInterval(loadCapsules, 60000); // 每分钟检查一次
styles.css(淡蓝色主题宇宙)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary-color: #4a90e2;
--primary-light: #e8f1fc;
--primary-dark: #2c5282;
--accent-color: #63b3ed;
--text-color: #2d3748;
--text-light: #718096;
--background: #f7fafc;
--white: #ffffff;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--transition: all 0.3s ease;
}
body {
font-family: 'Microsoft YaHei', -apple-system, BlinkMacSystemFont, sans-serif;
background: linear-gradient(135deg, var(--background) 0%, var(--primary-light) 100%);
min-height: 100vh;
padding: 20px;
color: var(--text-color);
line-height: 1.6;
}
.container {
max-width: 800px;
margin: 0 auto;
background: var(--white);
padding: 40px;
border-radius: 20px;
box-shadow: var(--shadow);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
h1 {
text-align: center;
color: var(--primary-dark);
margin-bottom: 40px;
font-size: 2.5em;
font-weight: 700;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
}
h2 {
color: var(--primary-dark);
margin-bottom: 20px;
font-size: 1.8em;
}
.input-group {
margin-bottom: 25px;
position: relative;
}
label {
display: block;
margin-bottom: 10px;
color: var(--text-color);
font-weight: 600;
font-size: 1.1em;
}
textarea, input[type="datetime-local"] {
width: 100%;
padding: 15px;
border: 2px solid var(--primary-light);
border-radius: 12px;
font-size: 16px;
transition: var(--transition);
background: var(--white);
color: var(--text-color);
}
textarea:focus, input[type="datetime-local"]:focus {
border-color: var(--primary-color);
outline: none;
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.2);
}
textarea {
min-height: 120px;
resize: vertical;
}
.primary-button {
background: var(--primary-color);
color: var(--white);
border: none;
padding: 15px 30px;
border-radius: 12px;
cursor: pointer;
font-size: 1.1em;
font-weight: 600;
width: 100%;
transition: var(--transition);
text-transform: uppercase;
letter-spacing: 1px;
}
.primary-button:hover {
background: var(--primary-dark);
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(74, 144, 226, 0.2);
}
#recordButton {
background: var(--accent-color);
color: var(--white);
border: none;
padding: 12px 24px;
border-radius: 10px;
cursor: pointer;
margin-bottom: 15px;
font-weight: 600;
transition: var(--transition);
}
#recordButton:hover {
background: var(--primary-dark);
transform: translateY(-2px);
}
.capsule-list {
margin-top: 50px;
}
.capsule-item {
background: var(--primary-light);
padding: 25px;
border-radius: 15px;
margin-bottom: 20px;
border-left: 5px solid var(--primary-color);
transition: var(--transition);
box-shadow: var(--shadow);
}
.capsule-item:hover {
transform: translateX(5px);
box-shadow: 0 6px 12px rgba(74, 144, 226, 0.15);
}
.capsule-item h3 {
color: var(--primary-dark);
margin-bottom: 15px;
font-size: 1.3em;
}
.capsule-item p {
color: var(--text-light);
margin-bottom: 10px;
}
.capsule-item button {
background: var(--primary-color);
color: var(--white);
border: none;
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
transition: var(--transition);
margin-top: 15px;
}
.capsule-item button:hover {
background: var(--primary-dark);
transform: translateY(-2px);
}
.particles {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 1000;
}
@keyframes particle {
0% {
transform: translateY(0) rotate(0deg) scale(1);
opacity: 1;
}
100% {
transform: translateY(-100px) rotate(360deg) scale(0);
opacity: 0;
}
}
.particle {
position: absolute;
width: 8px;
height: 8px;
background: var(--primary-color);
border-radius: 50%;
animation: particle 1.5s ease-out forwards;
box-shadow: 0 0 10px var(--primary-color);
}
/* 响应式设计 */
@media (max-width: 768px) {
.container {
padding: 20px;
}
h1 {
font-size: 2em;
}
.input-group {
margin-bottom: 20px;
}
textarea, input[type="datetime-local"] {
padding: 12px;
}
}
/* 自定义滚动条 */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: var(--primary-light);
}
::-webkit-scrollbar-thumb {
background: var(--primary-color);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--primary-dark);
}
结语:当代码遇见诗意
现在,我的时间胶囊里躺着这样一条消息:"2025年7月1日,如果你还在纠结要不要辞职创业,记得看看这条消息——当时觉得疯狂的想法,现在可能已经是新世界的入口。"
Trae: "下次要不要试试用WebGL做3D时间轴?"
我: "先让我把这个淡蓝色宇宙修好再说吧..."
(完)
演示地址:穿越时空的按钮