用原生 JavaScript 写了一个电影搜索网站,体验拉满🔥

前端开发不缺项目练习,但能覆盖 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 数据请求与渲染逻辑。

项目整体围绕"提升用户体验"展开,比如阻止默认刷新、卡片式排布、悬停展开信息等,每一步都体现了从用户角度出发的思考。


✍️ 结语

纯原生开发,不依赖任何框架,代码逻辑清晰、结构可控,是很好的入门练习素材。如果你也想找一个扎实的项目练习基础,不妨跟着做一遍,再试着加入更多功能:

  • 分页加载;
  • 类型筛选;
  • 本地收藏夹;
  • 深色模式切换;
  • 加入后端或缓存机制。

欢迎点赞 + 收藏 + 评论,一起交流 👇

相关推荐
Hilaku6 分钟前
我用 Cursor 写了两个月代码,项目代码量不降反升,为什么?
前端·javascript·架构
哀木7 分钟前
识别手写数字,居然可以只靠前端?
前端
Dream耀10 分钟前
掌握Flex布局核心:项目属性深度指南
前端·css·html
绅士玖18 分钟前
从电影网站揭秘:前端开发中那些鲜为人知的黑科技与设计哲学
前端·javascript·css
_风满楼20 分钟前
如何优雅展示日历中的重叠日程?三步搞定复杂布局
前端·javascript·算法
CAD老兵20 分钟前
TypeScript 函数重载详解:原理、实践与最佳用法
前端
前端西瓜哥21 分钟前
图形编辑器开发:钢笔工具新增和删除并连接锚点
前端
LuckySusu21 分钟前
【HTML 篇】深入理解 Web Worker:让 JavaScript 在后台默默工作
前端·html
前端日常开发22 分钟前
前端实现画中画,让网页飞出浏览器
前端