使用 React 映射图像数组时如何创建图像背景渐变

Posted

技术标签:

【中文标题】使用 React 映射图像数组时如何创建图像背景渐变【英文标题】:How to create an image background fade when mapping an array of images with React 【发布时间】:2020-09-25 14:08:00 【问题描述】:

我正在使用 Sanity 无头 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;

我的 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;
  

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

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

编辑 - 简化的 StackBlitz 模型

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

【问题讨论】:

如果您在 stackblitz 上分享有关该问题的工作演示会更容易提供帮助 感谢@AkberIqbal 添加了一个非常基本的内容,但希望能得到重点 【参考方案1】:

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

尝试像这样设置延迟:

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

但是如果你使用 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;

在这里使用transition 而不是animation 会容易得多,只需按类更改过渡属性(不透明度)。

 //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;

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

【讨论】:

非常好的解决方案,感谢@Robson。在将 babel 实施到我的项目中时,我遇到了一些问题,但我相信实际的源代码运行良好!

以上是关于使用 React 映射图像数组时如何创建图像背景渐变的主要内容,如果未能解决你的问题,请参考以下文章

Next.js 以线性渐变为背景的图像组件

如何从 React 中的公共文件夹设置背景图像(创建 React 应用程序)

如何在反应中从数组中映射出预加载的图像?

React-native:如何在布局(视图)的背景中设置图像

div、背景图像和图像映射

如何在反应中从对象映射动态设置 sessionStorage