一、项目构思
520 是一个非常有意义的日子,用一个特别的 web 项目来表达心意,非常有创意!可以构思一个既新颖、有彩蛋,又相对容易在短时间内实现并部署的 web 项目:《我们的回忆地图》。
这个项目的核心是一个交互式地图,地图上标记着情侣关系中重要的地点(第一次见面、第一次约会、一起旅行的地方等等)。点击每个标记,会弹出一个窗口,展示相关的照片、日期和一段简短的回忆文字。更重要的是,加入一些隐藏的“彩蛋”,让整个体验更加惊喜和有趣。
项目核心:
- 可视化回忆: 将抽象的回忆具象化到地图上,直观展示共同走过的旅程。
- 交互体验: 可以自由探索地图,点击标记,参与其中。
- 隐藏彩蛋: 在地图或页面中隐藏一些触发点,点击后出现惊喜内容(隐藏照片、特殊动画、专属情话等)。
- 个性化定制: 额~~~~,算了,万一给搅黄了可是罪过,哈哈哈哈 。
技术栈:
- 前端: HTML, CSS, JavaScript
- 地图库: Leaflet.js (轻量级、易于使用,适合静态部署)
- 数据存储: JSON 文件 (存储地点、回忆、照片等信息)
- 部署: EdgeOne Pages MCP (部署静态网站)
为什么选择这个方案?
- 比起简单的电子相册或情书,地图形式更具创意和故事感。
- 使用 Leaflet.js 和静态 JSON 数据,前端即可完成大部分功能,非常适合 EdgeOne Pages 的静态部署。
- 彩蛋易于集成: 可以在前端通过 JavaScript 控制彩蛋的触发和展示。
- CodeBuddy 可以很好地辅助生成 HTML 结构、CSS 样式、JavaScript 逻辑(包括 Leaflet 的使用和彩蛋的实现),以及 JSON 数据的格式。
二、准备工作
开发环境:推荐 VS Code + CodeBuddy 插件。
在 VSCode中安装 腾讯云代码助手CodeBuddy 插件。
腾讯云重磅上线了MCP广场:https://cloud.tencent.com/developer/mcp?channel=ugc,里面上线了EdgeOne Pages MCP服务器。
我们需要把这个 EdgeOne Pages MCP 服务器添加到 CodeBuddy 中,后面部署到网页需要。
首先,进入 CodeBuddy 对话窗口,找到 MCP 选项。
进入MCP配置界面,点击配置 MCP Server。
在 Craft_mcp_settings.json
中加入如下内容:
{
"mcpServers": {
"edgeone-pages-mcp-server": {
"command": "npx",
"args": ["edgeone-pages-mcp"]
}
}
}
保存后可以看到 MCP server 添加成功。
好了,到这里基本的开发环境就准备好了!很简单吧。
三、项目实现步骤
接下来一起构思一个能让 对象 眼前一亮的 520 Web 项目,充分利用 CodeBuddy 加速开发,并部署到 EdgeOne Pages 上。
向 CodeBuddy 提问:
一个交互式地图,地图上标记着情侣关系中重要的地点(第一次见面、第一次约会、一起旅行的地方等等)。点击每个标记,会弹出一个窗口,展示相关的照片、日期和一段简短的回忆文字。更重要的是,加入一些隐藏的“彩蛋”,让整个体验更加惊喜和有趣。
CodeBuddy立马开始生成代码,并利用 MCP 服务器部署到了 EdgeOne Pages 上。看一下效果:
部署地址:https://mcp.edgeone.site/share/DZOn0BC3fsmFiWParIhoK
地图渲染有点慢!
不过, 项目功能实现了:
-
交互式地图:使用Leaflet.js实现的交互式地图,可以自由缩放和平移。
-
记忆点标记:地图上标记了四个重要的地点(示例数据),包括:第一次见面(北京)、第一次约会(上海)、一起旅行(昆明)、纪念日(杭州)。
-
点击查看详情:点击每个标记,会弹出包含照片、日期和回忆描述的窗口。
-
隐藏彩蛋:项目中包含了三种不同类型的彩蛋:
- 地图点击彩蛋:在地图特定区域(北纬35-36度,东经115-116度之间)点击会触发隐藏消息。
- 时间彩蛋:访问页面30秒后会触发心形动画。
- Konami代码彩蛋:输入经典的Konami代码(↑↑↓↓←→←→BA)会显示秘密相册。
我们来一步步完善这个项目。在每个步骤中,都会使用 CodeBuddy 来帮助。
第一步:构建基础 HTML 结构 (index.html
)。
打开 index.html
,使用 CodeBuddy 生成基本的 HTML5 结构。CodeBuddy Prompt:
“请生成一个基本的 HTML5 页面结构,包含 title 为 ‘爱的密码锁’,链接到 style.css 和 script.js。”
<!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="style.css">
</head>
<body>
<!-- 密码锁容器 -->
<div class="container">
<div class="password-lock">
<h2>爱的密码锁</h2>
<input type="text" id="passwordInput" readonly placeholder="请输入密码">
<div class="keyboard">
<!-- 数字按钮将在这里生成 -->
</div>
<button id="unlockButton">解锁</button>
<div id="message" class="message"></div>
</div>
<!-- 惊喜内容区域 (初始隐藏) -->
<div id="surpriseContent" class="surprise-content" style="display: none;">
<!-- 惊喜内容将在这里动态加载 -->
</div>
</div>
<script src="script.js"></script>
</body>
</html>
继续 CodeBuddy Prompt:
“请帮我在
.keyboard
div 中生成 0-9 的数字按钮,每个按钮都有 class ‘number’。”
<div class="keyboard">
<button class="number">1</button>
<button class="number">2</button>
<button class="number">3</button>
<button class="number">4</button>
<button class="number">5</button>
<button class="number">6</button>
<button class="number">7</button>
<button class="number">8</button>
<button class="number">9</button>
<button class="number">0</button>
</div>
将这段代码插入到 index.html
中 .keyboard
div 的位置。
第二步:设计基础 CSS 样式 (style.css
)。
打开 style.css
,使用 CodeBuddy 设计密码锁的基本样式。
CodeBuddy Prompt:
“请帮我设计一个居中显示的密码锁容器样式,背景使用浪漫的渐变色,密码锁面板有圆角和阴影。”
body {
font-family: 'Arial', sans-serif;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(to bottom right, #ffafbd, #ffc3a0); /* 浪漫渐变背景 */
}
.container {
text-align: center;
}
.password-lock {
background-color: rgba(255, 255, 255, 0.9); /* 半透明白色背景 */
padding: 30px;
border-radius: 15px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
width: 300px;
max-width: 90%; /* 响应式调整 */
animation: fadeIn 1s ease-out; /* 添加淡入动画 */
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}
h2 {
color: #e57373; /* 柔和的红色 */
margin-bottom: 20px;
}
#passwordInput {
width: calc(100% - 22px); /* 减去 padding 和 border */
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ffcdd2; /* 柔和的边框颜色 */
border-radius: 5px;
font-size: 18px;
text-align: center;
outline: none; /* 移除点击时的外边框 */
}
.keyboard {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
margin-bottom: 15px;
}
.number, #unlockButton {
padding: 15px;
border: none;
border-radius: 8px;
font-size: 20px;
cursor: pointer;
background-color: #ffcdd2; /* 按钮背景色 */
color: #424242; /* 按钮文字颜色 */
transition: background-color 0.3s ease, transform 0.1s ease;
}
.number:hover, #unlockButton:hover {
background-color: #ef9a9a; /* 鼠标悬停效果 */
}
.number:active, #unlockButton:active {
transform: scale(0.95); /* 按钮按下效果 */
}
#unlockButton {
background-color: #e57373; /* 解锁按钮背景色 */
color: white;
grid-column: span 3; /* 解锁按钮占满三列 */
}
.message {
margin-top: 15px;
font-size: 16px;
min-height: 20px; /* 预留空间,避免内容出现时布局跳动 */
}
.message.error {
color: #ef5350; /* 错误提示颜色 */
animation: shake 0.5s; /* 添加抖动动画 */
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
20%, 40%, 60%, 80% { transform: translateX(5px); }
}
.surprise-content {
margin-top: 30px;
padding: 20px;
background-color: rgba(255, 255, 255, 0.95);
border-radius: 15px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
animation: slideInUp 1s ease-out; /* 添加滑入动画 */
}
@keyframes slideInUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
/* 响应式调整 */
@media (max-width: 400px) {
.password-lock {
padding: 20px;
}
.number, #unlockButton {
padding: 12px;
font-size: 18px;
}
}
第三步:实现核心 JavaScript 逻辑 (script.js
)。
打开 script.js
,使用 CodeBuddy 编写交互逻辑。
CodeBuddy Prompt:
“请帮我编写 JavaScript 代码,实现密码锁功能。获取 id 为 ‘passwordInput’, ‘unlockButton’, ‘message’, ‘surpriseContent’ 的元素。获取所有 class 为 ‘number’ 的按钮。设置一个变量存储输入的密码,一个常量存储正确的密码(例如 ‘5201314’)。监听数字按钮点击事件,将按钮文本添加到输入框和密码变量。监听解锁按钮点击事件,比较输入的密码和正确密码。如果正确,隐藏密码锁容器,显示惊喜内容区域,并在 message 元素显示 ‘解锁成功!’。如果错误,在 message 元素显示 ‘密码错误,请重试!’,清空输入框和密码变量,并给 passwordInput 添加一个 ‘shake’ 类(用于 CSS 动画),0.5秒后移除该类。”
const passwordInput = document.getElementById('passwordInput');
const unlockButton = document.getElementById('unlockButton');
const messageElement = document.getElementById('message');
const surpriseContent = document.getElementById('surpriseContent');
const passwordLock = document.querySelector('.password-lock'); // 获取密码锁容器
const numberButtons = document.querySelectorAll('.number');
let currentPassword = ''; // 存储输入的密码
const correctPassword = '5201314'; // 设置正确的密码,请替换成你的专属密码!
// 监听数字按钮点击事件
numberButtons.forEach(button => {
button.addEventListener('click', () => {
if (currentPassword.length < 10) { // 限制密码长度,避免过长
currentPassword += button.textContent;
passwordInput.value = currentPassword;
messageElement.textContent = ''; // 清空提示信息
messageElement.classList.remove('error'); // 移除错误样式
}
});
});
// 监听解锁按钮点击事件
unlockButton.addEventListener('click', () => {
if (currentPassword === correctPassword) {
messageElement.textContent = '解锁成功!';
messageElement.style.color = 'green';
passwordLock.style.display = 'none'; // 隐藏密码锁容器
surpriseContent.style.display = 'block'; // 显示惊喜内容区域
// 在这里调用加载惊喜内容的函数
loadSurpriseContent();
} else {
messageElement.textContent = '密码错误,请重试!';
messageElement.classList.add('error'); // 添加错误样式触发动画
currentPassword = ''; // 清空密码
passwordInput.value = '';
// 移除抖动动画类,以便下次错误时再次触发
passwordInput.classList.remove('shake');
// 强制重绘,确保动画能再次触发
void passwordInput.offsetWidth;
passwordInput.classList.add('shake');
// 0.5秒后移除错误样式和抖动类
setTimeout(() => {
messageElement.classList.remove('error');
passwordInput.classList.remove('shake');
}, 500);
}
});
// 添加一个函数来加载惊喜内容
function loadSurpriseContent() {
// 这个函数将在密码正确后被调用
// 在这里实现加载照片墙、情话等逻辑
console.log("密码正确,加载惊喜内容...");
// 示例:添加一个简单的文本提示
surpriseContent.innerHTML = '<h1>恭喜你,解锁成功!</h1><p>这是为你准备的特别惊喜!</p>';
// 调用加载照片墙的函数
loadPhotoWall();
// 调用加载情话卡片的函数
loadLoveMessages();
// ... 调用其他加载惊喜内容的函数
}
// Placeholder functions for surprise content
function loadPhotoWall() {
console.log("加载照片墙...");
// 在这里实现照片墙的加载逻辑
}
function loadLoveMessages() {
console.log("加载情话卡片...");
// 在这里实现情话卡片的加载逻辑
}
// 可以添加一个清除按钮或长按输入框清除功能(可选)
// CodeBuddy Prompt: "请帮我为 passwordInput 添加一个事件监听,当用户长按输入框(例如按住超过1秒)时,清空输入框和 currentPassword 变量。"
// (这个功能实现稍微复杂一些,涉及到 mousedown, mouseup, setTimeout, clearTimeout)
// 简单起见,我们暂时不添加清除功能,或者可以添加一个单独的清除按钮。
重要: 将 const correctPassword = '5201314';
中的 '5201314'
替换为你想要设置的专属密码。
第四步:填充惊喜内容 (data.json
和 script.js
)。
现在我们来填充惊喜内容,首先准备数据。
- 在
images
文件夹中放入一些照片(例如photo1.jpg
,photo2.jpg
)。 - 打开
data.json
,使用 CodeBuddy 生成 JSON 格式的数据结构。
CodeBuddy Prompt:
“请帮我生成一个 JSON 结构,包含一个图片列表 (photos),每个图片对象有 url 属性。再包含一个情话列表 (messages),每个情话是一个字符串。”
{
"photos": [
{ "url": "images/photo1.jpg" },
{ "url": "images/photo2.jpg" },
{ "url": "images/photo3.jpg" }
// ... 更多图片
],
"messages": [
"你是我生命中最美的意外。",
"有你的日子,每天都是晴天。",
"想把所有的温柔都给你。",
"遇到你,是我这辈子最幸运的事。"
// ... 更多情话
]
}
将自己的照片路径和情话填充到 data.json
中。
现在修改 script.js
中的 loadSurpriseContent
, loadPhotoWall
, loadLoveMessages
函数,使其从 data.json
读取数据并展示。
CodeBuddy Prompt:
“请帮我编写 JavaScript 代码,使用
fetch
API 读取data.json
文件,并在成功读取后调用loadPhotoWall
和loadLoveMessages
函数,将读取到的数据传递给它们。”
// 修改 loadSurpriseContent 函数
async function loadSurpriseContent() {
console.log("密码正确,加载惊喜内容...");
surpriseContent.innerHTML = ''; // 清空之前的占位内容
try {
const response = await fetch('data.json');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log("成功加载数据:", data);
// 加载照片墙
if (data.photos && data.photos.length > 0) {
// 添加一个标题
const photoTitle = document.createElement('h3');
photoTitle.textContent = "我们的甜蜜瞬间";
surpriseContent.appendChild(photoTitle);
loadPhotoWall(data.photos);
}
// 加载情话卡片
if (data.messages && data.messages.length > 0) {
// 添加一个标题
const messageTitle = document.createElement('h3');
messageTitle.textContent = "送给你的情话";
surpriseContent.appendChild(messageTitle);
loadLoveMessages(data.messages);
}
// 你可以在这里添加加载音乐等的逻辑
} catch (error) {
console.error("加载惊喜内容失败:", error);
surpriseContent.innerHTML = '<p>加载惊喜内容失败,请稍后再试。</p>';
}
}
// 修改 loadPhotoWall 函数,接收 photos 数组
function loadPhotoWall(photos) {
const photoWallDiv = document.createElement('div');
photoWallDiv.classList.add('photo-wall');
surpriseContent.appendChild(photoWallDiv); // 将照片墙容器添加到惊喜内容区域
photos.forEach(photo => {
const img = document.createElement('img');
img.src = photo.url;
img.alt = '我们的回忆照片';
img.classList.add('memory-photo'); // 添加一个 class 用于样式
photoWallDiv.appendChild(img);
});
// CodeBuddy Prompt: "请帮我为 class 为 'photo-wall' 的 div 和 class 为 'memory-photo' 的 img 添加 CSS 样式,让照片墙看起来整洁,图片有圆角和阴影,并且图片可以自适应容器大小。"
// (将 CodeBuddy 生成的 CSS 添加到 style.css 中)
/*
.photo-wall {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
}
.memory-photo {
width: 100px; // 默认宽度
height: 100px; // 默认高度
object-fit: cover; // 保持图片比例并填充容器
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease; // 添加悬停放大效果
}
.memory-photo:hover {
transform: scale(1.1);
}
@media (max-width: 600px) {
.memory-photo {
width: 80px;
height: 80px;
}
}
*/
}
// 修改 loadLoveMessages 函数,接收 messages 数组
function loadLoveMessages(messages) {
const messagesDiv = document.createElement('div');
messagesDiv.classList.add('love-messages');
surpriseContent.appendChild(messagesDiv); // 将情话容器添加到惊喜内容区域
messages.forEach(message => {
const p = document.createElement('p');
p.textContent = message;
p.classList.add('love-message'); // 添加一个 class 用于样式
messagesDiv.appendChild(p);
});
// CodeBuddy Prompt: "请帮我为 class 为 'love-messages' 的 div 和 class 为 'love-message' 的 p 添加 CSS 样式,让情话看起来温馨,可以有不同的字体或颜色。"
// (将 CodeBuddy 生成的 CSS 添加到 style.css 中)
/*
.love-messages {
margin-top: 20px;
border-top: 1px solid #eee;
padding-top: 15px;
}
.love-message {
font-size: 1.1em;
color: #d32f2f; // 温馨的红色
margin-bottom: 10px;
font-style: italic;
}
*/
}
// ... 其他 JavaScript 代码保持不变
将上面的 JavaScript 代码复制到 script.js
中,替换掉之前 loadSurpriseContent
等函数的占位符。同时,将 CodeBuddy 生成的 CSS 样式添加到 style.css
中。
第五步:添加隐藏彩蛋
添加一个简单的彩蛋:当用户连续点击密码锁面板的某个区域(例如右上角)三次时,弹出一个隐藏的甜蜜信息。
CodeBuddy Prompt:
“请帮我编写 JavaScript 代码,监听 class 为 ‘password-lock’ 的元素的点击事件。计算点击位置。如果点击位置在元素的右上角区域(例如距离右边小于50px,距离顶部小于50px),并且连续点击次数达到3次,则弹出一个 alert 框显示 ‘找到隐藏的彩蛋啦!你真是太棒了!’。在每次点击后,如果不是在彩蛋区域,则重置点击计数器。”
// 在 script.js 中添加以下代码
const passwordLockElement = document.querySelector('.password-lock');
let easterEggClickCount = 0;
let easterEggTimer = null; // 用于重置计数器的定时器
passwordLockElement.addEventListener('click', (event) => {
// 获取点击相对于 passwordLockElement 的位置
const rect = passwordLockElement.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
// 定义彩蛋区域 (右上角 50x50 像素)
const easterEggAreaSize = 50;
const isEasterEggArea = x > rect.width - easterEggAreaSize && y < easterEggAreaSize;
if (isEasterEggArea) {
easterEggClickCount++;
console.log("彩蛋区域点击次数:", easterEggClickCount);
// 如果之前有定时器,先清除
if (easterEggTimer) {
clearTimeout(easterEggTimer);
}
// 设置一个定时器,如果在一定时间内没有再次点击彩蛋区域,则重置计数器
easterEggTimer = setTimeout(() => {
easterEggClickCount = 0;
console.log("彩蛋点击计数器已重置");
}, 1000); // 1秒内没有再次点击则重置
if (easterEggClickCount === 3) {
alert('找到隐藏的彩蛋啦!你真是太棒了!');
easterEggClickCount = 0; // 触发后重置计数器
clearTimeout(easterEggTimer); // 触发后清除定时器
}
} else {
// 如果点击不在彩蛋区域,重置计数器
easterEggClickCount = 0;
if (easterEggTimer) {
clearTimeout(easterEggTimer);
easterEggTimer = null;
}
}
});
将这段代码添加到 script.js
的末尾。可以根据需要调整彩蛋区域的大小和连续点击次数。
第六步:准备部署文件
项目文件夹结构如下:
love-password-lock/
├── index.html
├── style.css
├── script.js
├── data.json
├── images/
│ ├── photo1.jpg
│ ├── photo2.jpg
│ └── photo3.jpg
└── audio/ (可选)
└── your_song.mp3
确保 index.html
中引用的 CSS, JavaScript, 图片, JSON 文件的路径都是正确的相对路径。
四、部署和展示
在部署之前,要先在腾讯EdgeOne控制台创建一个API Key,否则会部署不上:
部署到 EdgeOne Pages,向 CodeBuddy 提问:
帮我把这个项目通过mcp服务器部署
将使用EdgeOne Pages MCP服务器提供的deploy_html工具来部署这个项目文件。并返回了一个公共访问URL:https://mcp.edgeone.site/share/v4x0AH_6xKrC0BSclf_Qk。
这个URL可以用来访问部署的网站。
网站使用说明:
- 密码解锁:网站初始界面是一个密码锁,密码是:5201314(爱你一生一世),输入正确密码后点击"解锁"按钮即可进入内容页面。
- 内容页面:照片墙展示了6张浪漫图片以及展示了15条爱的留言。
- 彩蛋功能:在右上角区域连续点击3次会触发心形动画。
效果如下:
项目已提交到GitHub:https://github.com/LongTengFly/HTML-CSS-JS/。
五、总结
至此,使用 CodeBuddy 辅助,一步步完成了“爱的密码锁” Web 项目的开发和部署。从基础的 HTML 结构、CSS 样式,到复杂的 JavaScript 交互和彩蛋逻辑,CodeBuddy 都提供了极大的帮助。通过 EdgeOne Pages,成功地将这个充满心意的项目部署到了互联网上,随时可以分享给你的女朋友,给她一个大大的惊喜!
这个项目只是一个基础框架,还可以继续发挥创意,添加更多个性化的内容和更酷炫的彩蛋,让它变得更加独一无二!
提前祝大家 520 快乐!