# Swiper插件踩坑

Swiper结合React使用文档 (opens new window)

# 1.配置card模式

Swiper 的每个特性在 React 中使用需要引入对应的模块,以及 css 文件

使用 autoplay 以及 cards 功能模块的示例:

import { useEffect, useState } from 'react';
import { Autoplay, EffectCards } from 'swiper';
import { Swiper, SwiperSlide } from 'swiper/react';
import 'swiper/css';
import "swiper/css/effect-cards";

const App = () => {
  const [slideList, setSlideList] = useState([]);
  useEffect(() => {
    setSlideList(["swiper1", "swiper2", "swiper3"]);
  }, []);
  return (
    <>
    <Swiper
        effect={"cards"}
        grabCursor={true}
        modules={[EffectCards, Autoplay]}
        className="mySwiper"
        loop={true}
        autoplay={{
            delay: 2500,
            disableOnInteraction: false,
          }}
        // onSwiper={(swiper) =>
        //   console.log(swiper, swiper.activeIndex, swiper.realIndex)
        // }
        // initialSlide={1}
      >
        {/* {slideList.length > 0 &&
          slideList.map((item, index) => {
            return <SwiperSlide key={index}>{item}</SwiperSlide>;
          })} */}
      </Swiper>
    </>
  )
}

# 问题1

无法复制轮播图里面的文字内容

# 解决方法1

...
allowTouchMove={false}
...

通过禁用 touchMove 事件,解决了不能复制文字的问题,但是无法通过拖拽换页,只能通过点击 navigation 箭头进行换页

# 解决方法2

...
noSwiping={true} // 设置不可拖动文字区域样式
...

<h1 className={`${styles.title} swiper-no-swiping`}>This is a Title.</h1>

通过配置 noSwiping 属性,并在对应文字内容添加 swiper-no-swiping 样式,即可禁用拖拽效果,实现文字的复制。同时不禁用轮播模块其他部分的拖拽效果。

# 问题2

loop 模式下,展示的第一张 slide 实际上是最后一张而不是第一张。

# 解决方案

配置 initialSlide={1}

# 原因

loop 模式的原理就是在 Swiper 初始化时,会复制第一个和最后一个slide置于尾部和头部。也就是说初始化时当前展示的第一个 slide 实际上是 activeIndex1 的那个,而不是 activeIndex0 的那个。

  1. 静态渲染,即在渲染的时候已经有静态的 slideSide 数据。swiper 初始化时,会把 activeIndex 设置为 1,这样展示的就是第一个 slide
  2. 还有一种情况是异步渲染,即在初始化 swiper 组件时,由于没有 slideSide 数据, activeIndex 会被设置成 0。当获取到数据后,activeIndex 仍然为 0。所以需要手动设置 activeIndex1。即添加 initialSlide={1} 属性

# 2.双向控制轮播图,swiper1轮播控制swiper2,同时swiper2要有渐显效果

需要引入 Controller EffectFade 模块,代码如下


import { useEffect, useState } from 'react';
import { Autoplay, Navigation, Controller, EffectFade } from 'swiper';
import { Swiper, SwiperSlide } from 'swiper/react';
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/effect-fade';

const HomeStories = ({ data }) => {
  const [swiperI, setSwiperI] = useState(null);
  const [storyList, setStoryList] = useState([]);
  useEffect(() => {
    if (data) {
      setStoryList(data.contentList);
    }
  }, [data]);
  return (
    <div className={styles.storyBox}>
      <div className={styles.backgroundBox}>
        {storyList.length > 0 && (
          <div className={styles.swiperContainer}>
            <div className={styles.pictureSwiperBox}>
              <Swiper
                spaceBetween={30}
                centeredSlides={true}
                autoplay={{
                  delay: 2500,
                  disableOnInteraction: false,
                }}
                pagination={{
                  clickable: true,
                }}
                // initialSlide={1}
                loop={true}
                navigation={true}
                modules={[Autoplay, Navigation, Controller]}
                className={styles.swiperImage}
                controller={{ control: swiperI }}
              >
                {storyList?.length > 0 &&
                  storyList.map((item, index) => {
                    return (
                      <SwiperSlide key={index} className={styles.swiperSlide}>
                        <img src={item.contentMedium} alt='image' />
                      </SwiperSlide>
                    );
                  })}
              </Swiper>
            </div>

            <div className={styles.textSwiperBox}>
              <Swiper
                spaceBetween={30}
                onSwiper={setSwiperI}
                style={{
                  '--swiper-navigation-color': '#101828',
                }}
                centeredSlides={true}
                pagination={{
                  clickable: true,
                }}
                noSwiping={true} // 设置不可拖动文字区域样式
                loop={true}
                effect='fade'
                fadeEffect={{
                  crossFade: true,
                }}
                initialSlide={1}
                // navigation={true}
                modules={[Autoplay, Navigation, EffectFade]}
              >
                {storyList?.length > 0 &&
                  storyList.map((item, index) => (
                    <SwiperSlide className={styles.textSwiperSlide} key={index}>
                      <div className={styles.textBox}>
                        <h1 className='swiper-no-swiping'>{item.contentTitle}</h1>
                        <p className='swiper-no-swiping'>{item.contentSummary}</p>
                      </div>
                    </SwiperSlide>
                  ))}
              </Swiper>
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

export default HomeStories;

注意点:

  1. 要引入对应的样式文件 import 'swiper/css/effect-fade'
  2. swiper2 fadeEffect 属性 要设置为 crossFade: true,否则会产生文字重叠
  3. 需要用 useState 提供的 setSwiperI 拿到 swiper2 的实例,需要用到 onSwiper 回调函数
  4. 因为设置了 loop 模式,且 slide 数据为异步获取,所以默认展示的 slideindex0 的最后一个。这不是我们想要的,按照之前的解决方法设置 initialSlide={1} 却没有生效。最后的解决方法是,只有在拿到 slide 的数据后才进行 Swiper 组件的初始化,见上述代码。
LastEditTime: 2023/4/5 23:54:54