Carousel
是一个像旋转木马一样会轮流转的轮播元件。在一个内容空间有限的可视范围中进行内容的轮播展示。通常适用於一组图片或是卡片的轮播。
Carousel 的样式也是五花八门,随便在 google 下一个关键字就能够找到各种不同形式的 Carousel。
所以在这边我们也是挑一个简单易做的 Carousel 来实现。
dataSource
由於是一组轮流播放的图片,所以首先我们需要提供给这个元件一个 list 的资料,其中 list 的每一笔资料我们希望能够包含一个 image url。
autoplay
autoplay 提供一个 boolean 来决定这个轮播是否自动切换。
dots
dots 是一个 boolean,用来决定是否出现「指示点」。
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
className | 客制化样式 | string | |
dataSource | 轮播资料 | list of image url | |
autoplay | 是否自动播放 | boolean | false |
hasDots | 是否显示指示点 | boolean | true |
hasControlArrow | 是否显示上一个、下一个切换键 | boolean | true |
我们的 Carousel 包含了轮播图片本身、左右切换按钮,以及指示点,所以 DOM 大致上会长得像下面这个形状:
<CarouselWrapper>
<ImageWrapper>
{...images...}
</ImageWrapper>
<ControlButtons />
<Dots />
</CarouselWrapper>
由下图知道,轮播图片、左右切换按钮以及指示点都是叠在一起的,有点是分不同图层的概念,所以这边的定位都是使用 position: absolute;
。
图片轮播的计算方法
我们就直接来看 Carousel 的核心,到底要怎麽让图片可以轮播。
这边我们是要做 slide 动画的轮播,所以为了让图片可以在 X 轴上左右滑动,我们势必会使用到 position: absolute;
、left
、transition
这三个关键的 CSS。
如下图示意,为了让图片能够左右滑动轮播,我们可以先将图片排成一整排,并且在可视范围之外的地方隐藏这些图片。
排成一整排的方式不能像我们以前那样使用 flex 布局来达成,而是会需要算一些数学,计算出每一张图片的位置,也就是他的 left
值,之後要轮转的时候,就是去改变这个 left
数值,搭配 transition
过场动画,就能够做到我们轮播的效果。
概念上已经说明完了,接下来我们来看程序码,left 的计算很简单,就是目前迭代到的这个 image 与正在可视范围中的那个 current image 的距离,乘上图片的宽度就是了:
const makePosition = ({ itemIndex }) => (itemIndex - currentIndex) * imageWidth;
<ImageWrapper>
{
dataSource.map((imageUrl, index) => (
<Image
key={imageUrl}
src={imageUrl}
alt=""
$left={makePosition({ itemIndex: index })}
/>
))
}
</ImageWrapper>
切换图片的左右按钮
切换左右的按钮我希望只专注在计算哪一张图片是 current ,也就是正在可视范围中的图片,避免在这些 function 里面做太多其他的事,保持他功能的单纯性。
所以看下面 click next 的 function,我只有计算让 current index 不断的 +1
,直到尾部的时候再从头开始;反之,click prev 的 function 就是让 current index 不断的 -1
,直到 0 的时候再从尾部开始:
const getIndexes = () => {
const prevIndex = currentIndex - 1 < 0 ? dataSource.length - 1 : currentIndex - 1;
const nextIndex = (currentIndex + 1) % dataSource.length;
return {
prevIndex, nextIndex,
};
};
const handleClickPrev = () => {
const { prevIndex } = getIndexes();
setCurrentIndex(prevIndex);
};
const handleClickNext = useCallback(() => {
const { nextIndex } = getIndexes();
setCurrentIndex(nextIndex);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentIndex]);
<ControlButtons>
<ArrowLeft onClick={handleClickPrev} />
<ArrowRight onClick={handleClickNext} />
</ControlButtons>
自动播放
自动播放当然就是要靠我们的 setInterval
了,我们每 3 秒就改变 current index 一次,改变的方式我们就直接呼叫上面做好的 handleClickNext
function 就可以了:
useEffect(() => {
let intervalId;
if (autoplay) {
intervalId = setInterval(() => {
handleClickNext();
}, 3000);
}
return () => {
clearInterval(intervalId);
};
}, [autoplay, handleClickNext]);
以上就是我们 Carousel 的重点整理啦!简单展示一下成果:
Carousel 元件原始码:
Source code
Storybook:
Carousel
<<: [Day 13]每天前进一点应该也是进步吧?(前端篇)
>>: 【PHP Telegram Bot】Day19 - 基础(8):回圈、Xdebug
这个系列开始我们先介绍了 RSS feed 里面的内容和不同平台的格式,也了解到要一次处理这麽多又有...
之前我们在写 API 程序的时候,一开始使用写死在程序里的资料集合(List),这个方法虽然快速让我...
元件介绍 Checkbox 是一个多选框元件。通常使用情境是在一个群组的选项当中进行多项选择时使用。...
tags: 2021铁人赛 React 上一篇刻好版型後,这篇就可以来串接API拉,目标当然就是让使...
图片截自三立新闻 与笔者年纪相当的朋友,肯定还记得小时候有个非常红的电示节目叫「龙兄虎弟」吧。当时...