但是到此为止,我们只是进行了activeIndex的自增,并没有真正的让页面上的元素动起来,为了实现真正的动画效果 , 我们使用useEffect对于activeIndex进行监听 。
import React, { FC, useEffect, useRef, useState } from "react";useEffect(() => { const swiper = document.querySelector("#swiper-container") as any; // 根据用户传入的轮播方向,决定是在bottom上变化还是right变化 if (direction === "vertical") { // 兼容用户输入百分比的模式 swiper.style.bottom = (height as string)?.includes("%") ? `${activeIndex * +(height as string)?.replace("%", "")}vh` : `${activeIndex * +height}px`; } else { swiper.style.right = (width as string)?.includes("%") ? `${activeIndex * +(width as string)?.replace("%", "")}vw` : `${activeIndex * +width}px`; // 判断如果到达最后一张,停止自动轮播 if (activeIndex >= urls.length - 1) { clearInterval(timer?.current); timer.current = null; setDone(true); }}, [activeIndex, urls]);截止到这里 , 其实简易的自动轮播就完成了,但是其实很多同学也会有疑问,是不是还缺少分页器(Pagination) 。
5、分页器(Pagination)分页器的原理其实很简单,我们可以分成两个步骤来看 。1、渲染与图片相同个数的节点;2、根据activeIndex动态改变分页样式 。
import React, { FC } from "react";import styled from "styled-components";const SwiperSlideBar = styled.div` margin-top: 16px; width: 100%; height: 4px; display: flex; align-items: center; justify-content: center;`;const SwiperSlideBarItem: any = styled.div` cursor: pointer; width: ${(props: any) => (props.isActive ? "26px" : "16px")}; height: 4px; background: #e6e6e6; margin-right: 6px;`;const SlideBarInner: any = styled.div` width: 100%; height: 100%; background: #0075ff; animation: ${innerFrame} ${(props: any) => `${props.speed}s`} ease;`;{urls?.length > 1 ? ( <SwiperSlideBar> {urls?.map((f: string, index: number) => ( <SwiperSlideBarItem onClick={() => slideToOne(index)} isActive={index === activeIndex} > {index === activeIndex ? <SlideBarInner speed={speed} /> : null} </SwiperSlideBarItem> ))} </SwiperSlideBar>) : null}细心的同学可能看到我在这里为什么还有一个SlideBarInner元素 , 其实是在这里实现了一个当前所在分页停留时间进度条展示的功能,感兴趣的同学可以自己看一下,我这里就不在赘述了 。
6、整体实现代码最后,我们可以看到完整的Swiper代码如下:
import React, { FC, useEffect, useRef, useState } from "react";import styled, { keyframes } from "styled-components";const innerFrame = keyframes` from { width: 0%; } to { width: 100%; }`;const Swiper = styled.div` overflow: hidden; position: relative;`;const SwiperNextTip = styled.div` position: absolute; top: 50%; transform: translateY(-50%); right: 24px; width: 32px; height: 32px; border-radius: 50%; background: #ffffff70; display: flex; justify-content: center; align-items: center; cursor: pointer; opacity: 0.7; user-select: none; :hover { opacity: 1; background: #ffffff80; }`;const SwiperPrevTip = (styled as any)(SwiperNextTip)` left: 24px;`;const SwiperContainer = styled.div` position: relative; display: flex; align-item: center; justify-content: flex-start; transition: all 0.3s ease; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -o-transition: all 0.3s ease;`;const SwiperSlide = styled.div` display: flex; align-item: center; justify-content: center; flex-shrink: 0;`;const SwiperSlideBar = styled.div` margin-top: 16px; width: 100%; height: 4px; display: flex; align-items: center; justify-content: center;`;const SwiperSlideBarItem: any = styled.div` cursor: pointer; width: ${(props: any) => (props.isActive ? "26px" : "16px")}; height: 4px; background: #e6e6e6; margin-right: 6px;`;const SlideBarInner: any = styled.div` width: 100%; height: 100%; background: #0075ff; animation: ${innerFrame} ${(props: any) => `${props.speed}s`} ease;`;const Swiper: FC< { direction?: 'horizontal' | 'vertical'; speed?: number; width: string; height: string; urls: string[]; }> = ({ direction = "horizontal", speed = 3, width = "", height = "", urls = []}) => { const [activeIndex, setActiveIndex] = useState<number>(0); const [isDone, setDone] = useState<boolean>(false); const [swiperStyle, setSwiperStyle] = useState<{ width: string; height: string; }>({ width: (width as string)?.replace("%", "vw"), height: (height as string)?.replace("%", "vh"), } as any); const timer = useRef<any>(null); const swiperContainerRef = useRef<HTMLDivElement>(null); const styles = { width: isNaN(+swiperStyle.width) ? swiperStyle!.width : `${swiperStyle!.width}px`, height: isNaN(+swiperStyle.height) ? swiperStyle.height : `${swiperStyle.height}px`, }; const startPlaySwiper = () => { if (speed <= 0) return; timer.current = setInterval(() => { setActiveIndex((preValue) => preValue + 1); }, speed * 1000); }; const slideToOne = (index: number) => { if (index === activeIndex) return; setActiveIndex(index); clearInterval(timer?.current); startPlaySwiper(); }; useEffect(() => { if (swiperContainerRef?.current) { startPlaySwiper(); } return () => { clearInterval(timer?.current); timer.current = null; }; }, [swiperContainerRef?.current]); useEffect(() => { const swiper = document.querySelector("#swiper-container") as any; if (direction === "vertical") { swiper.style.bottom = (height as string)?.includes("%") ? `${activeIndex * +(height as string)?.replace("%", "")}vh` : `${activeIndex * +height}px`; } else { swiper.style.right = (width as string)?.includes("%") ? `${activeIndex * +(width as string)?.replace("%", "")}vw` : `${activeIndex * +width}px`; } if (activeIndex >= urls.length - 1) { clearInterval(timer?.current); timer.current = null; setDone(true); } }, [activeIndex, urls]); return (<> <Swiper style={{ width, height }}> <SwiperContainer id="swiper-container" ref={swiperContainerRef} style={{ height, // 根据轮播方向参数 , 调整flex布局方向 flexDirection: direction === "horizontal" ? "row" : "column", }} > {urls.map((f: string, index: number) => ( <SwiperSlide style={{ ...styles }}> <img src=https://www.huyubaike.com/biancheng/{f} style={{ ...styles }} />
推荐阅读
- React +SpreadJS+Echarts 项目实战:在线报价采购系统
- 四十七 SpringCloud微服务实战——搭建企业级开发框架:【移动开发】整合uni-app搭建移动端快速开发框架-添加Axios并实现登录功能
- 键盘上双引号怎么打(双引号在键盘的哪一个键)
- 怎么去除电脑上一个mcafee(怎么去除电脑上的小图标)
- 六 软件架构MVC架构历史
- 编程猫怎么编程游戏(怎么用编程猫做一个高难度的游戏)
- 2d游戏怎么编程(怎么编写一个2d游戏)
- 如何开发简单的游戏(自学开发一个游戏app)
- 二 京东云开发者| Redis数据结构-List、Hash、Set及Sorted Set的结构实现
- 路由器与猫怎样正确链接(一个猫怎么连接三个路由器)