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

React.js中如何在Swiper组件外实现首尾导航按钮禁用?

实现自定义Swiper导航按钮的禁用逻辑

要实现和原生Swiper导航一致的禁用逻辑,你可以通过React状态管理按钮的禁用状态,并结合Swiper的回调事件来更新状态,具体实现如下:

  1. 添加状态变量:用useState定义左右按钮的禁用状态,初始时左侧按钮默认禁用,右侧按钮根据总幻灯片数量和每页显示数判断是否需要禁用。
  2. 绑定Swiper回调事件:通过onInit初始化状态,onSlideChange在幻灯片切换时实时更新按钮禁用状态。
  3. 关联状态与按钮:将状态值绑定到IconButton的disabled属性上,并添加禁用状态的样式优化。

修改后的完整代码:

import { useState, useRef } from 'react';
import { Container, Stack, IconButton, Box, Typography, Button } from '@mui/material';
import { ArrowBackRounded, ArrowForwardRounded, ArrowCircleRightRounded } from '@mui/icons-material';
import { styled } from '@mui/material/styles';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Autoplay } from 'swiper/modules';
import { useStaticQuery, graphql } from 'gatsby';
import GatsbyImage from 'gatsby-plugin-image';
import EicrIcon from './path-to-eicr-icon'; // 替换为你的图标实际路径

const Services = () => {
  const swiperRef = useRef();
  const [isLeftDisabled, setIsLeftDisabled] = useState(true);
  const [isRightDisabled, setIsRightDisabled] = useState(false);

  const data = useStaticQuery(graphql`
    query HomeServicesQuery {
      allFile(
        filter: { sourceInstanceName: { eq: "services" } }
        sort: { childMdx: { frontmatter: { id: ASC } } }
      ) {
        nodes {
          childMdx {
            frontmatter {
              title
              slideImage {
                childImageSharp {
                  gatsbyImageData
                }
              }
              description
            }
          }
        }
      }
    }
  `);

  const StyledSwiper = styled(Swiper)(({ theme }) => ({
    "& .swiper-wrapper": {
      marginBottom: "20px",
    },
  }));

  const servicesData = data?.allFile?.nodes;
  const totalSlides = servicesData?.length || 0;
  const slidesPerView = 3;

  // 初始化Swiper时设置按钮状态
  const handleSwiperInit = (swiper) => {
    swiperRef.current = swiper;
    // 总幻灯片数不足一页时,直接禁用右侧按钮
    setIsRightDisabled(totalSlides <= slidesPerView);
  };

  // 幻灯片切换时更新按钮禁用状态
  const handleSlideChange = (swiper) => {
    setIsLeftDisabled(swiper.isBeginning);
    setIsRightDisabled(swiper.isEnd);
  };

  return (
    <Container sx={{ mt: 10 }}>
      <Stack direction="row" alignItems="center">
        <IconButton
          color="secondary"
          onClick={() => swiperRef.current?.slidePrev()}
          disabled={isLeftDisabled}
          sx={{
            border: "1px solid",
            borderColor: "border.main",
            marginRight: "20px",
            "&:hover": {
              backgroundColor: "primary.main",
              color: "white",
            },
            "&.Mui-disabled": {
              opacity: 0.5,
              cursor: "not-allowed",
            },
          }}
        >
          <ArrowBackRounded />
        </IconButton>
        <StyledSwiper
          modules={[Autoplay]}
          spaceBetween={25}
          slidesPerView={slidesPerView}
          onInit={handleSwiperInit}
          onSlideChange={handleSlideChange}
          autoplay
        >
          {servicesData?.map((item, index) => (
            <SwiperSlide key={index}>
              <Box>
                <GatsbyImage
                  image={
                    item.childMdx.frontmatter.slideImage.childImageSharp
                      .gatsbyImageData
                  }
                  alt={item.childMdx.frontmatter.title}
                />
              </Box>
              <Box
                sx={{
                  margin: "-60px 0 0 45px",
                  backgroundColor: "white",
                  zIndex: 1,
                  position: "relative",
                  padding: "35px 30px 30px",
                  boxShadow: "0 0 20px 0 rgba(6, 22, 58, 0.11)",
                  clipPath: "inset(0px 0px -25px -25px)",
                }}
              >
                <img
                  src={EicrIcon}
                  style={{ width: "50px", marginBottom: "20px" }}
                  alt=""
                />
                <Typography
                  sx={{
                    fontSize: 22,
                  }}
                  component="h3"
                  variant="h5"
                  color="secondary"
                >
                  {item.childMdx.frontmatter.title}
                </Typography>
                <Typography
                  paragraph
                  my={1}
                  sx={{ color: "text.main", ...theme.typography.body2, mb: 2 }}
                >
                  {item?.childMdx?.frontmatter?.description?.length > 50
                    ? item.childMdx.frontmatter.description.slice(0, 47) + "..."
                    : item.childMdx.frontmatter.description}
                </Typography>
                <Button
                  disableRipple
                  endIcon={
                    <ArrowCircleRightRoundedIcon
                      sx={{ fontSize: "16px!important" }}
                    />
                  }
                  variant="black-text"
                >
                  Learn More
                </Button>
              </Box>
            </SwiperSlide>
          ))}
        </StyledSwiper>

        <IconButton
          color="secondary"
          onClick={() => swiperRef.current?.slideNext()}
          disabled={isRightDisabled}
          sx={{
            border: "1px solid",
            borderColor: "border.main",
            marginLeft: "20px",
            "&:hover": {
              backgroundColor: "primary.main",
              color: "white",
            },
            "&.Mui-disabled": {
              opacity: 0.5,
              cursor: "not-allowed",
            },
          }}
        >
          <ArrowForwardRounded />
        </IconButton>
      </Stack>
    </Container>
  );
};

export default Services;

关键说明:

  • 直接使用Swiper实例自带的isBeginning和isEnd属性判断首尾页,无需手动计算索引,逻辑更可靠
  • 初始化时判断总幻灯片数是否小于等于每页显示数,避免出现无意义的导航按钮
  • 添加禁用状态的样式调整,让用户能直观感知按钮状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 14:50:30