You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 05:22:33