关于javascript:react.js替换img src onerror

react.js Replace img src onerror

我有一个React组件,它是列表中的详细信息视图。

我试图用默认图像替换该图像,如果该图像不存在并且出现404错误。

我通常会在img标签中使用onerror方法,但这似乎不起作用。

我不确定如何做出反应。

这是我的组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import React from 'react';
import {Link} from 'react-router';
import ContactStore from '../stores/ContactStore'
import ContactActions from '../actions/ContactActions';

class Contact extends React.Component {
  constructor(props) {
    super(props);
    this.state = ContactStore.getState();
    this.onChange = this.onChange.bind(this);
 }

componentDidMount() {
  ContactStore.listen(this.onChange);
  ContactActions.getContact(this.props.params.id);
}

componentWillUnmount() {
  ContactStore.unlisten(this.onChange);
}

componentDidUpdate(prevProps) {
  if (prevProps.params.id !== this.props.params.id) {
    ContactActions.getContact(this.props.params.id);
  }
}

onChange(state) {
  this.setState(state);
}

render() {
  return (
   
     
       
          <h4>{this.state.contact.displayname}</h4>
          <img src={this.state.imageUrl} />
       
     
   
  );
}
}

export default Contact;


这对我来说最好

1
<img src={record.picture} onError={(e)=>{e.target.onerror = null; e.target.src="image_path_here"}}/>


您可以使用不受控制的组件:

1
2
3
<img src={this.state.img} ref={img => this.img = img} onError={
    () => this.img.src = 'img/default.img'
}>


您只需要定义onError处理程序,而不是更改状态即可,该状态将触发组件的渲染方法,最终组件将使用占位符重新渲染。

请不要将jQuery和React一起使用!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import React from 'react';
import {Link} from 'react-router';
import ContactStore from '../stores/ContactStore'
import ContactActions from '../actions/ContactActions';

class Contact extends React.Component {
  constructor(props) {
    super(props);
    this.state = ContactStore.getState();
    this.onChange = this.onChange.bind(this);
 }

componentDidMount() {
  ContactStore.listen(this.onChange);
  ContactActions.getContact(this.props.params.id);
}

componentWillUnmount() {
  ContactStore.unlisten(this.onChange);
}

componentDidUpdate(prevProps) {
  if (prevProps.params.id !== this.props.params.id) {
    ContactActions.getContact(this.props.params.id);
  }
}

onChange(state) {
  this.setState(state);
}

onError() {
  this.setState({
    imageUrl:"img/default.png"
  })
}

render() {
  return (
   
     
       
          <h4>{this.state.contact.displayname}</h4>
          <img onError={this.onError.bind(this)} src={this.state.imageUrl} />
       
     
   
  );
}

export default Contact;


由于没有完美的答案,因此我发布了我使用的代码段。我正在使用回退到fallbackSrc的可重用Image组件。

由于后备图像可能再次失败并触发重新渲染的无限循环,因此我添加了errored状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import React, { Component } from 'react';
import PropTypes from 'prop-types';

class Image extends Component {
  constructor(props) {
    super(props);

    this.state = {
      src: props.src,
      errored: false,
    };
  }

  onError = () => {
    if (!this.state.errored) {
      this.setState({
        src: this.props.fallbackSrc,
        errored: true,
      });
    }
  }

  render() {
    const { src } = this.state;
    const {
      src: _1,
      fallbackSrc: _2,
      ...props
    } = this.props;

    return (
      <img
        src={src}
        onError={this.onError}
        {...props}
      />
    );
  }
}

Image.propTypes = {
  src: PropTypes.string,
  fallbackSrc: PropTypes.string,
};


如果后备图像也失败,Arthur的答案将导致无限回调。

为了避免这种情况,请首先在构造函数中将imageLoadError的状态设置为true:

1
2
3
4
5
6
constructor(props) {
    super(props);
    this.state = {
      imageLoadError: true,
    };
}

然后在onError函数中检查此状态值,以避免无限回调,

该代码将如下所示:-

1
2
3
4
5
6
7
8
9
10
11
<img
    src={"https://if_this_url_fails_go_to_onError"}
    onError={e => {
        if(this.state.imageLoadError) {
            this.setState({
                imageLoadError: false
            });
            e.target.src = 'fallbackImage.png';
        }
    }}
/>

遇到类似的问题,我能找到的最佳解决方案是Georgii Oleinikov的答案。 (不需要像Nitesh Ranjan在回答中所建议的那样建立新的imageLoadError状态)

1
2
3
4
5
onError={(e)=>{ if (e.target.src !=="image_path_here"){
                    e.target.onerror = null;
                     e.target.src="image_path_here";}
                }
           }

不需要e.target.onerror = null(实际上并没有帮助),因为if条件足以防止无限循环(如果备用图片也无法加载)。

所以:

1
2
3
4
onError={(e)=>{ if (e.target.src !=="image_path_here"){
                 e.target.src="image_path_here";}
               }
         }

编辑:另一种方法是在返回括号外设置一个标志,并在if语句中检查该标志。代码应如下所示:

1
2
3
4
5
6
7
render(){
 let errorflag=true;
 return(
            <img alt='' src={imageUrl}
                    onError={(e)=>{ if (errorflag){ errorflag=false; e.target.src=url; } }} />
            );
}


@DepH的答案很好,但是如果您的错误源也没有加载,它的确会产生无限循环。这帮助我避免了回调循环:

1
2
onError={(e)=>{ if (e.target.src !=="image_path_here")
    { e.target.onerror = null; e.target.src="image_path_here"; } }}


我接受了@Skay的回答,并创建了一个可重用的Image组件。张贴以防万一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React, { PropTypes } from 'react';

const Image = ({src, fallbackSrc, ...other}) => {
    let element;
    const changeSrc = newSrc => {
        element.src = newSrc;
    };
    return (
        <img src={src}
             onError={() => changeSrc(fallbackSrc)}
             ref={el => element=el}
             {...other} />
    );
};

Image.propTypes = {
    src: PropTypes.string,
    fallbackSrc: PropTypes.string
};
export default Image;


1
2
3
4
5
6
7
8
9
10
11
import OriginalImage from '../../originalImg.png'
import ReplacementImage from '../../replaceImg.png'

<img
 src= OriginalImage
 alt="example"
 onError={(e) => {
    e.target.src = ReplacementImage //replacement image imported above
    e.target.style = 'padding: 8px; margin: 16px' // inline styles in html format
 }}
/>

这就是我目前正在使用的。


这是使用钩子的答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import React, { useState } from 'react'

/**
 * Returns an object that can
 * be spread onto an img tag
 * @param {String} img
 * @param {String} fallback
 * @returns {Object} { src: String, onError: Func }
*/

function useFallbackImg(img, fallback) {
  const [src, setImg] = useState(img)

  function onError(e) {
    console.log('Missing img', img, e)
    // React bails out of hook renders if the state
    // is the same as the previous state, otherwise
    // fallback erroring out would cause an infinite loop
    setImg(fallback)
  }

  return { src, onError }
}

/**
 * Usage <Image src='someUrl' fallback='fallbackUrl' alt='something' />
 */

function Image({src, fallback, ...rest}) {

  const imgProps = useFallbackImg(src, fallback)

  return <img {...imgProps} {...rest} />
}

如果要处理src道具更改,则可以传递srckey道具。
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrol-component-with-a-key

1
<Image key='someUrl' src='someUrl' fallback='fallbackUrl' alt='...' />

使用此类键可能失败的唯一极端人为边缘情况是兄弟组件。我认为,只有一个同级节点具有相同的密钥才能渲染。为了解决这个问题,您可以将Image包装在<> Fragment中。

1
2
<><Image key={srcProp} ... /></>
<><Image key={srcProp} ... /></>

对于像我这样也想更改元素样式和/或更改img源的人,只需执行以下操作:

1
2
3
4
5
6
7
8
<img
  src={'original src url goes here'}
  alt="example"
  onError={(e) => {
     e.target.src = '/example/noimage.png' // some replacement image
     e.target.style = 'padding: 8px; margin: 16px' // inline styles in html format
  }}
/>

希望能帮助到你!


如果有人将图像src与require一起使用,则onError不能用作-

1
<img src={require(`./../../assets/images/${props.imgName}.png`)} className="card-img" alt={props.name} />

然后require引发错误,在这里我尝试了多种方法,然后尝试捕获块解决方案,例如-

1
2
3
4
5
6
  let imgSrc;
  try {
    imgSrc = require(`./../../assets/images/${props.imgName}.png`);  
  } catch {
    imgSrc = require(`./../../assets/images/default.png`);
  }

并用作

1
<img src={imgSrc} className="card-img" alt={props.name} />

如果可以的话,可以使用object。像下面这样的东西会很好地工作

1
2
3
<object data={expected_image} type="image/jpg">
  <img src={DEFAULT} alt="404" />
</object>

查看此答案以获取更多详细信息
https://stackoverflow.com/a/29111371/1334182


那就是我做到的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 class Pix extends React.Component{

          constructor(props){
            super(props);
           this.state={link: this.props.link};
           this.onError=this.onError.bind(this);
          }


          onError(){
              console.log("error: could not find picture");
              this.setState(function(){ return {link:"missing.png"}; });
             };

          render(){
          return <img onError={this.onError} src={this.state.link}/>;
          }
    }

我这样写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import React, { useState } from 'react';
import NoImageSVG from './noImage.svg';

const ImgWithFallback: React.FunctionComponent<{ src: string; alt: string; className: string }> = ({
  src,
  alt,
  className,
}) => {
  const [isUndefined, updateIsUndefined] = useState(false);

  const onError = () => {
    updateIsUndefined(true);
  };

  if (isUndefined) {
    return (
     
        <NoImageSVG width='5rem' height='5rem' />
     
    );
  }

  return <img src={src} alt={alt} className={className} onError={onError} />;
};

export default React.memo(ImgWithFallback, () => true);

这对我有用。

1
2
3
{<img className="images"
    src={`/images/${student.src ? student.src :"noimage.png" }`} alt=  
{student.firstname} />}

学生是我的数组的名称,当没有图像显示时,noimage是图像。