如何使用React类组件和Tailwind CSS创建一个旋转木马

318 阅读9分钟

如何使用React类组件和Tailwind CSS创建一个旋转木马

旋转木马是一种循环播放一系列内容的幻灯片。这些内容可以是图片、文本或视频。通过使用上一个和下一个控件,可以从一个旋转木马的幻灯片过渡到另一个。过渡也可以通过使用定时器来自动进行。

在这篇文章中,我们将使用React类组件创建一个旋转木马组件,并使用Tailwind CSS进行样式设计。React是一个JavaScript库,用于创建用户界面。

Tailwind CSS是一个CSS框架,使用实用类来设计网页的样式

目标

  • 使用React类组件创建一个旋转木马。
  • 使用Tailwind CSS对旋转木马进行样式设计。
  • 实现旋转木马的自动播放功能。
  • 在移动设备上实现滑动功能。

前提条件

要跟上本教程,你将需要。

  • React的基本知识。
  • 中级CSS知识。
  • 一个代码编辑器,最好是[VS Code]。
  • 一个浏览器,最好是Chrome。
  • 在你的机器上安装[Node.js]。

设置我们的项目

在Windows操作系统中,打开命令提示符,并导航到你想创建项目的位置。然后运行以下命令。

npx create-react-app react-tailwind-carousel

上面的命令将创建我们的React项目。

键入下面的命令来导航到项目目录。

cd react-tailwind-carousel

如果你使用的是VS Code,在命令提示符下键入以下命令,或者打开你的代码编辑器并打开包含项目的文件夹。

code .

打开集成终端,键入以下命令,在开发服务器上打开该项目。

npm run start

上面的命令,默认情况下,在localhost 3000端口启动项目。打开浏览器,输入以下地址:http://localhost:3000。如果你看到旋转的反应标志和它下面的一些文字,这意味着项目已经成功设置了。

下一步是在我们的项目中安装Tailwind CSS。

安装依赖项

以下是我们将在我们的项目中使用的依赖项。

  • react-icons - 我们将使用这个包来获得下一个和上一个图标。
  • react-easy-swipe - 我们将使用这个包来实现移动设备上的刷卡功能。

运行下面的命令来安装它们。

npm install react-icons react-easy-swipe

创建旋转木马

由于所有的组件都是默认的功能组件。打开App.js 组件并清除一切。然后粘贴以下代码。

import React, { Component } from "react";

export default class App extends Component {
  render() {
    return <div className="flex justify-center"></div>;
  }
}

上面的代码显示了我们如何定义一个类组件。这是根组件,我们将把其他组件导入这个组件中,以呈现给用户。

这个div有两个样式应用于它。这些样式有助于使组件在整个网页上水平居中。

接下来,打开src 文件夹,创建一个名为**component/**的文件夹。我们将在这里创建所有单独的组件。

在组件文件夹中,创建两个组件。

  • CarouselData.js - 这个组件将保存旋转木马的所有数据。它将是一个数组,包含我们将在旋转木马中显示的不同图片的链接。
  • Carousel.js - 这个组件将包含旋转木马的所有互动元素,包括下一个和上一个按钮、滑动指示器以及旋转木马的所有功能。

创建CarouselData.js组件

打开CarouselData.js文件,粘贴以下代码。

export const CarouselData = [
  {
    image:
      "https://images.unsplash.com/photo-1546768292-fb12f6c92568?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
  },
  {
    image:
      "https://images.unsplash.com/photo-1501446529957-6226bd447c46?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1489&q=80",
  },
  {
    image:
      "https://images.unsplash.com/photo-1483729558449-99ef09a8c325?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1350&q=80",
  },
  {
    image:
      "https://images.unsplash.com/photo-1475189778702-5ec9941484ae?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1351&q=80",
  },
  {
    image:
      "https://images.unsplash.com/photo-1503177119275-0aa32b3a9368?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1350&q=80",
  },
];

上面的代码是一个对象数组,包含了我们将在旋转木马中显示的图片的链接。

创建Carousel.js组件

打开Carousel.js组件,粘贴以下代码。

import React, { Component } from "react";
import { CarouselData } from "./CarouselData";
import { AiOutlineLeft, AiOutlineRight } from "react-icons/ai";
import Swipe from "react-easy-swipe";

class Carousel extends Component {
  constructor(props) {
    super(props);
    this.state = {
      currentSlide: 0,
    };
  }

  render() {
    return (
      <div className="mt-8">
        <div className="max-w-lg h-72 flex overflow-hidden relative">
          {CarouselData.map((slide, index) => {
            return (
              <img
                src={slide.image}
                alt="This is a carousel slide"
                key={index}
                className={
                  index === this.state.currentSlide
                    ? "block w-full h-auto object-cover"
                    : "hidden"
                }
              />
            );
          })}
        </div>
      </div>
    );
  }
}

export default Carousel;

我们首先导入CarouselData 组件,以获得将在旋转木马中显示的图片。

然后,我们从react-icons 包中导入左和右箭头。

最后,我们导入Swipe 包,这将帮助我们在移动设备中添加刷卡功能。

在状态部分,我们将活动状态定义为0。该状态将被一个函数修改,该函数将相应地增加或减少它。这将帮助我们决定显示哪个幻灯片。

我们给容器中的div一个类别,即mt-8 ,翻译成margin-top: 2rem。这就使我们的旋转木马远离了顶部的边距。然后我们再创建一个包含各个图片的div。

在这个div里面,我们使用JavaScript数组map() 方法。

在这个例子中,map() 方法需要两个参数:幻灯片--指CarouselData数组中的每个单独的元素,以及索引--指数组中每个单独元素的索引。该方法还需要一个回调,返回设置为src 的图像,slide.image

然后我们给图像一个类,在这个类中,我们使用条件渲染来决定我们将显示哪张图像。这是通过使用三元操作符实现的。

这段代码。

className={index===this.state.currentSlide ? 'block w-full h-auto object-cover' : 'hidden'}

翻译为:如果索引(这是map()方法中的一个参数)等于类中定义的currentSlide 状态,则对图像应用类block w-full h-auto object-cover 。否则,将hidden 类应用到图像上。这意味着我们一次只能查看一个图像。

用下面的代码更新App.js ,导入旋转木马组件,并将其渲染到浏览器中。

import React, { Component } from "react";
import Carousel from "./components/Carousel";

export default class App extends Component {
  render() {
    return (
      <div className="flex justify-center">
        <Carousel />
      </div>
    );
  }
}

添加下一个和上一个按钮

在浏览器上,我们只能查看一张图片。我们需要添加导航按钮来帮助我们从一张图片移动到另一张。

要做到这一点,在Carousel.js组件中,在包含地图方法的div内添加以下代码。

<AiOutlineLeft className='absolute left-0 text-3xl inset-y-1/2 text-white cursor-pointer' />

<AiOutlineRight className='absolute right-0 text-3xl inset-y-1/2 text-white cursor-pointer' />

我们插入两个箭头,并对它们进行相应的定位。

为了给箭头添加功能,添加onClick 事件监听器,它将监听一个点击事件并导航到相应的幻灯片。

<AiOutlineLeft onClick={this.prevSlide} className='absolute left-0 text-3xl inset-y-1/2 text-white cursor-pointer' />

<AiOutlineRight onClick={this.nextSlide} className='absolute right-0 text-3xl inset-y-1/2 text-white cursor-pointer' />

现在,我们必须创建当我们点击按钮时将被调用的函数。在构造函数方法下,添加以下几行代码。

nextSlide = () => {
  let newSlide =
    this.state.currentSlide === CarouselData.length - 1
      ? 0
      : this.state.currentSlide + 1;
  this.setState({ currentSlide: newSlide });
};

prevSlide = () => {
  let newSlide =
    this.state.currentSlide === 0
      ? CarouselData.length - 1
      : this.state.currentSlide - 1;
  this.setState({ currentSlide: newSlide });
};

nextSlide 函数在用户点击下一个按钮时被调用。

在这个函数中,我们首先定义了一个名为newSlide 的变量。然后我们有条件地给这个变量赋值。如果currentSlide状态等于包含图片的数组的长度,我们将newSlide 的值设置为0。否则,我们将增加currentSlide状态的值。

这有助于确保我们能够不断地循环浏览图片。然后我们使用setState 方法来更新currentSlide的值。

当用户点击上一个按钮时,prevSlide 函数被调用。newSlide变量根据currentSlide状态的值有条件地分配一个值。

假设currentSlide状态等于0,在这种情况下,newSlide变量被分配的值相当于包含图像的数组长度-1(即最后一张图像)。

实现圆点/指示器

这些通常位于旋转木马的底部,用于显示当前的幻灯片和幻灯片的总数。它们也可以用来在幻灯片之间进行导航。

要实现这些圆点,请在包含图片的div中复制以下代码。

<div className="absolute w-full flex justify-center bottom-0">
  {CarouselData.map((element, index) => {
    return (
      <div
        className={
          index === this.state.currentSlide
            ? "h-2 w-2 bg-blue-700 rounded-full mx-2 mb-2 cursor-pointer"
            : "h-2 w-2 bg-white rounded-full mx-2 mb-2 cursor-pointer"
        }
        key={index}
        onClick={() => {
          this.setCurrentSlide(index);
        }}
      ></div>
    );
  })}
</div>

该代码在数组中循环,为每个元素返回一个div。每个div都有一个onClick 事件监听器,当点击时调用一个setCurrentSlide 函数,并将被点击的div的索引作为一个参数传递。

我们有条件地分配类,以确保活动幻灯片的点与其他的不同。

prevSlide函数的下面,复制以下代码。

setCurrentSlide = (index) => {
  this.setState({ currentSlide: index });
};

上面的函数接收被点击的div的索引作为参数,并使用它来设置currentSlide状态的值。

现在,到浏览器上http://localhost:3000/。你会看到,你可以通过点击小圆点,或者上一个和下一个按钮在不同的图片之间切换。

实现幻灯片的自动播放和悬停时的暂停

要做到这一点,请修改状态部分,使其看起来像这样。

this.state = {
  currentSlide: 0,
  paused: false,
};

为了实现自动播放,我们将使用javascript的setInterval() 方法和componentDidMount() 方法。

componentDidMount(){
      setInterval(() => {
        if(this.state.paused === false){
          let newSlide = this.state.currentSlide === CarouselData.length - 1 ? 0 : this.state.currentSlide + 1
          this.setState({currentSlide: newSlide})
        }
      }, 3000)
    }

在上面的代码中,setInterval() 方法在组件安装时被调用。它只在暂停状态被设置为false时执行。它使用一个条件语句来给newSlide变量赋值,然后将currentSlide状态设置为赋值。它有助于确定要显示的图像。

setInterval() 方法还需要另一个参数,延迟,它决定了代码执行的时间间隔。在本例中,延迟是3000ms,这意味着该函数每隔3秒就执行一次。

为了实现悬停时的暂停,我们将使用onMouseEnteronMouseLeave事件监听器。在img标签上添加以下事件监听器。

onMouseEnter={() => {
    this.setState({paused: true})
}}

onMouseLeave={() => {
    this.setState({paused: false})
}}

onMouseEnter 是在你将光标移动到包含图像的区域时触发的。一旦触发,它将暂停状态修改为真,并暂停自动播放。

onMouseLeave 当你把光标从包含图像的区域移开时被触发。一旦触发,它将暂停的状态修改为假,并恢复自动播放。

在移动设备上实现刷屏功能

要做到这一点,我们将使用我们之前安装的react-easy-swipe 包。

<Swipe></Swipe> 标签放在你想监听刷卡事件的区域周围。在本例中,它是围绕产生图像的map() 方法。

<Swipe onSwipeLeft={this.nextSlide} onSwipeRight={this.prevSlide}>
  {CarouselData.map((slide, index) => {
    return (
      <img
        src={slide.image}
        alt="This is a carousel slide"
        key={index}
        className={
          index === this.state.currentSlide
            ? "block w-full h-auto object-cover"
            : "hidden"
        }
        onMouseEnter={() => {
          this.setState({ paused: true });
        }}
        onMouseLeave={() => {
          this.setState({ paused: false });
        }}
      />
    );
  })}
</Swipe>

Swipe标签接收onSwipeLeftonSwipeRight 属性,并调用适当的函数。

现在你有一个使用React类组件和Tailwind CSS创建的全功能旋转木马。

旋转木马组件的完整代码

import React, { Component } from "react";
import { CarouselData } from "./CarouselData";
import { AiOutlineLeft, AiOutlineRight } from "react-icons/ai";
import Swipe from "react-easy-swipe";

class Carousel extends Component {
  constructor(props) {
    super(props);
    this.state = {
      currentSlide: 0,
      paused: false,
    };
  }

  componentDidMount() {
    setInterval(() => {
      if (this.state.paused === false) {
        let newSlide =
          this.state.currentSlide === CarouselData.length - 1
            ? 0
            : this.state.currentSlide + 1;
        this.setState({ currentSlide: newSlide });
      }
    }, 3000);
  }

  nextSlide = () => {
    let newSlide =
      this.state.currentSlide === CarouselData.length - 1
        ? 0
        : this.state.currentSlide + 1;
    this.setState({ currentSlide: newSlide });
  };

  prevSlide = () => {
    let newSlide =
      this.state.currentSlide === 0
        ? CarouselData.length - 1
        : this.state.currentSlide - 1;
    this.setState({ currentSlide: newSlide });
  };

  setCurrentSlide = (index) => {
    this.setState({ currentSlide: index });
  };

  render() {
    return (
      <div className="mt-8">
        <div className="max-w-lg h-72 flex overflow-hidden relative">
          <AiOutlineLeft
            onClick={this.prevSlide}
            className="absolute left-0 text-3xl inset-y-1/2 text-white cursor-pointer"
          />

          <Swipe onSwipeLeft={this.nextSlide} onSwipeRight={this.prevSlide}>
            {CarouselData.map((slide, index) => {
              return (
                <img
                  src={slide.image}
                  alt="This is a carousel slide"
                  key={index}
                  className={
                    index === this.state.currentSlide
                      ? "block w-full h-auto object-cover"
                      : "hidden"
                  }
                  onMouseEnter={() => {
                    this.setState({ paused: true });
                  }}
                  onMouseLeave={() => {
                    this.setState({ paused: false });
                  }}
                />
              );
            })}
          </Swipe>

          <div className="absolute w-full flex justify-center bottom-0">
            {CarouselData.map((element, index) => {
              return (
                <div
                  className={
                    index === this.state.currentSlide
                      ? "h-2 w-2 bg-blue-700 rounded-full mx-2 mb-2 cursor-pointer"
                      : "h-2 w-2 bg-white rounded-full mx-2 mb-2 cursor-pointer"
                  }
                  key={index}
                  onClick={() => {
                    this.setCurrentSlide(index);
                  }}
                ></div>
              );
            })}
          </div>

          <AiOutlineRight
            onClick={this.nextSlide}
            className="absolute right-0 text-3xl inset-y-1/2 text-white cursor-pointer"
          />
        </div>
      </div>
    );
  }
}

export default Carousel;

总结

旋转木马是网站的一个重要组成部分,因为它有助于改善用户体验。

在上面的例子中,我们已经涵盖了旋转木马的主要部分。

然而,你可以通过添加动画和在大屏幕上显示一个以上的项目来改进它。