Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/383.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何检测何时加载通过道具提供的图像,并在React中更改状态?_Javascript_Image_Reactjs_Loading_State - Fatal编程技术网

Javascript 如何检测何时加载通过道具提供的图像,并在React中更改状态?

Javascript 如何检测何时加载通过道具提供的图像,并在React中更改状态?,javascript,image,reactjs,loading,state,Javascript,Image,Reactjs,Loading,State,我想在加载最终的化身图像时加载另一个图像(假化身)。其思想是检测道具图像何时加载并更改状态。可能吗?一些想法?谢谢大家! class ImageUser extends React.Component { constructor(props) { super(props); this.state = {userImageLoaded: false}; let imageSrc = ""; if (!this.props.userImage) {

我想在加载最终的化身图像时加载另一个图像(假化身)。其思想是检测道具图像何时加载并更改状态。可能吗?一些想法?谢谢大家!

class ImageUser extends React.Component {

constructor(props) {
    super(props);
    this.state = {userImageLoaded: false};
    let imageSrc = "";

    if (!this.props.userImage) {
        imageSrc = this.props.noUserImage;
    } else {
        imageSrc = this.props.userImage;
    }

    this.loadingImage = <img className={styles.imageUser}
                     src={this.props.loadingImage} alt="2"/>;

    this.userImage =
        <img onLoad={this.setState({userImageLoaded: true})}
             className={styles.imageUser} src={imageSrc}
             alt="1"/>;

}

render() {
    let image = "";
    if (this.state.userImageLoaded) {
        image = this.userImage;
    } else {
        image = this.loadingImage;
    }
    return (
        <div>
            {image}
        </div>
    );
}
}

export default ImageUser;
类ImageUser扩展React.Component{
建造师(道具){
超级(道具);
this.state={userImageLoaded:false};
设imageSrc=“”;
如果(!this.props.userImage){
imageSrc=this.props.nouser图像;
}否则{
imageSrc=this.props.userImage;
}
this.loadingImage=;
这个是.userImage=
;
}
render(){
让图像=”;
if(this.state.userImageLoaded){
image=this.userImage;
}否则{
image=this.loadingImage;
}
返回(
{image}
);
}
}
导出默认图像用户;

有几种方法可以做到这一点,但最简单的方法是显示隐藏的最终图像,然后在加载后将其翻转为可见

类Foo扩展了React.Component{
构造函数(){
超级();
this.state={loaded:false};
}
render(){
返回(
{this.state.loaded?空:
}
this.setState({loaded:true})
/>
);
}
}

与Brigand接受的答案相同,但带有钩子:

const Foo = ({ src }) => {
  const [loaded, setLoaded] = useState(false);

  return (
    <div>
      {loaded ? null : (
        <div
          style={{
            background: 'red',
            height: '400px',
            width: '400px'
          }}
        />
      )}
      <img
        style={loaded ? {} : { display: 'none' }}
        src={src}
        onLoad={() => setLoaded(true)}
      />
    </div>
  );
};
constfoo=({src})=>{
const[loaded,setLoaded]=useState(false);
返回(
{已加载?空:(
)}
setLoaded(true)}
/>
);
};
很有用,谢谢

我想加强你的力量并补充 用于背景图像

  constructor(){
    super();
    this.state = {loaded: false};
  }

  render(){
    return (
      <div>
        {this.state.loaded ? null :
          <div
            style={{
              background: 'red',
              height: '400px',
              width: '400px',
            }}
          />
        }
        <img
          style={{ display: 'none' }}
          src={this.props.src}
          onLoad={() => this.setState({loaded: true})}
        />
       <div 
         style={ {
                  background: `url(${this.props.src})`
                   ,display: this.state.loaded?'none':'block'
                }}
        />
      </div>
    );
  }
}```
constructor(){
超级();
this.state={loaded:false};
}
render(){
返回(
{this.state.loaded?空:
}
this.setState({loaded:true})
/>
);
}
}```

检测何时加载图像的更好方法是创建对元素的引用,然后向引用添加事件侦听器。您可以避免在元素中添加事件处理程序代码,并使代码更易于阅读,如下所示:

    class Foo extends React.Component {
        constructor(){
            super();
            this.state = {loaded: false};
            this.imageRef = React.createRef();
        }

        componentDidMount() {
            this.imageRef.current.addEventListener('load', onImageLoad);
        }

        onImageLoad = () => { 
            this.setState({loaded: true})
        }

        render(){
            return (
              <div>
                {this.state.loaded ? null :
                  <div
                    style={{
                      background: 'red',
                      height: '400px',
                      width: '400px',
                    }}
                  />
                }
                <img
                  ref={this.imageRef}
                  style={{ display: 'none' }}
                  src={this.props.src}
                />
                <div 
                  style={{
                      background: `url(${this.props.src})`
                      ,display: this.state.loaded?'none':'block'
                  }}
                />
              </div>
            );
        }
    }
类Foo扩展了React.Component{
构造函数(){
超级();
this.state={loaded:false};
this.imageRef=React.createRef();
}
componentDidMount(){
this.imageRef.current.addEventListener('load',onImageLoad);
}
onImageLoad=()=>{
this.setState({loaded:true})
}
render(){
返回(
{this.state.loaded?空:
}
);
}
}

使用对元素的引用,但使用功能组件和带有typescript的挂钩,这是相同的想法:

从“React”导入React;
导出常量缩略图=()=>{
const imgEl=React.useRef(null);
常量[loaded,setLoaded]=React.useState(false);
const onImageLoaded=()=>setLoaded(true);
React.useffect(()=>{
常数imgElCurrent=imgEl.current;
如果(当前){
imgElCurrent.addEventListener('load',onImageLoaded);
return()=>imgElCurrent.removeEventListener('load',onImageLoaded);
}
},[imgEl]);
返回(

加载。。。

); };
我的解决方案:

import React, {FC,useState,useEffect} from "react"

interface ILoadingImg {
    url:string,
    classOk?:string,
    classError?:string,
    classLoading?:string
}


const LoadingImg: FC<ILoadingImg> = ({
                                         url,
                                         classOk,
                                         classError,
                                         classLoading
                                      }) => {


    const [isLoad,setIsLoad] = useState<boolean>(false)

    const [error,setError] = useState<string|undefined>(undefined)




    useEffect(() =>{

        const image = new Image()

        image.onerror = () =>{
            setError(`error loading ${url}`)
            setIsLoad( false)
        };

        image.onload = function() {

         
                setIsLoad( true)
        

/*
//and you can get the image data


            imgData = {
                                src: this.src,
                                width:this.width,
                                height:this.height
                                }

 */


        }

        image.src = url




       return () =>  setIsLoad(false)

    },[url])



    if(!isLoad){
        return <div className={classLoading}>Loading...</div>
    }

    if(error){
        return <div className={classError}>{error}</div>
    }


    return <img  src={url} className={classOk}  />

}

export default LoadingImg




import React,{FC,useState,useffect}来自“React”
界面迭代法{
url:string,
classOk?:字符串,
类错误?:字符串,
类加载?:字符串
}
常量加载img:FC=({
网址,
classOk,
类错误,
类加载
}) => {
常量[isLoad,setIsLoad]=useState(false)
const[error,setError]=useState(未定义)
useffect(()=>{
常量图像=新图像()
image.onerror=()=>{
setError(`error loading${url}`)
setIsLoad(错误)
};
image.onload=函数(){
setIsLoad(真)
/*
//你可以得到图像数据
imgData={
src:this.src,
宽度:这个。宽度,
高度:这个高度
}
*/
}
image.src=url
return()=>setIsLoad(false)
},[url])
如果(!isLoad){
返回加载。。。
}
如果(错误){
返回{error}
}
返回
}
导出默认加载img

在更改图像时,您可以通过添加淡入过渡来更进一步。下面的代码是我的
CrossFadeImage
组件。只需复制并使用它,而不是普通的
img
组件

CrossFadeImage
有两个图像,
top
bottom
<代码>底部堆叠在
顶部
上,用于显示需要设置动画的图像,在这种情况下,切换时将淡出的旧图像

在空闲状态下,
top
显示当前图像,
bottom
是前一个图像,但透明

CrossFadeImage
在检测
props.src
更改时将执行以下操作

  • 重置两个SRC以取消任何当前正在运行的动画
  • top
    的src设置为新图像,将
    bottom
    的src设置为下一帧将淡出的当前图像
  • bottom
    设置为transparent以启动转换
从“React”导入React;
常量usePrevious=(值:T)=>{
const ref=React.useRef();
React.useffect(()=>{
参考电流=值;
},[价值];
返回参考电流;
};
import React, {FC,useState,useEffect} from "react"

interface ILoadingImg {
    url:string,
    classOk?:string,
    classError?:string,
    classLoading?:string
}


const LoadingImg: FC<ILoadingImg> = ({
                                         url,
                                         classOk,
                                         classError,
                                         classLoading
                                      }) => {


    const [isLoad,setIsLoad] = useState<boolean>(false)

    const [error,setError] = useState<string|undefined>(undefined)




    useEffect(() =>{

        const image = new Image()

        image.onerror = () =>{
            setError(`error loading ${url}`)
            setIsLoad( false)
        };

        image.onload = function() {

         
                setIsLoad( true)
        

/*
//and you can get the image data


            imgData = {
                                src: this.src,
                                width:this.width,
                                height:this.height
                                }

 */


        }

        image.src = url




       return () =>  setIsLoad(false)

    },[url])



    if(!isLoad){
        return <div className={classLoading}>Loading...</div>
    }

    if(error){
        return <div className={classError}>{error}</div>
    }


    return <img  src={url} className={classOk}  />

}

export default LoadingImg




import React from "react";

const usePrevious = <T extends any>(value: T) => {
  const ref = React.useRef<T>();
  React.useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
};
const useRequestAnimationFrame = (): [(cb: () => void) => void, Function] => {
  const handles = React.useRef<number[]>([]);
  const _raf = (cb: () => void) => {
    handles.current.push(requestAnimationFrame(cb));
  };
  const _resetRaf = () => {
    handles.current.forEach((id) => cancelAnimationFrame(id));
    handles.current = [];
  };

  return [_raf, _resetRaf];
};

type ImageProps = {
  src: string;
  alt?: string;
  transitionDuration?: number;
  curve?: string;
};

const CrossFadeImage = (props: ImageProps) => {
  const { src, alt, transitionDuration = 0.35, curve = "ease" } = props;
  const oldSrc = usePrevious(src);
  const [topSrc, setTopSrc] = React.useState<string>(src);
  const [bottomSrc, setBottomSrc] = React.useState<string>("");
  const [bottomOpacity, setBottomOpacity] = React.useState(0);
  const [display, setDisplay] = React.useState(false);
  const [raf, resetRaf] = useRequestAnimationFrame();

  React.useEffect(() => {
    if (src !== oldSrc) {
      resetRaf();
      setTopSrc("");
      setBottomSrc("");

      raf(() => {
        setTopSrc(src);
        setBottomSrc(oldSrc!);
        setBottomOpacity(99);

        raf(() => {
          setBottomOpacity(0);
        });
      });
    }
  });

  return (
    <div
      className="imgContainer"
      style={{
        position: "relative",
        height: "100%"
      }}
    >
      {topSrc && (
        <img
          style={{
            position: "absolute",
            opacity: display ? "100%" : 0,
            transition: `opacity ${transitionDuration}s ${curve}`
          }}
          onLoad={() => setDisplay(true)}
          src={topSrc}
          alt={alt}
        />
      )}
      {bottomSrc && (
        <img
          style={{
            position: "absolute",
            opacity: bottomOpacity + "%",
            transition: `opacity ${transitionDuration}s ${curve}`
          }}
          src={bottomSrc}
          alt={alt}
        />
      )}
    </div>
  );
};

export default CrossFadeImage;
<CrossFadeImage
  src={image}
  alt="phonee"
  transitionDuration={0.35}
  curve="ease-in-out"
/>
import React from 'react'
import logo from './logo.svg'
import './App.css'


export default function App() {

  function loadImage(event) {
    const file = event.target.files && event.target.files[0]
    if (file) {
      const img = document.querySelector("#image")
      img.onload = () => window.URL.revokeObjectURL(img.src) // free memory
      img.src = window.URL.createObjectURL(file)
    }
  }

  return (
    <div className="App">
      <input type="file" id="inputfile" accept=".jpg" onChange={loadImage} />
      <br/><br/>
      <img src={logo} alt="upload" id="image" width={600} />
    </div>
  )
}