使用 React 映射图像数组时如何创建图像背景淡入淡出

LAT*_*T89 5 css arrays animation css-animations reactjs

我正在使用 Sanity Headless CMS 处理 React.js/Next.js 项目。

我有一个 hero 元素,它接受一组图像,但希望能够自动循环浏览以创建背景滑块效果。我很想使用光滑的滑块或类似的东西,但如果可能的话,我想尝试使用纯 CSS 来做到这一点,因为项目的 webpack 配置并没有使导入外部 css 文件变得非常容易。

我的组件...

import React from "react";
import PropTypes from "prop-types";
import styles from "./Hero.module.css";
import client from "../../client";
import SimpleBlockContent from "../SimpleBlockContent";
import Cta from "../Cta";
import imageUrlBuilder from "@sanity/image-url";

const builder = imageUrlBuilder(client);

function Hero(props) {
  const { heading, image, tagline, ctas } = props;


  const images = props.image;
  return (
    <div className={styles.root}>
      <div className={styles.content}>
        <h1 className={styles.title}>{heading}</h1>
        <div className={styles.tagline}>{tagline && <SimpleBlockContent blocks={tagline} />}</div>
        <div>
          {images.map((image) => (
            <img
              className={styles.image}
              src={builder.image(image).url()}
              className={styles.image}
              alt={heading}
            />
          ))}
        </div>
      </div>
    </div>
  );
}

Hero.propTypes = {
  heading: PropTypes.string,
  backgroundImage: PropTypes.object,
  tagline: PropTypes.array,
  ctas: PropTypes.arrayOf(PropTypes.object),
};

export default Hero;
Run Code Online (Sandbox Code Playgroud)

我的 CSS

@import "../../styles/custom-properties.css";

.root {
  composes: center from "../../styles/shared.module.css";
  position: relative;
  color: var(--color-white, #fff);
  background: none;
  padding-bottom: 2rem;

  @media (--media-min-medium) {
    padding-bottom: 1rem;
  }
}

.content {
  width: 100vw;
  min-height: 100vh;
  padding: 0 1.5em;
  box-sizing: border-box;
  z-index: 1;
  display: flex;
  justify-content: center;
  align-items: center;
}

.image {
  position: absolute;
  z-index: -1;
  left: 0;
  top: 0;
  overflow: hidden;
  display: block;
  width: 100vw;
  height: 100vh;
  object-fit: cover;
  animation: fade 2s infinite;
}

.title {
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 2px;
  position: relative;
  font-weight: 300;
  font-size: var(--font-title2-size);
  line-height: var(--font-title2-line-height);
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.5);
  margin: 0;
  padding: 0;

  @media (--media-min-medium) {
    font-size: var(--font-title1-size);
    line-height: var(--font-title1-line-height);
    padding-top: 0;
  }
}

@keyframes fade {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
Run Code Online (Sandbox Code Playgroud)

此代码确实使数组中的第一个图像淡入淡出,但不会影响“坐在”第一个图像后面的其他图像。

希望这是有道理的,任何帮助将不胜感激!

编辑 - 简化的 StackBlitz 模型

https://stackblitz.com/edit/react-wmfcbp

Rob*_*son 4

问题是您的.image类为所有图像设置了相同的 z-index 和动画属性。

尝试像这样设置延迟:

{images.map((image, index) => (
        <img
          id={index}
          className="image"
          src={image}
          style={{
            animationDelay: `${index * 4}s`, // delay animation for next images
            zIndex: `-${index + 1}` // make images as layers, not same layer -1
            }}
        />
      ))}
Run Code Online (Sandbox Code Playgroud)

但如果你使用 React,你也可以尝试在 React 中通过间隔和钩子来制作它,并通过将类应用到活动幻灯片来在 css 中制作动画幻灯片:

import React, { useRef, useState, useEffect } from "react";
import  "./Hero.css";

const images = [ 
 " https://images.unsplash.com/photo-1470165451736-166cb1cc909d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2552&q=80",

 "https://images.unsplash.com/photo-1537367075546-0529d021d198?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1500&q=80",
"https://images.unsplash.com/photo-1590064589331-f19edc8bed34?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1500&q=80"
]


function Hero(props) {
const slidePresentationTime = 3000 // after how many ms slide will change - now 3s / 3000ms
const [currentSlide, setCurrentSlide] = useState(0) // value and function to set currrent slide index
const sliderInterval = useRef() // interval ref

useEffect(() => {
  sliderInterval = setInterval(() => {
      setCurrentSlide((currentSlide + 1) % images.length); // change current slide to next slide after 'slidePresentationTime'
    }, slidePresentationTime);

    // cleanup interval when your component will unmount
    return () => {
      clearInterval(sliderInterval)
    }
})

  return (
    <div className="root">
      <div className="content">
        <h1 className="title">Title</h1>
        <div>
          {images.map((image, index) => (
            <img
              id={index}
              key={index}
              className={index === currentSlide ? 'image active' : 'image'}
              src={image}
              style={{
                zIndex: `-${index + 1}`
              }}
            />
          ))}
        </div>
      </div>
    </div>
  );
}


export default Hero;
Run Code Online (Sandbox Code Playgroud)

在这里,使用它会更容易,transitionanimation不是仅按类更改过渡属性(不透明度)。

 //styles

.image {
  position: absolute;
  left: 0;
  top: 0;
  overflow: hidden;
  display: block;
  width: 100vw;
  height: 100vh;
  object-fit: cover;
  transition: opacity 1s ease;
  opacity: 0;
}

.active {
    opacity: 1;
}
Run Code Online (Sandbox Code Playgroud)

这是演示https://stackblitz.com/edit/react-2dd6iu