前端开发不缺项目练习,但能覆盖 HTML、CSS、JavaScript 三项基础技能的实战项目不算多。于是我用原生技术栈写了一个简单但实用的电影搜索网站:支持关键词搜索、卡片动态展示、信息弹出等交互,整个过程没有用到任何框架或构建工具。
整套流程从零开始,包括页面结构设计、样式布局优化、数据请求与事件处理,细节尽量做到体验流畅、逻辑清晰,适合想巩固前端三剑客基础的朋友练手。
一、HTML 结构:简洁 + 语义化
HTML 是网页的骨架。在这个项目中,结构主要依靠 HTML5 语义标签构建,比如:
html
<form action="" id="form">
<input
type="text"
id="search"
class="search"
placeholder="Search"
required
>
</form>
这里有几个值得注意的点:
placeholder
属性可以在输入框内显示一段淡灰色的文字,用于提示用户该字段应该输入什么内容,能有效降低用户的理解成本,placeholder
只是辅助提示,不应用作表单字段的标签替代。required
是 HTML5 提供的基础校验机制,表单中的required
属性可防止用户提交空字段,是一种无需写 JavaScript 的前端验证手段。当用户试图提交未填写的必填项时,浏览器会自动阻止表单提交并展示原生的提示信息。- 虽然用了
<form>
,但我们后面会用 JavaScript 阻止默认提交行为,实现"非刷新"的搜索体验。
这些小细节都是为了降低用户误操作,让操作更顺手。
二、CSS 设计:布局 + 动效增强交互 + 响应式思维
页面美观、结构清晰之外,用户的视觉体验和交互直觉 同样离不开 CSS 的配合。本项目用到了 Flexbox
做卡片布局,结合定位 + 动效,构建了一个既灵活又具表现力的 UI。
🎯 布局部分:Flexbox 实现卡片自适应排列
css
main {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.movie {
width: 300px;
margin: 1rem;
position: relative;
}
display: flex
让主区域横向排布;flex-wrap: wrap
保证在小屏幕上自动换行;justify-content: center
保证所有卡片居中展示;.movie
卡片设置固定宽度,保证统一性和对齐效果;- 使用
position: relative
,为后面的.overview
设置绝对定位做准备。
这种写法比传统的 float + margin 更简洁可控,也非常适合响应式布局。
✨ 动效部分:实现卡片悬停时显示简介
css
.overview {
position: absolute;
left: 0;
bottom: 0;
right: 0;
background-color: #fff;
padding: 2rem;
min-height: 100%;
transform: translateY(101%);
transition: transform 0.3s ease-in;
}
.movie:hover .overview {
transform: translateY(0);
}
这部分实现了一个经典的"卡片悬停展开内容"交互:
position: absolute
+bottom: 0
让简介位于卡片底部;- 默认通过
transform: translateY(101%)
隐藏在卡片下方; - 悬停时,
transform
变为0
,内容滑出显示; transition
保证这个过程平滑自然,避免突兀闪现。
这种效果不仅好看,而且是提升信息密度的好方式:用户可以在不点击的情况下预览更多内容,类似于 Netflix 式卡片。
三、JavaScript:数据请求 + 事件监听 + 模块化组织
相比 HTML/CSS,JavaScript 是这个项目的"灵魂所在"。我们用它完成了:
- 页面首次加载时获取热门电影;
- 用户输入关键词后进行搜索;
- 动态将结果渲染到页面上;
- 提高用户体验的同时,也让项目具备了"应用感"。
🚀 Step 1:定义 API 地址
项目使用了 TMDB 提供的开放电影数据接口:
javascript
const API_URL = 'https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=你的APIKEY&page=1';
const IMG_PATH = 'https://image.tmdb.org/t/p/w1280';
const SEARCH_API = 'https://api.themoviedb.org/3/search/movie?api_key=你的APIKEY&query=';
📥 Step 2:封装请求函数
使用 fetch
发送网络请求,默认加载热门电影,也可通过关键词进行搜索。
javascript
const getMovies = (keyword = '') => {
const reqUrl = keyword ? SEARCH_API + keyword : API_URL;
fetch(reqUrl)
.then(response => {
if (!response.ok) throw new Error('网络请求失败');
return response.json();
})
.then(data => showMovies(data.results))
.catch(err => {
console.error('请求错误:', err);
main.innerHTML = '<p class="error">加载失败,请稍后重试。</p>';
});
};
- 错误处理 :
response.ok
判定是否成功,防止 silent fail; - 兜底 UI:加载失败时展示友好提示,而不是空页面;
- 函数默认值 :
keyword = ''
让调用更灵活。
🧱 Step 3:渲染页面内容
通过 innerHTML
将请求到的电影列表展示在页面中:
javascript
const showMovies = (movies) => {
if (!movies.length) {
main.innerHTML = '<p class="empty">没有找到相关电影。</p>';
return;
}
main.innerHTML = movies.map(movie => {
const { poster_path, title, vote_average, overview } = movie;
return `
<div class="movie">
<img src="${IMG_PATH + poster_path}" alt="${title}">
<div class="movie-info">
<h3>${title}</h3>
<span>${vote_average}</span>
</div>
<div class="overview">
<h3>Overview</h3>
${overview}
</div>
</div>
`;
}).join('');
};
- 空状态处理 :当结果为
[]
时提示"未找到电影",避免页面一片空白; - 解构赋值:用 ES6 解构写法提取字段,简洁直观;
- 模板字符串:插值表达式比字符串拼接更清晰,利于维护。
🔄 Step 4:表单事件监听(核心交互)
阻止默认表单提交行为,用 JS 接管搜索逻辑:
javascript
const oForm = document.querySelector('#form');
const oInput = document.querySelector('#search');
oForm.addEventListener('submit', function(event) {
event.preventDefault();
const search = oInput.value.trim();
if (search) {
getMovies(search);
oInput.value = ''; // 清空输入框
} else {
alert('请输入电影名称');
}
});
preventDefault()
:阻止默认刷新页面行为;.trim()
:防止用户只输入空格;.value = ''
:搜索后自动清空输入,增强体验;alert()
:最基础的验证方式,后期可改为更友好的 UI 提示(如 Toast)。
🕓 Step 5:页面加载完成时默认请求热门电影
javascript
window.onload = function () {
getMovies();
};
也可以用 DOMContentLoaded
替代:
javascript
document.addEventListener('DOMContentLoaded', () => {
getMovies();
});
四、实用补充:调试与开发小工具
- ✅ 推荐安装 JSONView 插件:方便直接查看 API 返回的 JSON 数据结构;

- ✅ 建议遵循统一的代码风格:比如字节、腾讯等公司的内部规范(模块划分、命名规范、注释清晰)虽然朴素,却非常实用。
五、项目亮点总结
这个项目虽然简单,但也涵盖了前端开发中的关键知识点:
- HTML 的语义化与可访问性设计;
- CSS 布局与交互动画;
- JavaScript 的事件处理与模块化封装;
- 真实 API 数据请求与渲染逻辑。
项目整体围绕"提升用户体验"展开,比如阻止默认刷新、卡片式排布、悬停展开信息等,每一步都体现了从用户角度出发的思考。
✍️ 结语
纯原生开发,不依赖任何框架,代码逻辑清晰、结构可控,是很好的入门练习素材。如果你也想找一个扎实的项目练习基础,不妨跟着做一遍,再试着加入更多功能:
- 分页加载;
- 类型筛选;
- 本地收藏夹;
- 深色模式切换;
- 加入后端或缓存机制。
欢迎点赞 + 收藏 + 评论,一起交流 👇