首页 > 解决方案 > 在 React 中从一个图像源淡化到另一个图像源

问题描述

我正在构建一个天气/旅行信息单页站点作为 React 中的投资组合/实践项目。页面顶部有一个很大的“jumbotron”风格元素,中间是搜索栏。默认情况下,它会显示海滩的通用照片,然后一旦搜索到一个城市,它就会变为该城市的照片,从自定义的谷歌图像搜索 API 中提取。

这一切都很好,但我希望一个图像能够淡出到另一个图像而不是突然改变!我查看了 react-bootstrap 和 react-transitions-group 文档,但没有找到任何明显可以做到这一点的东西。

目前在顶级 App 组件中,我正在使用状态“imgUrl”,该状态会更新为新图像的 URL,以便在 API 返回时显示。那么 JSX 元素的 backgroundImage 属性就是 this.state.imgUrl。

应用组件:

import React from 'react';
import Searchbar from './components/Searchbar'
import Weather from './components/Weather'
import background from './default-bg.jpg'
import Attractions from './components/Attractions'
import ImageSearch from './components/ImageSearch'
import './App.css'

class App extends React.Component {

  state = {
    city: '',
    searched: false,
    lat: '',
    lon: '',
    imgPath: background,
    mainHeight: '596px'

  }

  city = (text) => {
    this.setState({ city: text, mainHeight: '400px' })
  }

  searched = (isSearched) => {
    this.setState({ searched: isSearched })
    
  }

  imgPath = (imgUrl) => {
    this.setState({ imgPath: imgUrl })
  }

render() {
  return (
    <div className="App">
      <div className="jumbotron justify-content-center align-items-center" style={{textAlign: "center", height: this.state.mainHeight, backgroundImage: `url(${this.state.imgPath})`, backgroundSize: "100%", backgroundPosition: "bottom", margin: "0"}}>
        <div className="container" style={{ width: "35%", backgroundColor: "seashell", opacity: "0.75", padding: "0 40px 10px 40px", borderRadius: "20px" }}>
        <span style={{ fontSize: "6em", fontWeight: "bold" }}>Snapshot</span>
        <h4 style={{ fontWeight: "bold" }}>The world at a glance</h4>
        </div>
        <br></br>

        <Searchbar city={this.city} searched={this.searched} />
      </div>

      {this.state.searched === true && 
      <div>
      <Weather city={this.state.city} />
      <Attractions city={this.state.city} />
      <ImageSearch city={this.state.city} imgPath={this.imgPath} />
      </div>
      }

    </div>
  );
}}

export default App

图片搜索组件:

import React, { Component } from 'react'

export default class ImageSearch extends Component {

    state = {
        city: this.props.city,
        cx: ###
        apiKey: ###
        imgUrl: ''
    }

    async componentDidMount() {
    const imgSearchUrl = `https://www.googleapis.com/customsearch/v1?q=${this.state.city}&num=1&searchType=image&key=${this.state.apiKey}&cx=${this.state.cx}`

        try {
            const imgRes = await fetch(imgSearchUrl)
                if (imgRes.ok) {
                    const imgJson = await imgRes.json()
                    console.log(imgJson)
                    this.setState({ imgUrl: imgJson.items[0].link })
                    this.props.imgPath(this.state.imgUrl)
                    
                    
                }
        } catch (error) {
            console.log(error)
        }

    }
    

    render() {
        return (
            <React.Fragment />
        )
    }
}

标签: cssreactjs

解决方案


好主意!此外,在组件中组合 CSS 也很巧妙。这种方法有几个众所周知的优点(我不久前在这里写过一些优点和缺点:https ://x-team.com/blog/compare-cxs-jss-performance/ )。

这里至少有几种方法可以创建这种过渡效果(淡出和淡入):

  1. https://developer.mozilla.org/en-US/docs/Web/CSS/transition - 您可以使用原生 CSS 过渡功能。它通过指定您也应用它的 CSS 属性以及效果的持续时间来为您提供细粒度的控制。这种方法的一个缺点是它会在每次重新加载页面时触发(取决于实现细节)。要使用它,您需要在现有的内联样式中添加另一个 CSS 样式属性。

  2. 另一种方法是使用关键帧 - https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes - 这可以完全在 CSS 中处理(没有任何花哨的 JS。它也不会给你一些花哨的 WebGL 增强的 JS 会产生的很酷的效果!)。这允许您为动画效果定义特定阶段,并且您描述的用例非常适合它!

干杯!

--

编辑:为了“更具体”(根据下面的评论),我还将添加第三种方法。

这是本网站讨论的一种有用的、有用的、特定的、由代码提供的技术:https ://novelist.xyz/tech/progressive-background-image-loading/ 。我稍微调整了该示例并添加了一些个人风格选择(但可以根据您的喜好随意修改一般方法)。

这种方法不太适用于过渡效果,而更多地适用于用户第一次在浏览器中加载新图像时可能发生的轻微暂停或延迟。但是,您可能需要结合多种方法来优化您的实施。此外,下面的代码片段也可用于处理更一般的过渡效果。

JavaScript:

const loadImg = (el) => {
  const url = el.getAttribute("data-src");

  let img = new Image();
  img.src = url;
  img.onload = () => {
    el.classList.add("loaded");
    el.classList.remove("loading");
    el.style.backgroundImage = "url(" + url + ")";
  };
};

您的 HTML:

<div class="image loading" id="a" data-src="https://images.unsplash.com/photo-1537767017444-30935148a2f0?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=3034&q=80">

你的 CSS:

.image {
  background-position: center center;
  background-repeat: no-repeat;
  -webkit-background-size: cover;
  -moz-background-size: cover;
  background-size: cover;
  -o-background-size: cover;
  -webkit-filter: none;
  height: 200px;
  width: 200px;
  margin: 25px;
  padding: 25px;
  flex-basis: auto;
}

.loading {
  /* for a nicer aesthetically blurry effect use the following */
  /* background-image: filter(url(https://dummyimage.com/600x400/000/fff), blur(1px)); */
  
  /* for performance make sure to use a small image placeholder file */
  /* That file will be loaded first (across all images where it's used) and cached */
  /* Alternatively, use "background: black;" so no image is loaded */
  background-image: url(https://dummyimage.com/600x400/000/fff);
  filter: none;
  transition: -webkit-filter 0s 0.2s linear, filter 0s 0.2s linear;
  opacity: 0.9;
}

.loaded {
  transition: opacity 0.5s linear;
  opacity: 1;
}

这种方法可以与 React 结合使用或合并到现有代码中。


推荐阅读