手把手教你用原生JavaScript打造一个电影搜索应用

111 阅读3分钟

前言

在这个前端框架满天飞的时代,回归原生JavaScript开发一个功能完整的电影搜索应用,不仅能加深对基础知识的理解,更能体验到原生开发的魅力。今天我们就来一步步实现一个具有搜索功能、悬浮预览的电影展示应用。

🎬成果展示

image.png


image.png

🚀 项目概览

这是一个基于原生JavaScript开发的电影搜索应用,主要功能包括:

  • 展示热门电影列表
  • 实时搜索电影
  • 悬浮显示电影详情
  • 响应式布局设计

技术栈: 原生HTML + CSS + JavaScript + TMDb API

📁 项目结构

movie-app/
├── index.html      # 主页面
├── common.css      # 样式文件
├── script.js       # JavaScript逻辑
└── readme.md       # 项目说明

🏗️ 核心架构解析

1. HTML结构设计

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>电影</title>
  <link rel="stylesheet" href="./common.css">
</head>
<body>
  <header>
    <form action="" id="form">
      <input 
        type="text" 
        id="search" 
        class="search" 
        placeholder="Search"
        required
      >
    </form>
  </header>
  <main id="main"></main>
  <script src="./script.js"></script>
</body>
</html>

设计亮点:

  • 使用HTML5语义化标签(headermain)提升页面结构清晰度
  • required 属性进行前端表单验证,提升用户体验
  • placeholder 提供友好的输入提示
  • 将JavaScript文件放在body底部,避免阻塞页面渲染

2. CSS样式精髓

main {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
}

.movie {
  width: 300px;
  margin: 1rem;
  position: relative;
}

.movie img {
  width: 100%;
}

.overview {
  background-color: #fff;
  padding: 2rem;
  position: absolute;
  left: 0;
  bottom: 0;
  right: 0;
  min-height: 100%;
  transform: translateY(101%);
  overflow-y: auto;
  transition: transform 0.3s ease-in;
}

.movie:hover .overview {
  transform: translateY(0);
}

核心技术点:

  • Flexbox布局:实现响应式的电影卡片排列
  • CSS Transform:通过translateY()实现流畅的悬浮动画效果
  • 绝对定位:精确控制overview层的位置
  • CSS过渡transition属性创建平滑的动画体验

3. JavaScript核心逻辑

// API配置
const API_URL = 'https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=3fd2be6f0c70a2a598f084ddfb75487c&page=1'
const IMG_PATH = 'https://image.tmdb.org/t/p/w1280'
const SEARCH_API = 'https://api.themoviedb.org/3/search/movie?api_key=3fd2be6f0c70a2a598f084ddfb75487c&query="'

// DOM元素获取
const oForm = document.querySelector('#form');
const oInput = document.querySelector('#search');

// 获取电影数据
const getMovies = (keyword) => {
  let reqUrl = keyword ? SEARCH_API + keyword : API_URL;
  
  fetch(reqUrl)
    .then(res => res.json())
    .then(data => {
      showMovies(data.results);
    })
}

// 渲染电影列表
const showMovies = (movies) => {
  main.innerHTML = '';
  
  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("")
}

// 页面初始化
window.onload = function() {
  getMovies();
}

// 搜索表单处理
oForm.addEventListener('submit', function(event) {
  event.preventDefault();
  const search = oInput.value.trim();
  if (search) {
    getMovies(search);
  }
})

💡 技术要点深度解析

1. 为什么要阻止表单默认提交?

event.preventDefault();

在传统的HTML表单中,提交会导致页面刷新,这在现代Web应用中会带来糟糕的用户体验。通过preventDefault()阻止默认行为,我们可以:

  • 避免页面白屏闪烁
  • 实现无刷新的数据交互
  • 提供更流畅的用户体验

2. ES6解构赋值的优雅运用

const { poster_path, title, vote_average, overview } = movie;

相比传统的属性访问方式:

// 传统方式
const posterPath = movie.poster_path;
const title = movie.title;
const voteAverage = movie.vote_average;
const overview = movie.overview;

解构赋值让代码更加简洁优雅,一行代码就能完成多个变量的赋值。

3. 模板字符串与数组方法的完美结合

main.innerHTML = movies.map(movie => {
  // 返回HTML模板
}).join("")

这种方式相比传统的字符串拼接:

  • 代码可读性更强
  • 支持多行字符串
  • 变量插值更直观
  • 性能更优

🎯 用户体验优化细节

1. 输入验证与错误处理

  • 使用required属性进行必填验证
  • trim()方法去除输入的首尾空格
  • 条件判断确保只有有效输入才发起请求

2. 性能优化策略

  • 将JavaScript文件放在页面底部,避免阻塞页面渲染
  • 使用window.onload确保DOM完全加载后再执行脚本
  • 合理的API调用时机,避免不必要的请求

3. 交互体验提升

  • CSS过渡动画让界面变化更自然
  • 悬浮显示详情,节省页面空间
  • 响应式布局适配不同屏幕尺寸

📊 API集成最佳实践

TMDb API的使用

// 发现热门电影
const API_URL = 'https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=YOUR_API_KEY&page=1'

// 搜索电影
const SEARCH_API = 'https://api.themoviedb.org/3/search/movie?api_key=YOUR_API_KEY&query='

注意事项:

  • 将API密钥存储在环境变量中(生产环境)
  • 添加错误处理机制
  • 考虑添加加载状态提示

🔧 可扩展功能建议

  1. 分页功能:处理大量电影数据的展示
  2. 收藏功能:使用localStorage保存用户收藏
  3. 筛选排序:按年份、评分、类型筛选
  4. 详情页面:点击电影跳转到详细信息页
  5. 加载状态:添加loading动画提升用户体验

🎨 代码优化建议

1. 错误处理增强

const getMovies = async (keyword) => {
  try {
    const reqUrl = keyword ? SEARCH_API + keyword : API_URL;
    const response = await fetch(reqUrl);
    
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    
    const data = await response.json();
    showMovies(data.results);
  } catch (error) {
    console.error('获取电影数据失败:', error);
    // 显示错误提示给用户
  }
}

2. 防抖优化搜索

const debounce = (func, wait) => {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
};

// 应用防抖
const debouncedSearch = debounce(getMovies, 300);

🏆 总结

这个电影搜索应用虽然使用的是原生技术栈,但展现了现代Web开发的核心理念:

  1. 用户体验优先:流畅的动画、友好的交互设计
  2. 代码质量:模块化、可读性强的代码组织
  3. 性能意识:合理的资源加载顺序、高效的DOM操作
  4. 现代语法:ES6+特性的恰当运用

在这个框架化的时代,掌握原生JavaScript开发不仅能让我们更好地理解底层原理,也能在需要轻量级解决方案时游刃有余。

项目亮点:

  • ✅ 纯原生实现,无任何依赖
  • ✅ 响应式设计,适配多端
  • ✅ 优雅的动画效果
  • ✅ 良好的代码组织结构
  • ✅ 完整的用户交互流程

💡 小贴士:建议在学习过程中安装JSONView插件,能够更好地查看API返回的数据结构,提升开发效率。

希望这个项目能给你带来启发,让我们一起在原生JavaScript的世界里探索更多可能性!