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以取消任何当前正在运行的动画
- 将
的src设置为新图像,将top
的src设置为下一帧将淡出的当前图像bottom
- 将
设置为transparent以启动转换bottom
从“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>
)
}