# 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 实际上是 activeIndex 为 1 的那个,而不是 activeIndex 为 0 的那个。
- 静态渲染,即在渲染的时候已经有静态的
slideSide数据。swiper初始化时,会把activeIndex设置为1,这样展示的就是第一个slide - 还有一种情况是异步渲染,即在初始化
swiper组件时,由于没有slideSide数据,activeIndex会被设置成0。当获取到数据后,activeIndex仍然为0。所以需要手动设置activeIndex为1。即添加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;
注意点:
- 要引入对应的样式文件
import 'swiper/css/effect-fade' swiper2fadeEffect属性 要设置为crossFade: true,否则会产生文字重叠- 需要用
useState提供的setSwiperI拿到swiper2的实例,需要用到onSwiper回调函数 - 因为设置了
loop模式,且slide数据为异步获取,所以默认展示的slide是index为0的最后一个。这不是我们想要的,按照之前的解决方法设置initialSlide={1}却没有生效。最后的解决方法是,只有在拿到 slide 的数据后才进行Swiper组件的初始化,见上述代码。
← Picker 组件 找房筛选条件表单封装 →