介绍
在本博客中,我们将逐步介绍使用 React 和 OMDB API 构建 Movie Finder 网站的过程。该网站允许用户按复仇者联盟、星球大战和系列等类别浏览电影,并使用特定查询搜索电影。每部电影都有其详细页面,让您轻松探索更多有关您喜爱的电影。
项目概况
电影查找网站使用户能够:
- 浏览复仇者联盟和星球大战等类别。
- 通过关键字搜索电影。
- 查看详细的电影信息(海报、类型、导演、演员等)。
- 通过简洁、现代的设计轻松浏览网站。
特征
- 使用 OMDB API 动态获取数据。
- 响应式设计,提供更好的用户体验。
- 提供即时结果的搜索功能。
- 在获取数据时加载指标。
- 在单独的页面上查看各个电影的详细信息。
使用的技术
- React:用于构建 UI 组件的前端库。
- React Router:用于导航和路由。
- Axios:用于向 OMDB API 发出 HTTP 请求。
- OMDB API:获取电影详细信息。
- CSS:用于设计应用程序的样式。
项目结构
这是该项目的目录结构:
movie-finder/ ├── public/ ├── src/ │ ├── components/ │ │ └── Navbar.js │ │ └── Footer.js │ ├── pages/ │ │ └── Home.js │ │ └── Movies.js │ │ └── Series.js │ │ └── SearchResults.js │ │ └── MovieDetail.js │ └── App.js │ └── App.css └── package.json
安装
-
克隆存储库:
git clone https://github.com/abhishekgurjar-in/movie-finder.git cd movie-finder
-
安装依赖项:
npm install
从 OMDB API 获取您的 API 密钥。
-
在项目根目录中创建一个 .env 文件并添加您的 API 密钥:
REACT_APP_OMDB_API_KEY=yourapikey
-
运行项目:
npm start
用法
1. 主页
主页展示了两类电影:《复仇者联盟》和《星球大战》。当用户点击电影卡时,他们会被重定向到详细的电影页面。
来自 Home.js 的代码片段:
import React, { useEffect, useState } from "react"; import axios from "axios"; import { useNavigate } from "react-router-dom"; import Movies from "./Movies"; import Series from "./Series"; const Home = () => { const [avengersMovies, setAvengersMovies] = useState([]); const [starWarsMovies, setStarWarsMovies] = useState([]); const [loadingAvengers, setLoadingAvengers] = useState(true); const [loadingStarWars, setLoadingStarWars] = useState(true); const navigate = useNavigate(); useEffect(() => { fetchMovies("Avengers", setAvengersMovies, setLoadingAvengers); fetchMovies("Star Wars", setStarWarsMovies, setLoadingStarWars); }, []); const fetchMovies = (query, setMovies, setLoading) => { axios .get(`http://www.omdbapi.com/?s=${query}&apikey=you_api_key`) .then((response) => { if (response.data.Search) { setMovies(response.data.Search); } else { setMovies([]); // Clear movies if no results } }) .catch((error) => { console.error(`There was an error fetching the ${query} movies!`, error); setMovies([]); // Clear movies if there is an error }) .finally(() => { setLoading(false); }); }; const handleCardClick = (id) => { navigate(`/movie/${id}`); }; const renderMovies = (movies, loading) => ( loading ? ( <div classname="loader"><div classname="load"></div></div> ) : ( <div classname="cards"> {movies.length > 0 ? ( movies.map((movie) => ( <div key="{movie.imdbID}" classname="card" onclick="{()"> handleCardClick(movie.imdbID)}> <img src="%7Bmovie.Poster%7D" alt="{movie.Title}"> <h2 id="movie-Title">{movie.Title}</h2> </div> )) ) : ( <p>No movies found.</p> )} </div> ) ); return ( <div classname="home"> <div classname="movie-category"> <h4 id="Avengers-Movies">Avengers Movies</h4> {renderMovies(avengersMovies, loadingAvengers)} </div> <br> <br> <div classname="movie-category"> <h4 id="Star-Wars-Movies">Star Wars Movies</h4> {renderMovies(starWarsMovies, loadingStarWars)} </div> </div> <movies></movies> <series></series> > ); }; export default Home;
2. 搜索功能
用户可以使用网站顶部的搜索栏搜索任何电影。搜索结果是根据用户的查询从 OMDB API 获取的。
来自 SearchResults.js 的代码片段:
import React, { useEffect, useState } from "react"; import axios from "axios"; import { useParams, useNavigate } from "react-router-dom"; const SearchResults = () => { const [movies, setMovies] = useState([]); const [loading, setLoading] = useState(false); const { query } = useParams(); const navigate = useNavigate(); // Add this line to use navigate useEffect(() => { if (query) { setLoading(true); // Set loading to true before starting the fetch axios .get(`http://www.omdbapi.com/?s=${query}&apikey=your_api_key`) .then((response) => { if (response.data.Search) { setMovies(response.data.Search); } else { setMovies([]); // Clear movies if no results } }) .catch((error) => { console.error("There was an error fetching the movie data!", error); }) .finally(() => { setLoading(false); // Set loading to false once fetch is complete }); } }, [query]); const handleCardClick = (id) => { navigate(`/movie/${id}`); // Navigate to movie detail page }; return ( <div classname="search-results"> <h4 id="Search-Results-for-query">Search Results for "{query}"</h4> {loading ? ( <div classname="loader"><div classname="load"></div></div> // Loader ) : ( <div classname="cards"> {movies.length > 0 ? ( movies.map((movie) => ( <div key="{movie.imdbID}" classname="card" onclick="{()"> handleCardClick(movie.imdbID)}> <img src="%7Bmovie.Poster%7D" alt="{movie.Title}"> <h2 id="movie-Title">{movie.Title}</h2> </div> )) ) : ( <p>No results found.</p> )} </div> )} </div> ); }; export default SearchResults;
3. 电影详情页
当用户点击电影时,他们会被重定向到电影详细信息页面。此页面显示电影的标题、海报、情节、演员等。
来自 MovieDetail.js 的代码片段:
import React, { useEffect, useState } from 'react'; import axios from 'axios'; import { useParams } from 'react-router-dom'; const MovieDetail = () => { const [movie, setMovie] = useState(null); const [loading, setLoading] = useState(true); const { id } = useParams(); useEffect(() => { axios.get(`http://www.omdbapi.com/?i=${id}&apikey=your_api_key`) .then((response) => { setMovie(response.data); }) .catch((error) => { console.error("There was an error fetching the movie details!", error); }) .finally(() => { setLoading(false); }); }, [id]); if (loading) return <div classname="loader"> <div classname="load"></div> </div>; if (!movie) return <div classname="loader">No movie data found!</div>; return ( <div classname="movie-detail"> <div classname="detail-box"> <h1 id="movie-Title">{movie.Title}</h1> <p><strong>Year:</strong> {movie.Year}</p> <p><strong>Rating:</strong> {movie.imdbRating}</p> <p><strong>Genre:</strong> {movie.Genre}</p> <p><strong>Director:</strong> {movie.Director}</p> <p><strong>Actors:</strong> {movie.Actors}</p> <p><strong>Plot:</strong> {movie.Plot}</p> <p><strong>Runtime:</strong> {movie.Runtime}</p> <p><strong>Language:</strong> {movie.Language}</p> <p><strong>Country:</strong> {movie.Country}</p> <p><strong>Awards:</strong> {movie.Awards}</p> </div> <div classname="img-box"> <img src="%7Bmovie.Poster%7D" alt="{movie.Title}"> </div> </div> ); }; export default MovieDetail;
4. 电影和连续剧页面
Movies.js 和 Series.js 页面分别列出电影和电视剧。
来自 Movies.js 的代码片段:
import React, { useEffect, useState } from "react"; import axios from "axios"; import { useNavigate } from "react-router-dom"; const Movies = () => { const [movies, setMovies] = useState([]); const navigate = useNavigate(); useEffect(() => { axios .get(`http://www.omdbapi.com/?s=Avengers&type=movie&apikey=${process.env.REACT_APP_OMDB_API_KEY}`) .then(response => setMovies(response.data.Search || [])) .catch(error => console.error(error)); }, []); const handleCardClick = (id) => { navigate(`/detail/${id}`); }; return ( <div classname="movies"> <h2 id="Movies">Movies</h2> <div classname="cards"> {movies.map(movie => ( <div key="{movie.imdbID}" classname="card" onclick="{()"> handleCardClick(movie.imdbID)}> <img src="%7Bmovie.Poster%7D" alt="{movie.Title}"> <h3 id="movie-Title">{movie.Title}</h3> </div> ))} </div> </div> ); }; export default Movies;
Series.js 中的代码片段:
import React, { useEffect, useState } from "react"; import axios from "axios"; import { useNavigate } from "react-router-dom"; const Series = () => { const [series, setSeries] = useState([]); const navigate = useNavigate(); useEffect(() => { axios .get(`http://www.omdbapi.com/?s=Star Wars&type=series&apikey=${process.env.REACT_APP_OMDB_API_KEY}`) .then(response => setSeries(response.data.Search || [])) .catch(error => console.error(error)); }, []); const handleCardClick = (id) => { navigate(`/detail/${id}`); }; return ( <div classname="series"> <h2 id="TV-Series">TV Series</h2> <div classname="cards"> {series.map(show => ( <div key="{show.imdbID}" classname="card" onclick="{()"> handleCardClick(show.imdbID)}> <img src="%7Bshow.Poster%7D" alt="{show.Title}"> <h3 id="show-Title">{show.Title}</h3> </div> ))} </div> </div> ); }; export default Series;
5. 导航栏组件
导航栏组件允许用户在不同页面之间导航并执行搜索。
更新了 Navbar.js
import React, { useState } from "react"; import { NavLink, Link } from "react-router-dom"; const Navbar = () => { const [searchQuery, setSearchQuery] = useState(""); const handleSearch = (event) => { if (event.key === 'Enter' && searchQuery.trim()) { document.getElementById('search-link').click(); } }; return ( <div classname="navbar"> <div classname="logo"> <h1 id="Movie-Finder">Movie Finder</h1> </div> <div classname="page-list"> <navlink to="/"> <h4 id="Home">Home</h4> </navlink> <navlink to="/movies"> <h4 id="Movies">Movies</h4> </navlink> <navlink to="/series"> <h4 id="TV-Series">TV Series</h4> </navlink> </div> <div classname="search-box"> <input type="text" placeholder="Search for movies or series" value="{searchQuery}" onchange="{(e)"> setSearchQuery(e.target.value)} onKeyDown={handleSearch} /> <link to="{`/search/${searchQuery}`}" id="search-link"> <button>Search</button> </div> </div> ); }; export default Navbar;
6.页脚组件
页脚组件提供简单的页脚消息。
页脚.js
import React from 'react'; const Footer = () => { return ( <div classname="footer"> Made with <span>❤️</span> by Abhishek Gurjar </div> ); }; export default Footer;
*{ box-sizing: border-box; } body{ font-family: sans-serif; margin: 0; padding: 0; } .navbar { padding-inline: 100px; display: flex; align-items: center; justify-content: space-between; background-color: red; } .search-btn{ background-color: red; } .logo h1{ font-size: 25px; color:black; } .page-list { display: flex; align-items: center; gap: 40px; } .page-list a{ color: white; text-decoration: none; font-size: 20px; } .page-list a:hover{ color: black; } .page-list a.active{ color: black; } .search-box{ box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; background-color:white; color: gray; width: 250px; height: 40px; border-radius: 50px; overflow: hidden; } .search-box input{ width: 200px; height: 40px; margin-left: 10px; border: none; outline: none; } .home{ margin-block: 40px; margin-inline: 60px; } .home h4{ font-size: 16px; } .movies{ margin-block: 40px; margin-inline: 60px; } .movies h4{ font-size: 16px; } .cards{ display: flex; flex-wrap: wrap; align-items:center ; justify-content: space-between; gap: 10px; } .card{ width:200px; height:360px; border-radius: 10px; overflow: hidden; box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; } .card img{ width: 200px; height: 290px; object-fit: cover; } .card h2{ margin: 10px; font-size: 16px; text-align: center; } .series{ margin-block: 40px; margin-inline: 60px; } .series h4{ font-size: 16px; } .home{ margin-block: 40px; margin-inline: 60px; } .search-results{ margin-block: 40px; margin-inline: 60px; } .search-results h4{ font-size: 16px; } .loader{ min-height: 90vh; display: flex; align-items: center; justify-content: center; } /* HTML: <div class="loader"></div> */ .load { width: 50px; padding: 8px; aspect-ratio: 1; border-radius: 50%; background: #ff1900; --_m: conic-gradient(#0000 10%,#000), linear-gradient(#000 0 0) content-box; -webkit-mask: var(--_m); mask: var(--_m); -webkit-mask-composite: source-out; mask-composite: subtract; animation: l3 1s infinite linear; } @keyframes l3 {to{transform: rotate(1turn)}} .movie-detail { margin-block: 40px; margin-inline: 60px; display: flex; align-items: flex-start; justify-content: space-between; } img-box{ width: 50%; } .movie-detail img { border-radius: 10px; width: 330px; height: auto; object-fit: cover; box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; } .detail-box{ width: 50%; } .movie-detail p { font-size: 18px; margin: 10px 0; } .movie-detail a { display: inline-block; margin-top: 20px; color: #007bff; text-decoration: none; } .movie-detail a:hover { text-decoration: underline; } .footer{ width: 100%; background-color: red; text-align: center; color: white; padding: 20px; }
现场演示
您可以在此处查看 Movie Finder 网站的现场演示。
结论
在本博客中,我们学习了如何使用 React、React Router 和 Axios 创建 Movie Finder 网站。该项目演示了如何与公共 API 交互、在 React 中管理状态以及创建简单而实用的电影浏览体验。
随意定制设计并添加更多功能,例如用户评论或电影评分,使其更加动态!
制作人员
- OMDB API
- 反应
- 反应路由器
作者
Abhishek Gurjar 是一位专注的 Web 开发人员,热衷于创建实用且功能性的 Web 应用程序。在 GitHub 上查看他的更多项目。
以上是使用 React 构建电影查找网站的详细内容。更多信息请关注PHP中文网其他相关文章!

我最近找到了一种动态更新任何产品图像的颜色的解决方案。因此,只有一种产品之一,我们可以以不同的方式对其进行着色以显示

在本周的综述中,灯塔在第三方脚本上阐明了灯光,不安全的资源将在安全站点上被阻止,许多国家连接速度

有很多分析平台可帮助您跟踪网站上的访问者和使用数据。也许最著名的是Google Analytics(广泛使用)

文档负责人可能不是网站上最迷人的部分,但是其中所处的内容对于您的网站的成功也一样重要

当您看到一些称为super()的JavaScript时,在子类中,您会使用super()调用其父母的构造函数和超级。访问它的


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具

Dreamweaver CS6
视觉化网页开发工具

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

Dreamweaver Mac版
视觉化网页开发工具