Appearance
基础小项目(巩固知识点)
20.1 猜数字游戏
项目介绍
猜数字游戏是一个经典的小游戏,玩家需要在有限的次数内猜出计算机随机生成的数字。
实现思路
- 生成一个 1-100 之间的随机数字
- 让玩家输入猜测的数字
- 比较玩家输入的数字和随机数字
- 根据比较结果给出提示(太大、太小或正确)
- 限制猜测次数,超过次数则游戏结束
完整代码
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>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
padding: 20px;
}
.container {
max-width: 600px;
margin: 0 auto;
background-color: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
h1 {
text-align: center;
margin-bottom: 20px;
color: #333;
}
.instructions {
text-align: center;
margin-bottom: 30px;
font-size: 18px;
}
.game-container {
display: flex;
flex-direction: column;
gap: 20px;
}
.input-group {
display: flex;
gap: 10px;
}
input {
flex: 1;
padding: 10px;
font-size: 16px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
.message {
padding: 15px;
border-radius: 4px;
text-align: center;
font-size: 18px;
font-weight: bold;
}
.message.success {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.message.error {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.message.info {
background-color: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
.history {
margin-top: 20px;
}
.history h3 {
margin-bottom: 10px;
}
.history-list {
list-style: none;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
max-height: 200px;
overflow-y: auto;
}
.history-list li {
padding: 5px 0;
border-bottom: 1px solid #eee;
}
.history-list li:last-child {
border-bottom: none;
}
</style>
</head>
<body>
<div class="container">
<h1>猜数字游戏</h1>
<div class="instructions">
我已经想好了一个 1-100 之间的数字,你有 10 次机会来猜它!
</div>
<div class="game-container">
<div class="input-group">
<input type="number" id="guessInput" placeholder="请输入你猜测的数字" min="1" max="100">
<button id="guessBtn">猜</button>
</div>
<div class="message" id="message"></div>
<div class="history">
<h3>猜测历史</h3>
<ul class="history-list" id="historyList"></ul>
</div>
<button id="resetBtn">重新开始</button>
</div>
</div>
<script>
// 生成随机数字
let randomNumber = Math.floor(Math.random() * 100) + 1;
let attempts = 0;
const maxAttempts = 10;
const historyList = [];
// 获取 DOM 元素
const guessInput = document.getElementById("guessInput");
const guessBtn = document.getElementById("guessBtn");
const message = document.getElementById("message");
const historyListEl = document.getElementById("historyList");
const resetBtn = document.getElementById("resetBtn");
// 猜数字函数
function guessNumber() {
const guess = parseInt(guessInput.value);
// 验证输入
if (isNaN(guess) || guess < 1 || guess > 100) {
showMessage("请输入 1-100 之间的数字", "info");
return;
}
attempts++;
historyList.push(guess);
updateHistory();
// 比较猜测的数字和随机数字
if (guess === randomNumber) {
showMessage(`恭喜你!猜对了!你用了 ${attempts} 次机会。`, "success");
guessBtn.disabled = true;
guessInput.disabled = true;
} else if (attempts >= maxAttempts) {
showMessage(`游戏结束!正确数字是 ${randomNumber}。`, "error");
guessBtn.disabled = true;
guessInput.disabled = true;
} else if (guess > randomNumber) {
showMessage(`太大了!你还有 ${maxAttempts - attempts} 次机会。`, "info");
} else {
showMessage(`太小了!你还有 ${maxAttempts - attempts} 次机会。`, "info");
}
// 清空输入框
guessInput.value = "";
guessInput.focus();
}
// 显示消息
function showMessage(text, type) {
message.textContent = text;
message.className = `message ${type}`;
}
// 更新历史记录
function updateHistory() {
historyListEl.innerHTML = "";
historyList.forEach((item, index) => {
const li = document.createElement("li");
li.textContent = `第 ${index + 1} 次:${item}`;
historyListEl.appendChild(li);
});
}
// 重置游戏
function resetGame() {
randomNumber = Math.floor(Math.random() * 100) + 1;
attempts = 0;
historyList.length = 0;
updateHistory();
showMessage("游戏已重置,开始新的一轮吧!", "info");
guessBtn.disabled = false;
guessInput.disabled = false;
guessInput.focus();
}
// 事件监听
guessBtn.addEventListener("click", guessNumber);
resetBtn.addEventListener("click", resetGame);
// 按回车键也可以猜数字
guessInput.addEventListener("keypress", function(event) {
if (event.key === "Enter") {
guessNumber();
}
});
// 初始状态
showMessage("准备好了吗?开始猜数字吧!", "info");
guessInput.focus();
</script>
</body>
</html>20.2 简易计算器
项目介绍
简易计算器可以进行基本的加减乘除运算,帮助用户快速计算数学表达式。
实现思路
- 设计计算器的 UI 界面
- 实现数字和运算符的输入
- 处理计算逻辑
- 实现清除和删除功能
完整代码
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>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.calculator {
background-color: #333;
border-radius: 10px;
padding: 20px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
width: 300px;
}
.display {
background-color: #222;
color: white;
font-size: 24px;
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
text-align: right;
min-height: 60px;
word-wrap: break-word;
}
.buttons {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
}
button {
padding: 20px;
font-size: 18px;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.2s;
}
button:hover {
opacity: 0.8;
}
.number {
background-color: #555;
color: white;
}
.operator {
background-color: #ff9500;
color: white;
}
.clear {
background-color: #ff3b30;
color: white;
}
.equals {
background-color: #34c759;
color: white;
grid-column: span 2;
}
.decimal {
background-color: #555;
color: white;
}
.backspace {
background-color: #555;
color: white;
}
</style>
</head>
<body>
<div class="calculator">
<div class="display" id="display">0</div>
<div class="buttons">
<button class="clear" id="clear">C</button>
<button class="backspace" id="backspace">←</button>
<button class="operator" data-value="/">÷</button>
<button class="operator" data-value="*">×</button>
<button class="number" data-value="7">7</button>
<button class="number" data-value="8">8</button>
<button class="number" data-value="9">9</button>
<button class="operator" data-value="-">-</button>
<button class="number" data-value="4">4</button>
<button class="number" data-value="5">5</button>
<button class="number" data-value="6">6</button>
<button class="operator" data-value="+">+</button>
<button class="number" data-value="1">1</button>
<button class="number" data-value="2">2</button>
<button class="number" data-value="3">3</button>
<button class="equals" id="equals">=</button>
<button class="number" data-value="0">0</button>
<button class="decimal" data-value=".">.</button>
</div>
</div>
<script>
// 获取 DOM 元素
const display = document.getElementById("display");
const clearBtn = document.getElementById("clear");
const backspaceBtn = document.getElementById("backspace");
const equalsBtn = document.getElementById("equals");
const numberBtns = document.querySelectorAll(".number");
const operatorBtns = document.querySelectorAll(".operator");
const decimalBtn = document.querySelector(".decimal");
// 计算器状态
let currentValue = "0";
let previousValue = "";
let operator = "";
let resetDisplay = false;
// 更新显示
function updateDisplay() {
display.textContent = currentValue;
}
// 处理数字输入
function handleNumberInput(value) {
if (resetDisplay) {
currentValue = value;
resetDisplay = false;
} else {
currentValue = currentValue === "0" ? value : currentValue + value;
}
updateDisplay();
}
// 处理运算符输入
function handleOperatorInput(value) {
if (operator && !resetDisplay) {
calculate();
}
previousValue = currentValue;
operator = value;
resetDisplay = true;
}
// 处理小数点输入
function handleDecimalInput() {
if (!currentValue.includes(".")) {
currentValue += ".";
updateDisplay();
}
}
// 处理清除操作
function handleClear() {
currentValue = "0";
previousValue = "";
operator = "";
resetDisplay = false;
updateDisplay();
}
// 处理退格操作
function handleBackspace() {
if (currentValue.length === 1) {
currentValue = "0";
} else {
currentValue = currentValue.slice(0, -1);
}
updateDisplay();
}
// 计算结果
function calculate() {
let result;
const prev = parseFloat(previousValue);
const current = parseFloat(currentValue);
if (isNaN(prev) || isNaN(current)) return;
switch (operator) {
case "+":
result = prev + current;
break;
case "-":
result = prev - current;
break;
case "*":
result = prev * current;
break;
case "/":
result = prev / current;
break;
default:
return;
}
currentValue = result.toString();
operator = "";
previousValue = "";
resetDisplay = true;
updateDisplay();
}
// 事件监听
numberBtns.forEach(btn => {
btn.addEventListener("click", function() {
handleNumberInput(this.dataset.value);
});
});
operatorBtns.forEach(btn => {
btn.addEventListener("click", function() {
handleOperatorInput(this.dataset.value);
});
});
decimalBtn.addEventListener("click", handleDecimalInput);
clearBtn.addEventListener("click", handleClear);
backspaceBtn.addEventListener("click", handleBackspace);
equalsBtn.addEventListener("click", calculate);
// 键盘支持
document.addEventListener("keydown", function(event) {
const key = event.key;
if (key >= "0" && key <= "9") {
handleNumberInput(key);
} else if (key === ".") {
handleDecimalInput();
} else if (key === "+" || key === "-" || key === "*" || key === "/") {
handleOperatorInput(key);
} else if (key === "Enter" || key === "=") {
calculate();
} else if (key === "Backspace") {
handleBackspace();
} else if (key === "Escape") {
handleClear();
}
});
</script>
</body>
</html>20.3 待办事项清单(TODO List)
项目介绍
待办事项清单可以帮助用户管理日常任务,添加、完成和删除任务。
实现思路
- 设计待办事项的 UI 界面
- 实现添加新任务的功能
- 实现标记任务为已完成的功能
- 实现删除任务的功能
- 使用本地存储保存任务数据
完整代码
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>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
padding: 20px;
}
.container {
max-width: 600px;
margin: 0 auto;
background-color: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
h1 {
text-align: center;
margin-bottom: 30px;
color: #333;
}
.add-task {
display: flex;
gap: 10px;
margin-bottom: 30px;
}
input[type="text"] {
flex: 1;
padding: 12px;
font-size: 16px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
padding: 12px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
.task-list {
list-style: none;
}
.task-item {
display: flex;
align-items: center;
padding: 12px;
border-bottom: 1px solid #eee;
}
.task-item:last-child {
border-bottom: none;
}
.task-item.completed {
background-color: #f9f9f9;
}
.task-item.completed .task-text {
text-decoration: line-through;
color: #999;
}
.task-checkbox {
margin-right: 15px;
transform: scale(1.2);
}
.task-text {
flex: 1;
font-size: 16px;
}
.delete-btn {
background-color: #f44336;
padding: 6px 12px;
font-size: 14px;
}
.delete-btn:hover {
background-color: #da190b;
}
.empty-state {
text-align: center;
padding: 40px 20px;
color: #999;
font-size: 18px;
}
</style>
</head>
<body>
<div class="container">
<h1>待办事项清单</h1>
<div class="add-task">
<input type="text" id="taskInput" placeholder="请输入新的任务...">
<button id="addTaskBtn">添加</button>
</div>
<ul class="task-list" id="taskList">
<!-- 任务项将通过 JavaScript 动态添加 -->
</ul>
</div>
<script>
// 获取 DOM 元素
const taskInput = document.getElementById("taskInput");
const addTaskBtn = document.getElementById("addTaskBtn");
const taskList = document.getElementById("taskList");
// 从本地存储加载任务
function loadTasks() {
const tasks = JSON.parse(localStorage.getItem("tasks")) || [];
tasks.forEach(task => {
addTaskToDOM(task.text, task.completed);
});
updateEmptyState();
}
// 保存任务到本地存储
function saveTasks() {
const tasks = [];
document.querySelectorAll(".task-item").forEach(item => {
tasks.push({
text: item.querySelector(".task-text").textContent,
completed: item.classList.contains("completed")
});
});
localStorage.setItem("tasks", JSON.stringify(tasks));
}
// 添加任务到 DOM
function addTaskToDOM(text, completed = false) {
const li = document.createElement("li");
li.className = "task-item";
if (completed) {
li.classList.add("completed");
}
li.innerHTML = `
<input type="checkbox" class="task-checkbox" ${completed ? "checked" : ""}>
<span class="task-text">${text}</span>
<button class="delete-btn">删除</button>
`;
taskList.appendChild(li);
// 添加事件监听
const checkbox = li.querySelector(".task-checkbox");
const deleteBtn = li.querySelector(".delete-btn");
checkbox.addEventListener("change", function() {
li.classList.toggle("completed");
saveTasks();
});
deleteBtn.addEventListener("click", function() {
li.remove();
saveTasks();
updateEmptyState();
});
}
// 更新空状态
function updateEmptyState() {
if (taskList.children.length === 0) {
const emptyState = document.createElement("li");
emptyState.className = "empty-state";
emptyState.textContent = "还没有待办事项,添加一个吧!";
taskList.appendChild(emptyState);
} else {
const emptyState = taskList.querySelector(".empty-state");
if (emptyState) {
emptyState.remove();
}
}
}
// 添加新任务
function addTask() {
const text = taskInput.value.trim();
if (text) {
addTaskToDOM(text);
saveTasks();
taskInput.value = "";
updateEmptyState();
}
}
// 事件监听
addTaskBtn.addEventListener("click", addTask);
// 按回车键添加任务
taskInput.addEventListener("keypress", function(event) {
if (event.key === "Enter") {
addTask();
}
});
// 初始加载
loadTasks();
</script>
</body>
</html>20.4 图片轮播器
项目介绍
图片轮播器可以自动播放图片,也可以手动切换,是网站中常见的组件。
实现思路
- 设计轮播器的 UI 界面
- 实现图片的自动切换
- 实现手动切换功能
- 实现指示器功能
完整代码
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>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.slider {
position: relative;
width: 800px;
height: 400px;
overflow: hidden;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
}
.slides {
display: flex;
transition: transform 0.5s ease;
}
.slide {
width: 800px;
height: 400px;
flex-shrink: 0;
position: relative;
}
.slide img {
width: 100%;
height: 100%;
object-fit: cover;
}
.slide-content {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.6);
color: white;
padding: 20px;
}
.slide-content h3 {
margin-bottom: 10px;
font-size: 24px;
}
.slide-content p {
font-size: 16px;
}
.controls {
position: absolute;
top: 50%;
left: 0;
right: 0;
transform: translateY(-50%);
display: flex;
justify-content: space-between;
padding: 0 20px;
}
.control-btn {
background-color: rgba(255, 255, 255, 0.5);
color: #333;
border: none;
border-radius: 50%;
width: 50px;
height: 50px;
font-size: 24px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.2s;
}
.control-btn:hover {
background-color: rgba(255, 255, 255, 0.8);
}
.indicators {
position: absolute;
bottom: 20px;
left: 0;
right: 0;
display: flex;
justify-content: center;
gap: 10px;
}
.indicator {
width: 12px;
height: 12px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.5);
cursor: pointer;
transition: background-color 0.2s;
}
.indicator.active {
background-color: white;
}
.autoplay-control {
position: absolute;
top: 20px;
right: 20px;
}
.autoplay-btn {
background-color: rgba(0, 0, 0, 0.5);
color: white;
border: none;
border-radius: 4px;
padding: 8px 16px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.2s;
}
.autoplay-btn:hover {
background-color: rgba(0, 0, 0, 0.7);
}
</style>
</head>
<body>
<div class="slider">
<div class="slides" id="slides">
<div class="slide">
<img src="https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=beautiful%20nature%20landscape%20with%20mountains%20and%20lake&image_size=landscape_16_9" alt="风景 1">
<div class="slide-content">
<h3>美丽的自然风光</h3>
<p>壮观的山脉和湖泊景色</p>
</div>
</div>
<div class="slide">
<img src="https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=modern%20city%20skyline%20at%20night&image_size=landscape_16_9" alt="城市 1">
<div class="slide-content">
<h3>现代城市夜景</h3>
<p>繁华的都市天际线</p>
</div>
</div>
<div class="slide">
<img src="https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=tropical%20beach%20with%20palm%20trees&image_size=landscape_16_9" alt="海滩 1">
<div class="slide-content">
<h3>热带海滩</h3>
<p>阳光、沙滩和棕榈树</p>
</div>
</div>
<div class="slide">
<img src="https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=autumn%20forest%20with%20colorful%20leaves&image_size=landscape_16_9" alt="森林 1">
<div class="slide-content">
<h3>秋日森林</h3>
<p>色彩斑斓的秋叶</p>
</div>
</div>
</div>
<div class="controls">
<button class="control-btn" id="prevBtn">←</button>
<button class="control-btn" id="nextBtn">→</button>
</div>
<div class="indicators" id="indicators">
<!-- 指示器将通过 JavaScript 动态添加 -->
</div>
<div class="autoplay-control">
<button class="autoplay-btn" id="autoplayBtn">暂停</button>
</div>
</div>
<script>
// 获取 DOM 元素
const slides = document.getElementById("slides");
const prevBtn = document.getElementById("prevBtn");
const nextBtn = document.getElementById("nextBtn");
const indicators = document.getElementById("indicators");
const autoplayBtn = document.getElementById("autoplayBtn");
// 轮播器状态
const slideCount = slides.children.length;
let currentIndex = 0;
let autoplayInterval;
let isAutoplay = true;
// 创建指示器
function createIndicators() {
indicators.innerHTML = "";
for (let i = 0; i < slideCount; i++) {
const indicator = document.createElement("div");
indicator.className = "indicator";
if (i === currentIndex) {
indicator.classList.add("active");
}
indicator.addEventListener("click", function() {
goToSlide(i);
});
indicators.appendChild(indicator);
}
}
// 更新指示器
function updateIndicators() {
const indicatorItems = indicators.children;
for (let i = 0; i < indicatorItems.length; i++) {
if (i === currentIndex) {
indicatorItems[i].classList.add("active");
} else {
indicatorItems[i].classList.remove("active");
}
}
}
// 切换到指定幻灯片
function goToSlide(index) {
currentIndex = index;
slides.style.transform = `translateX(-${currentIndex * 100}%)`;
updateIndicators();
}
// 下一张幻灯片
function nextSlide() {
currentIndex = (currentIndex + 1) % slideCount;
goToSlide(currentIndex);
}
// 上一张幻灯片
function prevSlide() {
currentIndex = (currentIndex - 1 + slideCount) % slideCount;
goToSlide(currentIndex);
}
// 开始自动播放
function startAutoplay() {
autoplayInterval = setInterval(nextSlide, 3000);
autoplayBtn.textContent = "暂停";
isAutoplay = true;
}
// 停止自动播放
function stopAutoplay() {
clearInterval(autoplayInterval);
autoplayBtn.textContent = "播放";
isAutoplay = false;
}
// 切换自动播放状态
function toggleAutoplay() {
if (isAutoplay) {
stopAutoplay();
} else {
startAutoplay();
}
}
// 事件监听
prevBtn.addEventListener("click", prevSlide);
nextBtn.addEventListener("click", nextSlide);
autoplayBtn.addEventListener("click", toggleAutoplay);
// 初始设置
createIndicators();
startAutoplay();
</script>
</body>
</html>20.5 随机颜色生成器
项目介绍
随机颜色生成器可以生成随机的颜色,并显示颜色的十六进制代码,方便用户在设计中使用。
实现思路
- 设计颜色生成器的 UI 界面
- 实现随机颜色生成功能
- 显示颜色的十六进制代码
- 实现复制颜色代码的功能
- 实现保存喜欢的颜色的功能
完整代码
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>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
}
.container {
max-width: 800px;
width: 100%;
background-color: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.color-display {
height: 300px;
background-color: #3498db;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.color-code {
background-color: rgba(255, 255, 255, 0.9);
padding: 15px 25px;
border-radius: 50px;
font-size: 24px;
font-weight: bold;
color: #333;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}
.controls {
padding: 30px;
display: flex;
gap: 15px;
flex-wrap: wrap;
justify-content: center;
}
button {
padding: 12px 24px;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
transition: background-color 0.2s;
}
.generate-btn {
background-color: #4CAF50;
color: white;
}
.generate-btn:hover {
background-color: #45a049;
}
.copy-btn {
background-color: #3498db;
color: white;
}
.copy-btn:hover {
background-color: #2980b9;
}
.save-btn {
background-color: #f39c12;
color: white;
}
.save-btn:hover {
background-color: #e67e22;
}
.saved-colors {
padding: 0 30px 30px;
}
.saved-colors h3 {
margin-bottom: 15px;
color: #333;
}
.color-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
gap: 15px;
}
.color-item {
width: 80px;
height: 80px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
position: relative;
cursor: pointer;
transition: transform 0.2s;
}
.color-item:hover {
transform: scale(1.05);
}
.color-item .color-code-small {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(255, 255, 255, 0.9);
padding: 5px;
font-size: 12px;
font-weight: bold;
text-align: center;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
.toast {
position: fixed;
bottom: 20px;
right: 20px;
background-color: #333;
color: white;
padding: 15px 20px;
border-radius: 4px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
opacity: 0;
transition: opacity 0.3s;
}
.toast.show {
opacity: 1;
}
</style>
</head>
<body>
<h1>随机颜色生成器</h1>
<div class="container">
<div class="color-display" id="colorDisplay">
<div class="color-code" id="colorCode">#3498db</div>
</div>
<div class="controls">
<button class="generate-btn" id="generateBtn">生成随机颜色</button>
<button class="copy-btn" id="copyBtn">复制颜色代码</button>
<button class="save-btn" id="saveBtn">保存颜色</button>
</div>
<div class="saved-colors">
<h3>保存的颜色</h3>
<div class="color-grid" id="colorGrid">
<!-- 保存的颜色将通过 JavaScript 动态添加 -->
</div>
</div>
</div>
<div class="toast" id="toast">颜色代码已复制到剪贴板</div>
<script>
// 获取 DOM 元素
const colorDisplay = document.getElementById("colorDisplay");
const colorCode = document.getElementById("colorCode");
const generateBtn = document.getElementById("generateBtn");
const copyBtn = document.getElementById("copyBtn");
const saveBtn = document.getElementById("saveBtn");
const colorGrid = document.getElementById("colorGrid");
const toast = document.getElementById("toast");
// 保存的颜色
let savedColors = JSON.parse(localStorage.getItem("savedColors")) || [];
// 生成随机颜色
function generateRandomColor() {
const letters = "0123456789ABCDEF";
let color = "#";
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
// 更新颜色显示
function updateColorDisplay(color) {
colorDisplay.style.backgroundColor = color;
colorCode.textContent = color;
// 根据颜色亮度调整文本颜色
const brightness = getBrightness(color);
colorCode.style.color = brightness > 128 ? "#333" : "#fff";
}
// 计算颜色亮度
function getBrightness(color) {
const r = parseInt(color.substring(1, 3), 16);
const g = parseInt(color.substring(3, 5), 16);
const b = parseInt(color.substring(5, 7), 16);
return (r * 299 + g * 587 + b * 114) / 1000;
}
// 复制颜色代码
function copyColorCode() {
const color = colorCode.textContent;
navigator.clipboard.writeText(color)
.then(() => {
showToast("颜色代码已复制到剪贴板");
})
.catch(err => {
console.error("复制失败:", err);
showToast("复制失败,请手动复制");
});
}
// 显示提示消息
function showToast(message) {
toast.textContent = message;
toast.classList.add("show");
setTimeout(() => {
toast.classList.remove("show");
}, 2000);
}
// 保存颜色
function saveColor() {
const color = colorCode.textContent;
if (!savedColors.includes(color)) {
savedColors.push(color);
localStorage.setItem("savedColors", JSON.stringify(savedColors));
updateSavedColors();
showToast("颜色已保存");
} else {
showToast("颜色已存在");
}
}
// 更新保存的颜色
function updateSavedColors() {
colorGrid.innerHTML = "";
savedColors.forEach(color => {
const colorItem = document.createElement("div");
colorItem.className = "color-item";
colorItem.style.backgroundColor = color;
const colorCodeSmall = document.createElement("div");
colorCodeSmall.className = "color-code-small";
colorCodeSmall.textContent = color;
colorCodeSmall.style.color = getBrightness(color) > 128 ? "#333" : "#fff";
colorItem.appendChild(colorCodeSmall);
// 点击复制颜色代码
colorItem.addEventListener("click", function() {
navigator.clipboard.writeText(color)
.then(() => {
showToast("颜色代码已复制到剪贴板");
});
});
colorGrid.appendChild(colorItem);
});
}
// 事件监听
generateBtn.addEventListener("click", function() {
const color = generateRandomColor();
updateColorDisplay(color);
});
copyBtn.addEventListener("click", copyColorCode);
saveBtn.addEventListener("click", saveColor);
// 初始设置
updateColorDisplay("#3498db");
updateSavedColors();
</script>
</body>
</html>小结
- 猜数字游戏:练习了随机数生成、用户输入处理、条件判断和循环
- 简易计算器:练习了事件处理、状态管理和数学计算
- 待办事项清单:练习了DOM操作、本地存储和事件处理
- 图片轮播器:练习了定时器、DOM操作和动画效果
- 随机颜色生成器:练习了颜色生成、本地存储和用户交互
这些基础小项目可以帮助你巩固JavaScript的核心知识点,为更复杂的项目打下基础。
