React如何自定义轮播图Carousel组件

 更新时间:2023年11月14日 15:07:33   作者:贺知叶  
这篇文章主要介绍了React如何自定义轮播图Carousel组件问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

自定义轮播图Carousel组件

需求:

要求0-1自定义轮播图组件,默认自动翻页,无限翻页,允许点击翻页,底部有动画进度条,且可配置轮播时间,可以操作Children.

架构

React: ^18.0. Hooks. Css. FunctionComponent

  • React : ^18.0 //未使用其他第三方库
  • Hooks //进行状态管理 模块化设计
  • Css //进行样式分离,xxx.module.css. 局部作用域样式。防止Css全局污染 函数式编程.

需求解析

可点击 + 可定义轮博时间 + 可无限轮播项 + 动画进度条 + 可配置轮播图单项内容 + 业务定制化

  • 可点击:允许用户点击底部进度条进行对应索引翻页
  • 可定义轮播时间:当前默认为3秒,可以根据业务来调节时间 3000ms = 3s
  • 可无限轮播项:useEffect 进行监听 并进行相应的操作 实现无线轮播
  • 动画进度条:底色 #0000001a 黑色+10%的透明度 固定宽度,动画颜色为 #FFFFFF 动态宽度
.css{
 animation-name: progressBar; // 指定要绑定到选择器的关键帧的名称 name = progressBar
 animation-fill-mode: forwards; // 指定动画在执行时间之外应用的值 forwards = 保留最后一个关键帧设置的样式值
 animation-iteration-count: infinite; // 指定动画播放的次数 infinite = 播放无限次
 animation-duration: 3s // 一个周期所需的时间长度 3s = 3秒
}

可配置轮播图单项内容:React.Children.mapReact.cloneElement

需求解决

一、import Carousel, { CarouselItem, CarouselInfo } from “./Carousel”;

import React, { useState, useEffect } from "react";
import style from "./carousel.module.css";

/**
 * @param {children} children ReactNode
 * @param {width} width 宽度
 * @param {height} height 高度
 * @param {styles} styles 样式
 * @returns 轮播图 单项
 */
export const CarouselItem = ({
  children = React.createElement("div"),
  width = "100%",
  height = "100%",
  styles = {},
}) => {
  return (
    <div
      className={style.carousel_item}
      style={{ width: width, height: height, ...styles }}
    >
      {children}
    </div>
  );
};

/**
 * @param {title} title 标题
 * @param {describe} describe 描述
 * @param {image} image 图片
 * @returns 轮播图 主体
 */
export const CarouselInfo = ({ title = "", describe = "", image = "" }) => {
  return (
    <div className="carousel_info_container">
      <div className="carousel_info_info">
        <h1>{title}</h1>
        <span>{describe}</span>
      </div>
      <div className="carousel_info_image_container">
        <img src={image} alt="Jay" className="carousel_info_image" />
      </div>
    </div>
  );
};

/**
 * @param {children} children ReactNode
 * @param {switchingTime} switchingTime 间隔时间 默认3秒 以毫秒为单位 3000ms = 3s
 * @returns 轮播图 容器
 */
const Carousel = ({
  children = React.createElement("div"),
  switchingTime = 3000,
}) => {
  const time = ((switchingTime % 60000) / 1000).toFixed(0); // 将毫秒转换为秒
  const [activeIndex, setActiveIndex] = useState(0); // 对应索引

  /**
   * 更新索引
   * @param {newIndex} newIndex 更新索引
   */
  const onUpdateIndex = (newIndex) => {
    if (newIndex < 0) {
      newIndex = React.Children.count(children) - 1;
    } else if (newIndex >= React.Children.count(children)) {
      newIndex = 0;
    }
    setActiveIndex(newIndex);
    replayAnimations();
  };

  /**
   * 重置动画
   */
  const replayAnimations = () => {
    document.getAnimations().forEach((anim) => {
      anim.cancel();
      anim.play();
    });
  };

  /**
   * 底部加载条点击事件
   * @param {index} index 跳转索引
   */
  const onClickCarouselIndex = (index) => {
    onUpdateIndex(index);
    replayAnimations();
  };

  useEffect(() => {
    const interval = setInterval(() => {
      onUpdateIndex(activeIndex + 1);
    }, switchingTime);

    return () => {
      if (interval) {
        clearInterval(interval);
      }
    };
  });

  return (
    <div className={style.container}>
      <div
        className={style.inner}
        style={{ transform: `translateX(-${activeIndex * 100}%)` }}
      >
        {React.Children.map(children, (child) => {
          return React.cloneElement(child, { width: "100%", height: "100vh" });
        })}
      </div>
      <div className={style.loading}>
        {React.Children.map(children, (child, index) => {
          return (
            <div
              className={style.indicator_outer}
              onClick={() => onClickCarouselIndex(index)}
            >
              <div
                className={style.indicator_inside}
                style={{
                  animationDuration: index === activeIndex ? `${time}s` : "0s",
                  backgroundColor: index === activeIndex ? "#FFFFFF" : null,
                }}
              />
            </div>
          );
        })}
      </div>
    </div>
  );
};

export default Carousel;

二、import style from “./carousel.module.css”;

.container {
  overflow: hidden;
}

.inner {
  white-space: nowrap;
  transition: transform 0.3s;
}

.carousel_item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 200px;
  color: #fff;
  background-color: #312520;
}

.loading {
  position: absolute;
  bottom: 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  margin-bottom: 10px;
  width: 100%;
}

.indicator_outer {
  width: 90px;
  height: 7px;
  background-color: #0000001a;
  margin-left: 20px;
  border-radius: 5px;
}

.indicator_inside {
  height: 100%;
  border-radius: 5px;
  animation-fill-mode: forwards;
  animation-name: progressBar;
  animation-iteration-count: infinite;
}

@keyframes progressBar {
  0% {
    width: 0%;
  }
  100% {
    width: 100%;
  }
}

三、 App.js

import "./App.css";
import React, { useState } from "react";

import JayOne from "./assets/1.jpeg";
import JayTwo from "./assets/2.jpeg";
import JayThree from "./assets/3.jpeg";
import JayFour from "./assets/4.jpeg";

import Carousel, { CarouselItem, CarouselInfo } from "./Carousel";

// 轮播图数据
const info = [
  {
    id: 1,
    title: "Jay",
    describe: "2000—11—07",
    image: JayOne,
    backgroundColor: "#425066",
  },
  {
    id: 2,
    title: "范特西",
    describe: "2001—09—20",
    image: JayTwo,
    backgroundColor: "#1bd1a5",
  },
  {
    id: 3,
    title: "范特西PLUS",
    describe: "2001—12—28",
    image: JayThree,
    backgroundColor: "#a78e44",
  },
  {
    id: 4,
    title: "八度空间",
    describe: "2002—07—18",
    image: JayFour,
    backgroundColor: "#493131",
  },
];

const App = () => {
  return (
        <Carousel>
          {info?.map((item) => {
            return (
              <CarouselItem
                key={item.id}
                styles={{ backgroundColor: item.backgroundColor }}
              >
                <CarouselInfo
                  title={item.title}
                  describe={item.describe}
                  image={item.image}
                />
              </CarouselItem>
            );
          })}
        </Carousel>
  );
};

export default App;

效果图

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • ForwardRef useImperativeHandle方法demo

    ForwardRef useImperativeHandle方法demo

    这篇文章主要为大家介绍了ForwardRef useImperativeHandle方法demo,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • React中前端路由的示例代码

    React中前端路由的示例代码

    本文主要介绍了React中前端路由的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • React Native提供自动完成的下拉菜单的方法示例

    React Native提供自动完成的下拉菜单的方法示例

    这篇文章主要为大家介绍了React Native提供自动完成的下拉菜单的方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • React和Vue中实现锚点定位功能

    React和Vue中实现锚点定位功能

    在React中,可以使用useState和useEffect钩子来实现锚点定位功能,在Vue中,可以使用指令来实现锚点定位功能,在React和Vue中实现锚点定位功能的方法略有不同,下面我将分别介绍,文中通过代码示例介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • React实现一个拖拽排序组件的示例代码

    React实现一个拖拽排序组件的示例代码

    这篇文章主要给大家介绍了React实现一个拖拽排序组件 - 支持多行多列、支持TypeScript、支持Flip动画、可自定义拖拽区域,文章通过代码示例介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • react-native弹窗封装的方法

    react-native弹窗封装的方法

    这篇文章主要为大家详细介绍了react-native弹窗封装的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • 详解如何使用React Hooks请求数据并渲染

    详解如何使用React Hooks请求数据并渲染

    这篇文章主要介绍了如何使用React Hooks请求数据并渲染,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • React中的页面跳转方式示例详解

    React中的页面跳转方式示例详解

    React Router提供了几种不同的跳转方式,包括使用组件进行页面跳转、使用组件进行重定向,以及使用编程式导航进行跳转,这篇文章主要介绍了React中的页面跳转方式详解,需要的朋友可以参考下
    2023-09-09
  • React+Typescript创建项目的实现步骤

    React+Typescript创建项目的实现步骤

    通过React组件库和TypeScript的强类型特性,开发者可以创建出具有优秀用户体验和稳定性的Web应用程序,本文主要介绍了React+Typescript创建项目的实现步骤,感兴趣的可以了解一下
    2023-08-08
  • React Native开发封装Toast与加载Loading组件示例

    React Native开发封装Toast与加载Loading组件示例

    这篇文章主要介绍了React Native开发封装Toast与加载Loading组件,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-09-09

最新评论