在没有大模型和AI编辑器的时候,想要通过编程实现自己的页面并不是一件容易的事情。首先,你得找到一个与你想法类似的项目作为参考,然后再通过对HTML、CSS以及JS的深入学习,才能照猫画虎一般完成一个简单demo,又或是需要了解Vue和React等前端框架的使用,熟悉整个的开发流程。但通过AI编辑器Trae,你能够省去前端知识的学习成本,只需要将自己的一些奇思妙想交给编辑器,它便能结合大模型帮助你生成一个还不错的小项目。
那么灵感怎么来呢?
-
你可以结合自己生活和工作中的一些需求,将它们的核心部分提炼出来,然后你再想想能不能以工具的方式去解决这些问题。比如:当你工作中在处理文件时,需要用到markdown转pdf的功能,可是你嫌麻烦又不想去下载其他软件,这时候你就可以借助
Trae这款编辑器帮你实现一款markdown转pdf格式的页面小项目,同时你还可以根据自己的一些小需求对它进行微调,只需要不断地和Trae对话就可以啦。 -
如果你没有遇到上述的情况,那么寻找灵感的过程也可以交给
Trae来解决。比如你想开发一款休闲小游戏,但不知道应该以什么为主题好。那么你直接将该问题交给AI编辑器,它会给你提供一些有趣的想法。 -
我便是属于第二种情况,于是我我打开了
Trae,把我的问题告诉它:请帮我想一些页面小项目的名称和功能,要求只能用HTML、CSS以及JS来实现。
Trae交给豆包大模型理解后,给出了我很详细的答复:- 可以通过html、css、js设计一款像素绘画板,核心功能:网格画布(CSS Grid实现),点击填色,支持调色 盘;特色功能:添加本地保存功能(localStorage存图片数据)、一键导出PNG;技术点:canvas.toDataURL() 导出图片等。
- 可以通过html,css,js设计一个记忆卡片配对游戏,核心功能:翻牌匹配相同图案,计时计步,胜利提示;技术亮点:JS随机生成卡片布局( Fisher-Yates 洗牌算法)、CSS 3D翻转动画增强交互感。
- . . . . . .
我挑选了第一个作为我的想法,并再次发送给
Trae的AI对话框:
于是它很快就把代码实现了。
如何对项目进行微调?
我们第一次发给Trae的生成提示词可能比较粗糙,会忽略很多细节的功能和设计。所以我们可以先将每次的代码运行在浏览器中,通过查看它具体的运行效果,以及使用下来发现的一些问题,对我们第一次发送的提示词内容进行补充和优化。经过反复和Trae对话,我们便能够将这个小项目打磨地越来越好。
-
运行初始的代码,可以得到以下运行结果:
-
通过与
Trae对话进行优化:请将页面的滚动条去掉,并给画布添加类似于写字画板的棕色边框。
-
重新运行页面后:
-
继续将优化的提示词发送给
Trae:请将网格区域的高度整体适当减小,宽度整体适当增加,并放置于页面居中的位置;同时将按钮分别进行美化,颜 色为绿色,边框为圆角,大小适中,增加一些CSS特效,放置于调整后的页面的左侧上方的位置;添加用户通过拖动 鼠标可以在网格区域上色。
-
运行代码并测试画板的功能,画了一只可爱的果冻喵:
使用感想
从这个小项目的灵感来源,到包含的功能以及代码的实现,全部都来自于Trae这款编辑器。整个过程中,我所做的只是不断地和Trae对话,根据编辑器的反馈结果给出相应的建议,也算是实现了“零代码”开发页面。
《像素绘画板》 虽然功能非常简单,但它让我第一次体验了使用AI编辑器开发的全过程,只靠人类的自然语言也可以打造出一款自己的小项目。这也意味着,如果你并不从事写代码的相关行业,也可以靠“开口”开发自己的作品。
作品链接: 像素绘画板 - AI Coding
后续优化版本:像素绘画板 v2.0 - AI Coding
源码分享
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="pixel_painter.css">
</head>
<body>
<div id="canvas-container"></div>
<div id="color-picker">
<button onclick="saveDrawing()">保存</button>
<button onclick="resetCanvas()">重置</button>
<input type="color" id="custom-color">
</div>
<script src="pixel_painter.js"></script>
</body>
</html>
CSS
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
padding: 20px;
}
#canvas-container {
display: grid;
grid-template-columns: repeat(80, 10px);
grid-template-rows: repeat(50, 10px);
gap: 1px;
background-color: #ccc;
border: 10px solid #8B4513;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
margin-left: 80px;
}
.pixel {
background-color: white;
width: 10px;
height: 10px;
}
#color-picker {
display: flex;
flex-direction: column;
gap: 10px;
position: fixed;
top: calc(20px + 1 * (10px + 30px + 10px)); /* 恢复原间距 */
left: 20px;
width: 100px;
z-index: 1;
}
.color-option {
width: 30px;
height: 30px;
border: 2px solid transparent;
}
.color-option.selected {
border-color: black;
}
button {
width: 120px;
margin: 0px;
padding: 10px 20px;
border: none;
border-radius: 5px;
background-color: #4CAF50;
color: white;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
transition-duration: 0.4s;
cursor: pointer;
}
button:hover {
background-color: white;
color: black;
border: 2px solid #4CAF50;
}
button:active {
transform: translateY(4px);
box-shadow: 0 2px #666;
}
#export-buttons {
display: flex;
flex-direction: column;
align-items: center;
position: fixed;
top: 10px;
left: 20px;
}
JS
const canvas = document.getElementById('canvas-container');
const customColor = document.getElementById('custom-color');
let selectedColor = '#000000';
let pixels = [];
let isDrawing = false;
// 初始化画布
function initCanvas() {
for (let i = 0; i < 80 * 50; i++) {
const pixel = document.createElement('div');
pixel.classList.add('pixel');
pixel.addEventListener('click', () => colorPixel(pixel));
pixel.addEventListener('mousemove', () => colorPixel(pixel));
canvas.appendChild(pixel);
pixels.push(pixel);
}
loadDrawing();
}
// 选择颜色
customColor.addEventListener('change', () => {
selectedColor = customColor.value;
});
// 填充像素
function colorPixel(pixel) {
if (isDrawing) {
pixel.style.backgroundColor = selectedColor;
}
}
// 保存绘画(现在功能为导出 PNG)
function saveDrawing() {
exportPNG();
}
// 重置画布
function resetCanvas() {
pixels.forEach(pixel => {
pixel.style.backgroundColor = 'white';
});
}
// 加载绘画
function loadDrawing() {
const savedColors = JSON.parse(localStorage.getItem('pixelDrawing'));
if (savedColors) {
savedColors.forEach((color, index) => {
pixels[index].style.backgroundColor = color;
});
}
}
// 导出PNG
function exportPNG() {
const tempCanvas = document.createElement('canvas');
const ctx = tempCanvas.getContext('2d');
tempCanvas.width = 80 * 10;
tempCanvas.height = 50 * 10;
pixels.forEach((pixel, index) => {
const x = (index % 80) * 10;
const y = Math.floor(index / 80) * 10;
ctx.fillStyle = pixel.style.backgroundColor;
ctx.fillRect(x, y, 20, 20);
});
const link = document.createElement('a');
link.download = 'pixel-art.png';
link.href = tempCanvas.toDataURL();
link.click();
}
// 添加鼠标事件监听器
canvas.addEventListener('mousedown', () => isDrawing = true);
canvas.addEventListener('mouseup', () => isDrawing = false);
canvas.addEventListener('mouseleave', () => isDrawing = false);
initCanvas();
v2.0源码分享
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">
</head>
<body>
<div class="controls">
<input type="color" id="colorPicker">
<input type="text" id="textInput" placeholder="输入要转换的文字">
<button id="textToPixelButton">文字转像素画</button>
<button id="saveButton">保存</button>
<button id="exportButton">导出PNG</button>
<button id="clearButton">清空画布</button>
<button id="eraserButton">橡皮擦</button>
<button id="importButton">导入图片</button>
<button id="ai-chat-button">AI聊天</button>
<button id="clear-chat-history">清除对话</button>
</div>
<h1 class="pixel-text">像素绘画板</h1>
<div id="canvas"></div>
<script src="script.js"></script>
<div id="ai-chat-popup" style="display: none;">
<div id="ai-chat-messages"></div>
<input type="text" id="ai-chat-input" placeholder="请输入您的绘画想法...">
<button id="ai-chat-send">发送</button>
</div>
</body>
</html>
CSS
body {
background: linear-gradient(45deg, #ff9a9e 0%, #fad0c4 99%, #fad0c4 100%);
background-attachment: fixed;
font-family: 'Press Start 2P', cursive;
display: flex;
flex-direction: column;
align-items: center;
overflow: hidden; /* 去掉滚动条 */
}
.pixel-text {
font-family: 'Press Start 2P', cursive;
font-size: 32px;
color: #333;
text-shadow: 2px 2px 0px #fff, 4px 4px 0px #000;
margin-bottom: 20px;
letter-spacing: 2px;
}
#ai-loading-bar {
border: 2px solid #667eea;
background-color: rgba(255, 255, 255, 0.5);
border-radius: 10px;
overflow: hidden;
}
#ai-loading-progress {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
height: 100%;
border-radius: 8px;
transition: width 0.5s ease;
}
@font-face {
font-family: 'Press Start 2P';
src: url('https://fonts.gstatic.com/s/pressstart2p/v14/e3t4euO8T-267oIAQAu6jDQyK3nYivN04w.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
.controls input[type="color"] {
width: 100%;
height: 48px;
border: none;
border-radius: 25px;
padding: 4px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
cursor: pointer;
transition: all 0.3s ease;
}
.controls input[type="color"]:hover {
transform: translateY(-2px);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.2);
}
.controls input[type="color"]::-webkit-color-swatch-wrapper {
padding: 0;
}
.controls input[type="color"]::-webkit-color-swatch {
border: none;
border-radius: 21px;
}
.controls {
position: absolute;
left: 20px;
top: 20px;
display: flex;
flex-direction: column;
gap: 10px;
}
.controls button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 25px;
color: white;
padding: 12px 24px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
font-family: 'Press Start 2P', cursive;
font-weight: bold;
letter-spacing: 1px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
cursor: pointer;
}
.controls button:hover {
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
transform: translateY(-2px);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.2);
}
#canvas {
display: grid;
grid-gap: 1px;
background-color: #ccc;
border: 15px double #4a321a; /* 加宽边框并使用双线条样式,更改颜色为更深的棕色 */
box-shadow: 0 0 30px rgba(74, 50, 26, 0.7), 0 0 10px rgba(74, 50, 26, 0.5) inset; /* 增强外部阴影并添加内部阴影 */
margin: auto; /* 居中显示 */
height: auto;
width: auto;
}
.pixel {
background-color: #fff;
}
#ai-qa-container {
position: absolute;
right: 30px;
top: 30px;
display: flex;
flex-direction: column;
gap: 10px;
background: rgba(255, 255, 255, 0.3);
padding: 15px;
border-radius: 16px;
backdrop-filter: blur(5px);
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.1);
}
#ai-qa-container input[type="text"] {
width: 180px;
height: 35px;
border: 2px solid #667eea;
border-radius: 28px;
padding: 4px 12px;
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
font-size: 16px;
font-family: 'Press Start 2P', cursive;
color: #333;
transition: all 0.3s ease;
}
#ai-qa-container input[type="text"]:focus {
outline: none;
border-color: #764ba2;
box-shadow: 0 8px 10px rgba(0, 0, 0, 0.2);
}
#ai-qa-container button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: 2px solid transparent;
border-radius: 28px;
color: white;
padding: 8px 14px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
font-family: 'Press Start 2P', cursive;
font-weight: bold;
letter-spacing: 1px;
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
transition: all 0.3s ease;
cursor: pointer;
}
#ai-qa-container button:hover {
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
transform: translateY(-3px);
box-shadow: 0 8px 10px rgba(0, 0, 0, 0.2);
border-color: white;
}
#ai-qa-container button:hover {
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
transform: translateY(-2px);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.2);
}
#ai-chat-popup {
/* 美化聊天框背景 */
background: linear-gradient(135deg, #e6f7ff 0%, #f0f8ff 100%);
border: 2px solid #b3d9ff;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border-radius: 16px;
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.1);
width: 400px;
height: 500px;
display: none;
flex-direction: column;
}
#ai-chat-messages {
height: 430px;
overflow-y: auto;
/* 参照 QQ 美化对话内容框 */
background: #f0f3f5;
border: 1px solid #d3d7dc;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
/* 消息气泡样式 */
display: flex;
flex-direction: column;
gap: 10px;
flex-grow: 1;
overflow-y: auto;
padding: 10px;
margin-bottom: 10px;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.9) 0%, rgba(240, 240, 240, 0.9) 100%);
border-radius: 14px;
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
font-family: 'Press Start 2P', cursive;
font-size: 12px;
line-height: 1.6;
color: #333;
}
#ai-chat-messages div {
max-width: 70%;
padding: 8px 12px;
border-radius: 16px;
margin-bottom: 5px;
}
#ai-chat-messages div:nth-child(odd) {
background: #9eea6a;
align-self: flex-end;
}
#ai-chat-messages div:nth-child(even) {
background: #fff;
align-self: flex-start;
}
#ai-chat-input {
width: calc(100% - 120px);
height: 35px;
border: 2px solid #667eea;
border-radius: 28px;
padding: 4px 12px;
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
font-size: 16px;
font-family: 'Press Start 2P', cursive;
color: #333;
transition: all 0.3s ease;
}
#ai-chat-input:focus {
outline: none;
border-color: #764ba2;
box-shadow: 0 8px 10px rgba(0, 0, 0, 0.2);
}
#ai-chat-send {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: 2px solid transparent;
border-radius: 28px;
color: white;
padding: 8px 14px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
font-family: 'Press Start 2P', cursive;
font-weight: bold;
letter-spacing: 1px;
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
transition: all 0.3s ease;
cursor: pointer;
margin-left: 10px;
}
#ai-chat-send:hover {
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
transform: translateY(-3px);
box-shadow: 0 8px 10px rgba(0, 0, 0, 0.2);
border-color: white;
}
#ai-response-output {
max-width: 180px;
max-height: 200px;
overflow-y: auto;
padding: 10px;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.9) 0%, rgba(240, 240, 240, 0.9) 100%);
border-radius: 14px;
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
font-family: 'Press Start 2P', cursive;
font-size: 12px;
line-height: 1.6;
color: #333;
}
#ai-response-output::-webkit-scrollbar {
width: 6px;
}
#ai-response-output::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.5);
border-radius: 3px;
}
#ai-response-output::-webkit-scrollbar-thumb {
background: #667eea;
border-radius: 3px;
}
#ai-response-output::-webkit-scrollbar-thumb:hover {
background: #764ba2;
}
JS
document.addEventListener('DOMContentLoaded', () => {
const clearChatHistoryButton = document.getElementById('clear-chat-history');
clearChatHistoryButton.addEventListener('click', () => {
localStorage.removeItem('aiChatHistory');
aiChatMessages.innerHTML = '';
});
const aiChatButton = document.getElementById('ai-chat-button');
const aiChatPopup = document.getElementById('ai-chat-popup');
const aiChatInput = document.getElementById('ai-chat-input');
const aiChatSend = document.getElementById('ai-chat-send');
const aiChatMessages = document.getElementById('ai-chat-messages');
aiChatButton.addEventListener('click', () => {
// 加载历史记录
const chatHistory = JSON.parse(localStorage.getItem('aiChatHistory')) || [];
aiChatMessages.innerHTML = '';
chatHistory.forEach((message) => {
const msgElement = document.createElement('div');
msgElement.textContent = `${message.role === 'user' ? '您' : 'AI'}: ${message.content}`;
aiChatMessages.appendChild(msgElement);
});
if (aiChatPopup.style.display === 'block') {
aiChatPopup.style.display = 'none';
} else {
aiChatPopup.style.display = 'block';
}
});
aiChatSend.addEventListener('click', async () => {
const question = aiChatInput.value;
if (question.trim() === '') return;
// 添加用户消息到本地缓存
const chatHistory = JSON.parse(localStorage.getItem('aiChatHistory')) || [];
chatHistory.push({ role: 'user', content: question });
localStorage.setItem('aiChatHistory', JSON.stringify(chatHistory));
const userMessage = document.createElement('div');
userMessage.textContent = `您: ${question}`;
aiChatMessages.appendChild(userMessage);
// 清空画布输入框
aiChatInput.value = '';
try {
const response = await fetch('https://api.deepseek.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer sk-c81f865b4a684e6cad698bfec13bc4df'
},
body: JSON.stringify({
"model": "deepseek-chat",
"messages": [
{"role": "system", "content": "你是一个画家,请根据我的问题,给出一些绘制建议,需要分点回答"},
{"role": "user", "content": question}
]
})
});
const data = await response.json();
const answer = data.choices[0].message.content;
// 添加 AI 回复到本地缓存
chatHistory.push({ role: 'ai', content: answer });
localStorage.setItem('aiChatHistory', JSON.stringify(chatHistory));
const aiMessage = document.createElement('div');
aiMessage.textContent = `AI: ${answer}`;
aiChatMessages.appendChild(aiMessage);
} catch (error) {
console.error('请求 DeepSeek API 时出错:', error);
}
});
const textInput = document.getElementById('textInput');
const textToPixelButton = document.getElementById('textToPixelButton');
textToPixelButton.addEventListener('click', () => {
const text = textInput.value;
if (!text) return;
const tempCanvas = document.createElement('canvas');
const ctx = tempCanvas.getContext('2d');
const gridSize = 60;
tempCanvas.width = gridSize;
tempCanvas.height = gridSize;
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, gridSize, gridSize);
ctx.font = '20px Arial';
ctx.fillStyle = '#000';
ctx.textAlign = 'center';
ctx.fillText(text, gridSize / 2, gridSize / 2);
const imageData = ctx.getImageData(0, 0, gridSize, gridSize);
const data = imageData.data;
const pixels = document.querySelectorAll('.pixel');
const color = colorPicker.value;
let index = 0;
for (let i = 0; i < gridSize; i++) {
for (let j = 0; j < gridSize; j++) {
const r = data[index];
const g = data[index + 1];
const b = data[index + 2];
const a = data[index + 3];
if (a > 0 && r < 128 && g < 128 && b < 128) {
pixels[i * gridSize + j].style.backgroundColor = color;
} else {
pixels[i * gridSize + j].style.backgroundColor = '#fff';
}
index += 4;
}
}
});
const canvas = document.getElementById('canvas');
const colorPicker = document.getElementById('colorPicker');
const saveButton = document.getElementById('saveButton');
const exportButton = document.getElementById('exportButton');
const clearButton = document.getElementById('clearButton');
const eraserButton = document.getElementById('eraserButton');
const importButton = document.getElementById('importButton');
let isErasing = false;
const gridSize = 60; // 增加网格尺寸
const pixelSize = 10;
// 创建网格
for (let i = 0; i < gridSize; i++) {
for (let j = 0; j < gridSize; j++) {
const pixel = document.createElement('div');
pixel.classList.add('pixel');
pixel.style.width = `${pixelSize}px`;
pixel.style.height = `${pixelSize}px`;
let isDrawing = false;
canvas.addEventListener('mousedown', () => {
isDrawing = true;
});
canvas.addEventListener('mouseup', () => {
isDrawing = false;
});
canvas.addEventListener('mouseleave', () => {
isDrawing = false;
});
pixel.addEventListener('mousedown', () => {
if (isErasing) {
pixel.style.backgroundColor = '#fff';
} else {
pixel.style.backgroundColor = colorPicker.value;
}
});
pixel.addEventListener('mouseenter', () => {
if (isDrawing) {
if (isErasing) {
pixel.style.backgroundColor = '#fff';
} else {
pixel.style.backgroundColor = colorPicker.value;
}
}
});
canvas.appendChild(pixel);
}
}
canvas.style.gridTemplateColumns = `repeat(${gridSize}, ${pixelSize}px)`;
importButton.addEventListener('click', () => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*';
input.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (event) => {
const img = new Image();
img.onload = () => {
const tempCanvas = document.createElement('canvas');
tempCanvas.width = gridSize;
tempCanvas.height = gridSize;
const ctx = tempCanvas.getContext('2d');
// 计算图片的裁剪区域
let sourceX = 0;
let sourceY = 0;
let sourceWidth = img.width;
let sourceHeight = img.height;
if (img.width > img.height) {
sourceX = (img.width - img.height) / 2;
sourceWidth = img.height;
} else {
sourceY = (img.height - img.width) / 2;
sourceHeight = img.width;
}
// 裁剪并绘制图片到临时画布
ctx.drawImage(img, sourceX, sourceY, sourceWidth, sourceHeight, 0, 0, gridSize, gridSize);
const imageData = ctx.getImageData(0, 0, gridSize, gridSize);
const data = imageData.data;
const pixels = document.querySelectorAll('.pixel');
let index = 0;
for (let i = 0; i < gridSize; i++) {
for (let j = 0; j < gridSize; j++) {
const r = data[index];
const g = data[index + 1];
const b = data[index + 2];
const a = data[index + 3];
if (a === 0) {
pixels[i * gridSize + j].style.backgroundColor = '#fff';
} else {
pixels[i * gridSize + j].style.backgroundColor = `rgb(${r}, ${g}, ${b})`;
}
index += 4;
}
}
};
img.src = event.target.result;
};
reader.readAsDataURL(file);
}
});
input.click();
});
eraserButton.addEventListener('click', () => {
isErasing = !isErasing;
eraserButton.textContent = isErasing ? '结束擦除' : '橡皮擦';
});
// 保存功能
saveButton.addEventListener('click', () => {
const pixels = document.querySelectorAll('.pixel');
const data = [];
pixels.forEach(pixel => {
data.push(pixel.style.backgroundColor);
});
localStorage.setItem('pixelArt', JSON.stringify(data));
});
// 加载保存的数据
const savedData = JSON.parse(localStorage.getItem('pixelArt'));
if (savedData) {
const pixels = document.querySelectorAll('.pixel');
pixels.forEach((pixel, index) => {
pixel.style.backgroundColor = savedData[index];
});
}
// 清空画布功能
clearButton.addEventListener('click', () => {
const pixels = document.querySelectorAll('.pixel');
pixels.forEach(pixel => {
pixel.style.backgroundColor = '#fff';
});
localStorage.removeItem('pixelArt');
});
// 导出PNG
exportButton.addEventListener('click', () => {
const tempCanvas = document.createElement('canvas');
tempCanvas.width = gridSize * pixelSize;
tempCanvas.height = gridSize * pixelSize;
const ctx = tempCanvas.getContext('2d');
// 在绘制前填充白色背景
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, tempCanvas.width, tempCanvas.height);
const pixels = document.querySelectorAll('.pixel');
let index = 0;
for (let i = 0; i < gridSize; i++) {
for (let j = 0; j < gridSize; j++) {
const pixel = pixels[index];
const color = window.getComputedStyle(pixel).backgroundColor;
ctx.fillStyle = color;
ctx.fillRect(j * pixelSize, i * pixelSize, pixelSize, pixelSize);
index++;
}
}
const link = document.createElement('a');
link.download = 'pixel-art.png';
link.href = tempCanvas.toDataURL();
link.click();
});
});
const aiQuestionInput = document.getElementById('ai-question-input');
const aiSubmitButton = document.getElementById('ai-submit-button');
const aiResponseOutput = document.getElementById('ai-response-output');
aiSubmitButton.addEventListener('click', async () => {
const loadingBar = document.getElementById('ai-loading-bar');
const loadingProgress = document.getElementById('ai-loading-progress');
loadingBar.style.display = 'block';
const interval = setInterval(() => {
if (loadingProgress.style.width === '100%') {
loadingProgress.style.width = '0%';
} else {
loadingProgress.style.width = (parseInt(loadingProgress.style.width) + 10) + '%';
}
}, 500);
const question = aiQuestionInput.value;
if (question.trim() === '') {
return;
}
try {
const response = await fetch('https://api.deepseek.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer 你的deepseek-api-key'
},
body: JSON.stringify({
"model": "deepseek-chat",
"messages": [
{"role": "system", "content": "你是一个画家,请根据我的问题,给出一些绘制建议,需要分点回答"},
{"role": "user", "content": question}
],
"stream": false
})
});
const data = await response.json();
const answer = data.choices[0].message.content;
aiResponseOutput.textContent = answer;
clearInterval(interval);
loadingBar.style.display = 'none';
loadingProgress.style.width = '0%';
clearInterval(interval);
loadingBar.style.display = 'none';
loadingProgress.style.width = '0%';
} catch (error) {
console.error('请求 DeepSeek API 时出错:', error);
aiResponseOutput.textContent = '请求出错,请稍后重试。';
}
});