前言
主打:快速获取完善开发思想。
您是否在众多文章中看到过「50projects50days」项目的详细描述?垂涎三尺了?没有时间?如果您时间有限,或者只想快速领略其中的亮点,那么您来对地方了。
50projects50days项目地址:🌟🌟🌟🌟🌟
GitHub - bradtraversy/50projects50days: 50+ mini web projects using HTML, CSS & JS
简介: 想要快速领略「50projects50days」的精华,却又没有足够的时间?本文为您呈现这个项目系列的精华概览,每个项目都展示了不同的技术和创意,我们将深入剖析每个项目的关键代码和实现步骤,了解其背后的设计思想和技术原理。无论您是初学者还是有一定经验的开发者,本文都将为您提供灵感和知识,帮助您更好地理解和应用 HTML、CSS 和 JavaScript。无需大量时间投入,让我们一起探索这些项目,汲取前端技术的精华。前方的创意和知识等待着您的发现!
目录
由于篇幅问题,本文将分成数个部分来介绍项目系列。以下✅是已发布部分的导航

上期解析 41day-45day,项目展示。
- ✅ Verify Your Account(验证码)
- ✅ Live User Filter(Live用户筛选器)
- ✅ Feedback Ui Design(反馈性心情的Ui设计)
- ✅ Custom Range Slider(自定义范围滑块)
- ✅ Netflix Mobile Navigation(Netflix的移动导航)
本期解析 46day-50day,项目展示。
- ✅ [Quiz App(判题小程序)](#Quiz App(判题小程序) "#heading-3")
- ✅ [Testimonial Box Switcher(自动盒子切换器)](#Testimonial Box Switcher(自动盒子切换器) "#heading-6")
- ✅ [Random Image Feed(随机图像返回)](#Random Image Feed(随机图像返回) "#heading-9")
- ✅ [Todo List(事项清单)](#Todo List(事项清单) "#heading-12")
- ✅ [Insect Catch Game(昆虫捕捉游戏)](#Insect Catch Game(昆虫捕捉游戏) "#heading-15")
下期解析 无,项目展示。
没有了,真没有了。😘
传送门🚀
- ✅ 前端创意探索:速览「50projects50days」项目精华 - 第一部分(1-5 天)
- ✅ 前端创意探索:速览「50projects50days」项目精华 - 第二部分(6-10 天)
- ✅ 前端创意探索:速览「50projects50days」项目精华 - 第三部分(11-15 天)
- ✅ 前端创意探索:速览「50projects50days」项目精华 - 第四部分(16-20 天)
- ✅ 前端创意探索:速览「50projects50days」项目精华 - 第五部分(21-25 天)
- ✅ 前端创意探索:速览「50projects50days」项目精华 - 第六部分(26-30 天)
- ✅ 前端创意探索:速览「50projects50days」项目精华 - 第七部分(31-35 天)
- ✅ 前端创意探索:速览「50projects50days」项目精华 - 第八部分(36-40 天)
- ✅ 前端创意探索:速览「50projects50days」项目精华 - 第九部分(41-45 天)
- ✅ 前端创意探索:速览「50projects50days」项目精华 - 第十部分(46-50 天)
46、Quiz App(测验小程序)
主要关注点:关注一下数据的存储结构。
实现效果:
简单的测验应用(Quiz App)的示例,用户可以回答一系列问题并获取最终得分。

实现关键代码
HTML 结构:问题、选项、提交按钮以及最终结果的显示。
html
<div class="quiz-container" id="quiz">
<div class="quiz-header">
<h2 id="question">Question text</h2>
<ul>
<li>
<input type="radio" name="answer" id="a" class="answer">
<label for="a" id="a_text">Question</label>
</li>
<li>
<input type="radio" name="answer" id="b" class="answer">
<label for="b" id="b_text">Question</label>
</li>
<li>
<input type="radio" name="answer" id="c" class="answer">
<label for="c" id="c_text">Question</label>
</li>
<li>
<input type="radio" name="answer" id="d" class="answer">
<label for="d" id="d_text">Question</label>
</li>
</ul>
</div>
<button id="submit">Submit</button>
</div>
JavaScript 逻辑:包括测验的数据、事件监听器和得分计算逻辑。
答题的问题形成一种数组结构。
js
const quizData = [
{
question: "Which language runs in a web browser?",
a: "Java",
b: "C",
c: "Python",
d: "JavaScript",
correct: "d",
},
{
question: "What does CSS stand for?",
a: "Central Style Sheets",
b: "Cascading Style Sheets",
c: "Cascading Simple Sheets",
d: "Cars SUVs Sailboats",
correct: "b",
},
{
question: "What does HTML stand for?",
a: "Hypertext Markup Language",
b: "Hypertext Markdown Language",
c: "Hyperloop Machine Language",
d: "Helicopters Terminals Motorboats Lamborginis",
correct: "a",
},
{
question: "What year was JavaScript launched?",
a: "1996",
b: "1995",
c: "1994",
d: "none of the above",
correct: "b",
},
];
问题的展现与判题
js
if(answer) { // 判断是否选择了答案
if(answer === quizData[currentQuiz].correct) {
score++ // 这一题正确就加
}
currentQuiz++ // 指针指到下一题
if(currentQuiz < quizData.length) {
loadQuiz() // 题数不对,那就下一条
} else {
//完成题数的处理
}
}
完整的JS
js
const quiz = document.getElementById('quiz')
const answerEls = document.querySelectorAll('.answer')
const questionEl = document.getElementById('question')
const a_text = document.getElementById('a_text')
const b_text = document.getElementById('b_text')
const c_text = document.getElementById('c_text')
const d_text = document.getElementById('d_text')
const submitBtn = document.getElementById('submit')
let currentQuiz = 0
let score = 0
loadQuiz()
function loadQuiz() {
deselectAnswers()
const currentQuizData = quizData[currentQuiz]
// 加载问题
questionEl.innerText = currentQuizData.question
a_text.innerText = currentQuizData.a
b_text.innerText = currentQuizData.b
c_text.innerText = currentQuizData.c
d_text.innerText = currentQuizData.d
}
function deselectAnswers() {
answerEls.forEach(answerEl => answerEl.checked = false)
}
function getSelected() {
let answer
answerEls.forEach(answerEl => {
if (answerEl.checked) {
answer = answerEl.id
}
})
return answer
}
submitBtn.addEventListener('click', () => {
const answer = getSelected()
if (answer) {
if (answer === quizData[currentQuiz].correct) {
score++
}
currentQuiz++
if (currentQuiz < quizData.length) {
loadQuiz()
} else {
quiz.innerHTML = `
<h2>You answered ${score}/${quizData.length} questions correctly</h2>
<button onclick="location.reload()">Reload</button>
`
}
}
})
实现步骤:
- 提供测验问题和答案数据。
- 监听提交按钮的点击事件,处理问题正确性,计算用户得分,显示最终结果。
CSS样式
🐯页面的外观和布局,包括问题、选项、按钮等的样式。
没有啥留意的,看一下按钮的变化把。
css
button {
background-color: #8e44ad;
color: #fff;
border: none;
display: block;
width: 100%;
cursor: pointer;
font-size: 1.1rem;
font-family: inherit;
padding: 1.3rem;
}
button:hover {
background-color: #732d91;
}
button:focus {
outline: none;
background-color: #5e3370;
}
总结:
项目中用户回答一系列问题并获取最终得分,在答题中,把答题的问题形成一种数组结构,在点击下一题的同时,将 ++curryQuizIndex
移动角标,然后判断问题的长度是否到了最后一个(完成的效果),并且判断用户是否在这一题选择的正确(记分)。
47、Testimonial Box Switcher(自动的消息切换技术)
主要关注点:进度条的实现方式。
实现效果:
简单的推荐信展示框(Testimonial Box)的示例,用于展示用户的推荐和评价

实现关键代码
HTML 结构:推荐信内容、用户信息和进度条。
html
<div class="testimonial-container">
<div class="progress-bar"></div>
<div class="fas fa-quote-right fa-quote"></div>
<div class="fas fa-quote-left fa-quote"></div>
<p class="testimonial">
<!-- 内容-->
</p>
<div class="user">
<img
src="https://randomuser.me/api/portraits/women/46.jpg"
alt="user"
class="user-image"
/>
<div class="user-details">
<h4 class="username">Miyah Myles</h4>
<p class="role">Marketing</p>
</div>
</div>
</div>
JavaScript 逻辑:用于循环显示不同的推荐信内容。
js
// JavaScript 代码
const testimonialsContainer = document.querySelector('.testimonials-container')
const testimonial = document.querySelector('.testimonial')
const userImage = document.querySelector('.user-image')
const username = document.querySelector('.username')
const role = document.querySelector('.role')
const testimonials = [
{
name: 'Miyah Myles',
position: 'Marketing',
photo: 'URL_TO_PHOTO',
text: '推荐信文本内容1',
},
{
name: 'June Cha',
position: 'Software Engineer',
photo: 'URL_TO_PHOTO',
text: '推荐信文本内容2',
},
// (其他推荐信数据)
]
let idx = 1
function updateTestimonial() {
const { name, position, photo, text } = testimonials[idx]
testimonial.innerHTML = text
userImage.src = photo
username.innerHTML = name
role.innerHTML = position
idx++
if (idx > testimonials.length - 1) {
idx = 0
}
}
setInterval(updateTestimonial, 10000)
实现步骤:
- 提供多个不同的推荐信数据。
- 使用定时器
setInterval
循环显示不同的推荐信内容。
CSS样式
🐯主要用于页面的外观和布局,包括推荐信内容、用户信息和进度条的样式。
主要关心进度条
css
.progress-bar {
background-color: #fff;
height: 4px;
width: 100%;
animation: grow 10s linear infinite;
transform-origin: left;
}
@keyframes grow {
0% {
transform: scaleX(0);
}
/*以下可不写*/
100% {
transform: scaleX(1);
}
}
总结:
项目允许循环显示不同用户的推荐信,使用 setInterval
每隔10s时间自动切换下一个推荐信。
48、Random Image Feed(随机图像返回)
主要关注点:CSS中flex对布局的使用。
实现效果:
生成随机图片的示例,图片来自 Unsplash,使用展示的弹性。

实现关键代码
HTML 结构:标题和用于显示图片的容器。
html
<h1 class="title">Random Image Feed</h1>
<div class="container"></div>
JavaScript 逻辑:动态加载随机图片,并将它们显示在容器中。
js
const container = document.querySelector('.container')
const unsplashURL = 'https://source.unsplash.com/random/'
const rows = 5 // 加载五行
// 一行3列
for(let i = 0; i < rows * 3; i++) {
const img = document.createElement('img')
img.src = `${unsplashURL}${getRandomSize()}`
container.appendChild(img)
}
// 随机图片大小
function getRandomSize() {
return `${getRandomNr()}x${getRandomNr()}`
}
function getRandomNr() {
return Math.floor(Math.random() * 10) + 300
}
实现步骤:
- 使用 Unsplash 的随机图片 API 加载随机图片。
- 动态生成图片元素并将它们添加到容器中。
CSS样式
🐯页面的外观和布局。
css
.container {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
max-width: 1000px; // 容器宽1000px
}
.container img {
object-fit: cover;
margin: 10px;
height: 300px;
width: 300px; // 一个width定死300 刚刚好可以排3个
max-width: 100%;
}
总结:
生成了一个包含随机图片的图像流,使用flex弹性布局。
49、Todo List(事项清单)
主要关注点:监听鼠标左键都知道,下面有监听右键的,还有本地存储的一次格式转化。
实现效果:
简单的待办事项列表示例,您可以添加、标记完成和删除待办事项

实现关键代码
HTML 结构:标题、输入表单和待办事项列表。
html
<h1>todos</h1>
<form id="form">
<input type="text" class="input" id="input" placeholder="Enter your todo" autocomplete="off">
<ul class="todos" id="todos"></ul>
</form>
<small>Left click to toggle completed. <br> Right click to delete todo</small>
JavaScript 逻辑:处理待办事项的添加、标记完成和删除操作,并将数据存储在本地存储中以便保留状态。
点击监听
js
todoEl.addEventListener('click', () => {
//左键事件
})
todoEl.addEventListener('contextmenu', (e) => {
// 右键事件
})
完整js
js
const form = document.getElementById('form')
const input = document.getElementById('input')
const todosUL = document.getElementById('todos')
const todos = JSON.parse(localStorage.getItem('todos'))
// 如果有数据,就渲染更新一下数据
if(todos) {
todos.forEach(todo => addTodo(todo))
}
// 提交就新增数据
form.addEventListener('submit', (e) => {
e.preventDefault()
addTodo()
})
// 添加数据
function addTodo(todo) {
let todoText = input.value
if(todo) {
todoText = todo.text
}
if(todoText) {
const todoEl = document.createElement('li')
if(todo && todo.completed) {
todoEl.classList.add('completed')
}
todoEl.innerText = todoText
todoEl.addEventListener('click', () => {
todoEl.classList.toggle('completed')
updateLS()
})
todoEl.addEventListener('contextmenu', (e) => {
e.preventDefault()
todoEl.remove()
updateLS()
})
todosUL.appendChild(todoEl)
input.value = ''
updateLS()
}
}
function updateLS() {
todosEl = document.querySelectorAll('li')
const todos = []
todosEl.forEach(todoEl => {
todos.push({
text: todoEl.innerText,
completed: todoEl.classList.contains('completed')
})
})
// 数据存储本地
localStorage.setItem('todos', JSON.stringify(todos))
}
实现步骤:
- 初始化待办事项列表,从本地存储
JSON.parse(localStorage.getItem('todos'))
中加载已保存的待办事项。 - 处理表单提交事件,添加新的待办事项。
- 处理点击事件以标记待办事项为已完成。
- 处理右键点击事件以删除待办事项。
- 更新
localStorage.setItem('todos', JSON.stringify(todos))
本地存储中的待办事项数据。
CSS样式
🐯包括标题、输入表单、待办事项列表和小提示的样式
优先关心input框的变化
css
form {
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
max-width: 100%;
width: 400px;
}
.input {
border: none;
color: #444;
font-size: 2rem;
padding: 1rem 2rem;
display: block;
width: 100%;
}
.input::placeholder {
color: #d5d5d5;
}
.input:focus {
outline-color: rgb(179, 131, 226);
}
总结:
示例允许您创建、管理和删除待办事项,我们主要关心右键事件 contextmenu
与本地存储格式的转化:存 localStorage.setItem('todos', JSON.stringify(todos))
、取JSON.parse(localStorage.getItem('todos'))
。
50、Insect Catch Game(昆虫捕捉游戏)
主要关注点:这个游戏怎么实现的。
实现效果:
这是一个小游戏,您需要捕捉屏幕上出现的昆虫。

实现关键代码
HTML 结构:三个屏幕:起始屏幕、选择昆虫屏幕和游戏屏幕。
起始屏幕包括游戏的标题和"Play Game"按钮。
html
<div class="screen">
<h1>Catch The Insect</h1>
<button class="btn" id="start-btn">Play Game</button>
</div>
选择昆虫屏幕询问您的"favorite"昆虫,提供了不同昆虫的选项。
html
<div class="screen">
<h1>What is your "favorite" insect?</h1>
<ul class="insects-list">
<li>
<button class="choose-insect-btn">
<p>Fly</p>
<img src="http://pngimg.com/uploads/fly/fly_PNG3946.png" alt="fly">
</button>
</li>
<li>
<button class="choose-insect-btn">
<p>Mosquito</p>
<img
src="http://pngimg.com/uploads/mosquito/mosquito_PNG18175.png"
alt="mosquito"
/>
</button>
</li>
<li>
<button class="choose-insect-btn">
<p>Spider</p>
<img
src="http://pngimg.com/uploads/spider/spider_PNG12.png"
alt="spider"
/>
</button>
</li>
<li>
<button class="choose-insect-btn">
<p>Roach</p>
<img
src="http://pngimg.com/uploads/roach/roach_PNG12163.png"
alt="roach"
/>
</button>
</li>
</ul>
</div>
游戏屏幕包括计时器、分数和一群飞行的昆虫。
html
<div class="screen game-container" id="game-container">
<h3 id="time" class="time">Time: 00:00</h3>
<h3 id="score" class="score">Score: 0</h3>
<h5 id="message" class="message">
Are you annoyed yet? <br>
You are playing an impossible game!!
</h5>
</div>
JavaScript 逻辑:用于控制游戏的各个部分。
js
const screens = document.querySelectorAll('.screen');
const choose_insect_btns = document.querySelectorAll('.choose-insect-btn');
const start_btn = document.getElementById('start-btn')
const game_container = document.getElementById('game-container')
const timeEl = document.getElementById('time')
const scoreEl = document.getElementById('score')
const message = document.getElementById('message')
let seconds = 0
let score = 0
let selected_insect = {}
start_btn.addEventListener('click', () => screens[0].classList.add('up'))
// 选择一种昆虫
choose_insect_btns.forEach(btn => {
btn.addEventListener('click', () => {
const img = btn.querySelector('img')
const src = img.getAttribute('src')
const alt = img.getAttribute('alt')
selected_insect = { src, alt }
screens[1].classList.add('up')
setTimeout(createInsect, 1000)
startGame()
})
})
// 开始游戏
function startGame() {
setInterval(increaseTime, 1000)
}
// 开始计时
function increaseTime() {
let m = Math.floor(seconds / 60)
let s = seconds % 60
m = m < 10 ? `0${m}` : m
s = s < 10 ? `0${s}` : s
timeEl.innerHTML = `Time: ${m}:${s}`
seconds++
}
// 创建昆虫
function createInsect() {
const insect = document.createElement('div')
insect.classList.add('insect')
const { x, y } = getRandomLocation()
insect.style.top = `${y}px`
insect.style.left = `${x}px`
insect.innerHTML = `<img src="${selected_insect.src}" alt="${selected_insect.alt}" style="transform: rotate(${Math.random() * 360}deg)" />`
insect.addEventListener('click', catchInsect)
game_container.appendChild(insect)
}
// 创建昆虫出没的随机位置
function getRandomLocation() {
const width = window.innerWidth
const height = window.innerHeight
const x = Math.random() * (width - 200) + 100
const y = Math.random() * (height - 200) + 100
return { x, y }
}
// 捕捉到了昆虫
function catchInsect() {
increaseScore()
this.classList.add('caught')
setTimeout(() => this.remove(), 2000)
addInsects()
}
// 创建新的昆虫
function addInsects() {
setTimeout(createInsect, 1000)
setTimeout(createInsect, 1500)
}
// 增加积分
function increaseScore() {
score++
if(score > 19) {
message.classList.add('visible')
}
scoreEl.innerHTML = `Score: ${score}`
}
实现步骤:
- 单击"Play Game"按钮将切换到选择昆虫屏幕,并开始游戏。
- 单击昆虫选项后,游戏开始,创建飞行的昆虫,并启动游戏计时。
- 游戏计时会不断增加,分数随着捕捉昆虫的数量而增加。
- 游戏结束后,如果分数达到20,将显示一条消息。
CSS样式
🐯美化游戏界面。
游戏界面采用了像素风格的字体
css
@import url('https://fonts.googleapis.com/css?family=Press+Start+2P&display=swap');
* {
box-sizing: border-box;
}
body {
background-color: #516dff;
color: #fff;
font-family: 'Press Start 2P', sans-serif;
height: 100vh;
overflow: hidden;
margin: 0;
text-align: center;
}
a {
color: #fff;
}
h1 {
line-height: 1.4;
}
按钮和选项有特定的样式,包括悬停和点击效果
css
.btn {
border: 0;
background-color: #fff;
color: #516dff;
padding: 15px 20px;
font-family: inherit;
cursor: pointer;
}
.btn:hover {
opacity: 0.9;
}
.btn:focus {
outline: 0;
}
.screen {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
transition: margin 0.5s ease-out;
}
.screen.up {
margin-top: -100vh;
}
.insects-list {
display: flex;
flex-wrap: wrap;
justify-content: center;
list-style-type: none;
padding: 0;
}
.insects-list li {
margin: 10px;
}
.choose-insect-btn {
background-color: transparent;
border: 2px solid #fff;
color: #fff;
cursor: pointer;
font-family: inherit;
width: 150px;
height: 150px;
}
.choose-insect-btn:hover {
background-color: #fff;
color: #516dff;
}
.choose-insect-btn:active {
background-color: rgba(255, 255, 255, 0.7);
}
.choose-insect-btn img {
width: 100px;
height: 100px;
object-fit: contain;
}
游戏的时间
css
.game-container {
position: relative;
}
.time,
.score {
position: absolute;
top: 20px;
}
.time {
left: 20px;
}
.score {
right: 20px;
}
游戏中的昆虫具有动画效果,可以被单击捕捉。
css
.insect {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
width: 100px;
height: 100px;
position: absolute;
transform: translate(-50%, -50%) scale(1);
transition: transform 0.3s ease-in-out;
}
.insect.caught {
transform: translate(-50%, -50%) scale(0);
}
.insect img {
width: 100px;
height: 100px;
}
游戏结束后,会显示一条消息。
css
.message {
line-height: 1.7;
background-color: rgba(0, 0, 0, 0.5);
width: 100%;
padding: 20px;
z-index: 100;
text-align: center;
opacity: 0;
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -150%);
transition: transform 0.4s ease-in;
}
.message.visible {
transform: translate(-50%, 150%);
opacity: 1;
}
总结:
这个小游戏是一个简单而有趣的互动体验,可以通过点击昆虫来尽情享受游戏的乐趣。
为什么代码那么全,是由于我认为大家有意想玩玩看。
😘完结撒花🌹🌹🌹🌹🌹🌹