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

React图片滑块按钮过渡失效及窗口缩放重叠问题求助

图片滑块按钮过渡效果问题解决方案

问题描述

已实现图片滑块中文本的幻灯片切换过渡效果,但按钮应用相同逻辑时出现以下问题:

  • 切换到第二张幻灯片时,按钮无过渡效果且位置偏低
  • 窗口缩放时按钮出现重叠
  • 预期每张幻灯片仅显示一个激活状态的按钮,实际未达成

相关代码

ImageSlider 组件

import { useState } from "react";
import { SliderData } from "../data";
import { categories } from "../data";
import ShopNowButtonActive from "./ShopNowButtonActive";
import { IoIosArrowBack } from "react-icons/io";
import { IoIosArrowForward } from "react-icons/io";
import "./ImageSlider.css";
import ShopNowButton from "./ShopNowButton";

const ImageSlider = ({ slides }) => {
  const [current, setCurrent] = useState(0);
  const length = slides.length;

  const nextSlide = () => {
    setCurrent(current === length - 1 ? 0 : current + 1);
  };

  const prevSlide = () => {
    setCurrent(current === 0 ? length - 1 : current - 1);
  };

  return (
    <div className="slider">
      <IoIosArrowBack className="left-arrow" onClick={prevSlide} />
      {SliderData.map((slide, index) => (
        <div key={slide.id}>
          <img
            src={slide.img}
            alt=""
            className={index === current ? "slide active" : "slide"}
          />
          <div className="info-container">
            <div className={index === current ? "title active" : "title"}>
              {slide.title}
            </div>
            <div className={index === current ? "desc active" : "desc"}>
              {slide.desc}
            </div>
            {categories.map((item, index) =>
              index === current ? (
                <ShopNowButtonActive item={item} />
              ) : (
                <ShopNowButton item={item} />
              )
            )}
          </div>
        </div>
      ))}
      <IoIosArrowForward className="right-arrow" onClick={nextSlide} />
    </div>
  );
};

export default ImageSlider;

ImageSlider.css

.slider {
  height: 90vh;
  margin-bottom: 0.5rem;
}

.left-arrow {
  position: absolute;
  top: 45%;
  left: 32px;
  font-size: 2rem;
  cursor: pointer;
  opacity: 0.5;
  z-index: 1;
}

.slide.active {
  opacity: 1;
  width: 100%;
  height: 88%;
  object-fit: cover;
  object-position: center;
  -webkit-clip-path: polygon(100% 0, 100% 80%, 50% 100%, 0 80%, 0% 0%);
  clip-path: polygon(100% 0, 100% 80%, 50% 100%, 0 80%, 0% 0%);
}

.slide {
  opacity: 0;
  transition: 500ms opacity ease-in-out;
  width: 100%;
  height: 88%;
  object-fit: cover;
  object-position: center;
  position: absolute;
  -webkit-clip-path: polygon(100% 0, 100% 80%, 50% 100%, 0 80%, 0% 0%);
  clip-path: polygon(100% 0, 100% 80%, 50% 100%, 0 80%, 0% 0%);
}

.info-container {
  display: flex;
  flex-direction: column;
  width: 40%;
  height: 100%;
  position: absolute;
  top: 45%;
  right: 30px;
}

.title.active {
  opacity: 1;
  transition-delay: 700ms;
  font-size: 4rem;
}

.title {
  opacity: 0;
  transition: 200ms opacity ease-in-out;
  font-size: 4rem;
}

.desc.active {
  opacity: 1;
  padding-top: 1.5em;
  transition-delay: 700ms;
  font-size: 1.25rem;
  font-weight: 500;
  letter-spacing: 3px;
}

.desc {
  opacity: 0;
  padding-top: 1.5em;
  transition: 200ms opacity ease-in-out;
  font-size: 1.25rem;
  font-weight: 500;
  letter-spacing: 3px;
}

.right-arrow {
  position: absolute;
  top: 45%;
  right: 32px;
  font-size: 2rem;
  cursor: pointer;
  opacity: 0.5;
  z-index: 1;
}

ShopNowButtonActive 组件

import React from "react";
import styled from "styled-components/macro";
import { Link } from "react-router-dom";

const ButtonActive = styled.button`
  opacity: 1;
  padding: 0.5rem;
  margin-top: 2.5rem;
  width: 8rem;
  font-size: 20px;
  background-color: transparent;
  cursor: pointer;
  transition-delay: 700ms;
`;

const ShopNowButtonActive = ({ item }) => {
  return (
    <Link to={`/products/${item.cat}`}>
      <ButtonActive>SHOP NOW</ButtonActive>
    </Link>
  );
};

export default ShopNowButtonActive;

ShopNowButton 组件

import React from "react";
import styled from "styled-components/macro";
import { Link } from "react-router-dom";

const Button = styled.button`
  opacity: 0;
  /* display: none; */
  padding: 0.5rem;
  margin-top: 2.5rem;
  width: 8rem;
  font-size: 20px;
  background-color: transparent;
  cursor: pointer;
  transition: 200ms opacity ease-in-out;
`;

const ShopNowButton = ({ item }) => {
  return (
    <Link to={`/products/${item.cat}`}>
      <Button>SHOP NOW</Button>
    </Link>
  );
};

export default ShopNowButton;

解决方案

1. 修复按钮重复渲染问题

当前每个幻灯片都会遍历整个categories数组渲染所有按钮,导致同一位置叠加多个按钮,这是重叠问题的核心。修改ImageSlider组件中的按钮渲染逻辑,只渲染当前幻灯片对应的按钮:

// 替换原有的categories.map代码
<ShopNowButton 
  item={categories[current]}
  isActive={index === current}
/>

2. 合并按钮组件,统一样式控制

删除ShopNowButtonActive组件,将两个按钮的逻辑合并到一个组件中,通过isActive props控制状态:

import React from "react";
import styled from "styled-components/macro";
import { Link } from "react-router-dom";

const Button = styled.button`
  opacity: ${props => props.isActive ? 1 : 0};
  padding: 0.5rem;
  margin-top: 2.5rem;
  width: 8rem;
  font-size: 20px;
  background-color: transparent;
  cursor: pointer;
  transition: opacity 200ms ease-in-out;
  transition-delay: ${props => props.isActive ? '700ms' : '0ms'};
  /* 固定按钮位置,避免偏移 */
  position: absolute;
  bottom: 2rem;
`;

const ShopNowButton = ({ item, isActive }) => {
  return (
    <Link to={`/products/${item.cat}`}>
      <Button isActive={isActive}>SHOP NOW</Button>
    </Link>
  );
};

export default ShopNowButton;

3. 调整容器布局,修复位置偏移

给info-container添加相对定位,让内部绝对定位的按钮以容器为基准定位:

.info-container {
  display: flex;
  flex-direction: column;
  width: 40%;
  height: 100%;
  position: absolute;
  top: 45%;
  right: 30px;
  position: relative; /* 添加相对定位 */
}

4. 统一幻灯片定位逻辑

给激活状态的幻灯片也添加绝对定位,确保所有幻灯片处于同一层级:

.slide.active {
  opacity: 1;
  width: 100%;
  height: 88%;
  object-fit: cover;
  object-position: center;
  -webkit-clip-path: polygon(100% 0, 100% 80%, 50% 100%, 0 80%, 0% 0%);
  clip-path: polygon(100% 0, 100% 80%, 50% 100%, 0 80%, 0% 0%);
  position: absolute; /* 添加绝对定位 */
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 21:40:16