React项目求助:实现电影描述框占满整行宽度
问题
我正在完成一个React课程项目,目标是搭建一个展示数据库中电影的网站。点击电影卡片时,下方会弹出一个描述框,但目前该描述框宽度仅与电影卡片一致,我希望它能占满整行宽度。
我曾尝试将.movie-description设置为position: absolute和left:0,并将.row设置为position: relative来让描述框占满宽度,这在宽度上有一定效果,但会导致其他电影卡片覆盖描述框。我认为问题根源在于描述框被包含在电影卡片的容器内,恳请提供解决方案。
相关代码
MovieGrid.jsx
import { useState } from 'react'; import FilmBild from './assets/filmBild.jpg'; import SingleMovieGridElement from "./SingleMovieGridElement.jsx"; function MovieGrid() { const [selectedMovieId, setSelectedMovieId] = useState(null); const handleMovieClick = (movieId) => { if (selectedMovieId === movieId) { setSelectedMovieId(null); // Om samma film klickas igen, stäng av beskrivningen } else { setSelectedMovieId(movieId); } }; return ( <div className="container"> <div className="row gx-4 gy-4"> {/* gx-4 ger horisontell space, gy-4 ger vertikal space */} <SingleMovieGridElement handleMovieClick={handleMovieClick} selectedMovieId={selectedMovieId} /> <div className="card mt-2 movie-description"> </div> </div> </div> ); } export default MovieGrid;
SingleMovieGridElement.jsx
import { useOutletContext } from 'react-router-dom'; import { useLoaderData } from 'react-router-dom'; //import {useState} from "react"; function SingleMovieGridElement({handleMovieClick, selectedMovieId}) { //const [handleMovieClick, selectedMovieId] = useOutletContext() const movies = useLoaderData(); console.log("filmer") console.log(movies) return( <> {movies.map((movie) => ( <div key={movie.details.id} className="col-lg-4 col-md-6 col-sm-12"> <div className="card"> <img src={`https://image.tmdb.org/t/p/original/${movie.details["poster_path"]}`} className="card-img-top img-fluid" alt={movie.details["original_title"]} onClick={() => handleMovieClick(movie.details.id)} // Klicka för att visa beskrivningen /> <div className="card-body"> <h5 className="card-title" style={{ fontSize:'1rem' }}> {movie.details["original_title"]}</h5> </div> </div> {/* Shows description for the selcted movie */} {selectedMovieId === movie.details.id && ( <div className="card mt-2 movie-description"> <div className="card-body"> <p>{movie.details["overview"]}</p> </div> </div> )} </div> ))} </>) } export default SingleMovieGridElement;
CSS文件
#root { max-width: 1280px; margin: 0 auto; padding: 2rem; text-align: center; } .logo { height: 6em; padding: 1.5em; will-change: filter; transition: filter 300ms; } .logo:hover { filter: drop-shadow(0 0 2em #646cffaa); } .logo.react:hover { filter: drop-shadow(0 0 2em #61dafbaa); } @keyframes logo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } @media (prefers-reduced-motion: no-preference) { a:nth-of-type(2) .logo { animation: logo-spin infinite 20s linear; } } .card { padding: 2em; } .read-the-docs { color: #888; } .card { box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); border-radius: 8px; overflow: hidden; display: flex; flex-direction: column; height: 350px; } .card-img-top { max-height: 200px; object-fit: cover; } .card-body { flex: 1; padding: 15px; display: flex; flex-direction: column; justify-content: space-between; } .card-title { font-size: 1rem; font-weight: bold; line-height: 1.4; overflow: hidden; text-overflow: ellipsis; white-space: normal; height: 50px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; } .card-body p { flex: 1; font-size: 0.875rem; color: #666; overflow: hidden; text-overflow: ellipsis; white-space: normal; height: 70px; } .movie-description { width: 100%; height: 300px; overflow-y: auto; } .row { position: relative; }
解决方案
核心问题确实是描述框嵌套在电影卡片的col容器里,导致宽度被限制。可以通过以下步骤解决:
1. 调整父组件逻辑,将描述框移到网格外层
修改MovieGrid.jsx,新增状态存储选中的电影数据,把描述框渲染在电影网格的外层,让它单独占一行:
import { useState } from 'react'; import FilmBild from './assets/filmBild.jpg'; import SingleMovieGridElement from "./SingleMovieGridElement.jsx"; function MovieGrid() { const [selectedMovieId, setSelectedMovieId] = useState(null); const [selectedMovie, setSelectedMovie] = useState(null); // 存储选中的电影详情 const handleMovieClick = (movieId, movie) => { if (selectedMovieId === movieId) { setSelectedMovieId(null); setSelectedMovie(null); } else { setSelectedMovieId(movieId); setSelectedMovie(movie); } }; return ( <div className="container"> <div className="row gx-4 gy-4"> {/* 传递更新后的点击回调 */} <SingleMovieGridElement handleMovieClick={handleMovieClick} selectedMovieId={selectedMovieId} /> </div> {/* 单独渲染描述框,占满整行 */} {selectedMovie && ( <div className="row mt-2"> <div className="col-12"> <div className="card movie-description"> <div className="card-body"> <h5 className="card-title">{selectedMovie.details["original_title"]}</h5> <p>{selectedMovie.details["overview"]}</p> </div> </div> </div> </div> )} </div> ); } export default MovieGrid;
2. 修改子组件的点击事件,传递电影数据
更新SingleMovieGridElement.jsx,删除嵌套在卡片里的描述框,点击时把电影对象传给父组件:
import { useOutletContext } from 'react-router-dom'; import { useLoaderData } from 'react-router-dom'; function SingleMovieGridElement({handleMovieClick, selectedMovieId}) { const movies = useLoaderData(); return( <> {movies.map((movie) => ( <div key={movie.details.id} className="col-lg-4 col-md-6 col-sm-12"> <div className="card"> <img src={`https://image.tmdb.org/t/p/original/${movie.details["poster_path"]}`} className="card-img-top img-fluid" alt={movie.details["original_title"]} {/* 点击时传递电影ID和对象 */} onClick={() => handleMovieClick(movie.details.id, movie)} /> <div className="card-body"> <h5 className="card-title" style={{ fontSize:'1rem' }}> {movie.details["original_title"]}</h5> </div> </div> {/* 删除原有的嵌套描述框 */} </div> ))} </> ) } export default SingleMovieGridElement;
3. 优化CSS样式
去掉.movie-description的width:100%,因为外层的col-12已经会让它占满整行宽度:
.movie-description { height: 300px; overflow-y: auto; }
这样修改后,描述框会出现在所有电影卡片的下方,自动占满整行宽度,同时不会被其他卡片覆盖,逻辑也更清晰。
内容的提问来源于stack exchange,提问作者user27872484
相关产品推荐
相关产品推荐

