# 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'
swiper2
fadeEffect
属性 要设置为crossFade: true
,否则会产生文字重叠- 需要用
useState
提供的setSwiperI
拿到swiper2
的实例,需要用到onSwiper
回调函数 - 因为设置了
loop
模式,且slide
数据为异步获取,所以默认展示的slide
是index
为0
的最后一个。这不是我们想要的,按照之前的解决方法设置initialSlide={1}
却没有生效。最后的解决方法是,只有在拿到 slide 的数据后才进行Swiper
组件的初始化,见上述代码。
← Picker 组件 找房筛选条件表单封装 →