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

React电影收藏列表图片溢出布局问题求助

解决React电影收藏列表图片溢出布局问题

问题分析

列表中首个项目布局正常,但后续项目出现图片溢出,核心原因:

  • .posterBlock仅设置宽度占比,未限制高度,导致图片的height:100%无法基于固定高度的父容器计算,会按自身原始比例拉伸,超出.item的固定高度。
  • 文本区域未设置空间限制,长标题或内容会撑开容器,进一步破坏整体布局。

修复方案

  1. 给.posterBlock添加height: 100%,让图片高度严格限制在容器范围内,配合object-fit: cover保证图片比例正确。
  2. 给.textBlock设置flex: 1占据剩余空间,添加overflow-y: auto,文本过长时自动出现滚动条,避免撑开容器。
  3. 给标题添加word-wrap: break-word,处理长标题换行问题。
  4. 修复React列表循环的key缺失问题,避免渲染警告。

修改后的代码

SCSS 样式修改

@import "../../mixins.scss";
.watchList {
  background-color: var(--black);
  padding-top: 50px;
  margin-bottom: 10px;

  .item {
    margin: 10px auto;
    width: 500px;
    height: 350px;
    border: 2px solid white;
    overflow: hidden; /* 防止内部元素溢出容器 */

    .itemWrapper {
      position: relative;
      height: 100%;
      width: 100%;
      display: flex;
      align-items: stretch; /* 让子元素高度铺满容器 */
      padding: 10px; /* 增加内边距,避免内容贴边框 */

      .posterBlock {
        position: relative;
        width: 40%;
        height: 100%; /* 限制海报块高度 */

        .posterImg {
          width: 100%;
          height: 100%;
          object-fit: cover;
          border-radius: 4px; /* 可选:优化视觉效果 */
        }
      }

      .textBlock {
        display: flex;
        flex-direction: column;
        margin-left: 15px;
        flex: 1; /* 占据剩余空间 */
        overflow-y: auto; /* 文本过长时滚动 */

        .title {
          font-size: 2em;
          color: white;
          margin-bottom: 10px;
          word-wrap: break-word; /* 长标题换行 */
          line-height: 1.2; /* 优化标题行高 */
        }
        .info {
          display: flex; /* 信息行内排列更整齐 */
          flex-wrap: wrap;
          .text {
            margin-right: 10px;
            opacity: 0.5;
            line-height: 24px;
            color: white;
            &.bold {
              font-weight: 600;
              opacity: 1;
            }
          }
        }

        .btn {
          background-image: linear-gradient(
            92.88deg,
            #455eb5 9.16%,
            #5643cc 43.89%,
            #673fd7 64.72%
          );
          color: white;
          font: var(--black);
          display: flex;
          justify-content: center;
          align-items: center;
          font-size: 16px;
          font-weight: 500;
          height: 2rem;
          cursor: pointer;
          border-radius: 8px;
          border-style: none;
          margin-top: auto; /* 按钮固定在文本区域底部 */
          padding: 0 1.3rem; /* 调整padding,避免按钮高度溢出 */
        }
        .btn:hover {
          box-shadow: rgba(80, 63, 205, 0.5) 0 1px 30px;
          transition-duration: 0.1s;
        }
      }
    }
  }
}

JSX 代码修改

/* this is WatchList.jsx */

import dayjs from "dayjs";
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import ContentWrapper from "../../components/contentWrapper/ContentWrapper";
import Img from "../../components/lazyLoadImage/Img";
import "./style.scss";
import { removeFromWatchList } from "../../store/homeSlice";
import PosterFallback from "../../path/to/your/fallback/image"; // 补全缺失的导入

const WatchList = () => {
  const { url, watchList } = useSelector((state) => state.home);
  const navigate = useNavigate();
  const dispatch = useDispatch();

  const removeMovieFromWatchList = (item) => {
    dispatch(removeFromWatchList(item));
  };

  return (
    <div className="watchList">
      <ContentWrapper>
        {watchList.length > 0 &&
          watchList.map((m) => {
            const posterUrl = m[0].poster_path
              ? url.poster + m[0].poster_path
              : PosterFallback;
            return (
              <div key={m[0].id} className="item"> {/* 替换空标签为带key的容器 */}
                <div className="itemWrapper">
                  <div
                    className="posterBlock"
                    onClick={() => navigate(`/${m[2]}/${m[0].id}`)}
                  >
                    <Img 
                      className="posterImg" 
                      src={posterUrl} 
                      alt={m[0].title || m[0].name} {/* 添加alt属性优化可访问性 */}
                    />
                  </div>
                  <div className="textBlock">
                    <span className="title">{m[0].title || m[0].name}</span>

                    <div className="info">
                      <span className="text bold">Released on:</span>
                      <span className="text">
                        {dayjs(m[0].release_date).format("MMM D, YYYY")}
                      </span>
                    </div>
                    <div className="info">
                      <span className="text bold">Type:</span>
                      <span className="text">
                        {m[2] === "movie" ? "Movie" : "TV series"}
                      </span>
                    </div>
                    <div className="info">
                      <span className="text bold">Added on: </span>
                      <span className="text">
                        {dayjs(m[1]).format("MMM D, YYYY")}
                      </span>
                    </div>

                    <button
                      className="btn"
                      onClick={() => removeMovieFromWatchList(m[0].id)}
                    >
                      Remove
                    </button>
                  </div>
                </div>
              </div>
            );
          })}
      </ContentWrapper>
    </div>
  );
};

export default WatchList;

修复说明

  • .posterBlock的height:100%让图片严格限制在.item的350px高度内,object-fit:cover保证图片不变形。
  • .textBlock的flex:1自动填充剩余宽度,overflow-y:auto处理长文本溢出,margin-top:auto让按钮固定在底部,保持布局一致性。
  • 补全了缺失的图片导入和alt属性,修复了列表循环的key问题。

内容的提问来源于stack exchange,提问作者RingMaster

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 22:05:53