同构/通用反应中的图像onLoad事件 - 加载图像后注册事件

Eve*_*tss 18 javascript reactjs isomorphic-javascript

在同构呈现的页面图像可以在主script.js文件之前下载.因此,可以在react注册onLoad事件之前加载图像- 从不触发此事件.

script.js

constructor(props) {
    super(props);
    this.handleImageLoaded = this.handleImageLoaded.bind(this);
}

handleImageLoaded() {
    console.log('image loaded');
} 

render() {
    return (
        <img src='image.jpg' onLoad={this.handleImageLoaded} />
    );
}
Run Code Online (Sandbox Code Playgroud)

场景1 - image.jpg大于script.js

image.jpg比script.js大

在这种情况下一切正常.在最终加载图像之前注册事件,因此在控制台中是image loaded消息.


场景2 - image.jpg小于script.js

image.jpg小于script.js

在这种情况下,您可以看到帖子开头描述的问题.onLoad事件未触发.


为了onLoad方案2中触发事件,我该怎么办?


编辑:Soviut答案实施

要检测渲染时图像是否准备好,您应该检查complete纯javascript img对象上的属性:

constructor(props) {
    super(props);
    this.state = { loaded: false };
    this.handleImageLoaded = this.handleImageLoaded.bind(this);
    this.image = React.createRef();
}

componentDidMount() {
    const img = this.image.current;
    if (img && img.complete) {
        this.handleImageLoaded();
    }
}

handleImageLoaded() {
    if (!this.state.loaded) {
        console.log('image loaded');
        this.setState({ loaded: true });
    }
} 

render() {
    return (
        <img src='image.jpg' ref={this.image} onLoad={this.handleImageLoaded} />
    );
}
Run Code Online (Sandbox Code Playgroud)

Sov*_*iut 13

您可以complete在应用onload事件之前检查图像上的属性.

if (!img.complete) {
    // add onload listener here
}
Run Code Online (Sandbox Code Playgroud)


Ida*_*lan 11

另一种方法是使用 ref 并涵盖这两种情况:

<img
  ref={(input) => {
    // onLoad replacement for SSR
    if (!input) { return; }
    const img = input;

    const updateFunc = () => {
      this.setState({ loaded: true });
    };
    img.onload = updateFunc;
    if (img.complete) {
      updateFunc();
    }
  }}
  src={imgSrc}
  alt={imgAlt}
/>
Run Code Online (Sandbox Code Playgroud)


cor*_*ard 9

使用 Hooks 这一切都变得更整洁了:


const useImageLoaded = () => {
  const [loaded, setLoaded] = useState(false)
  const ref = useRef()

  const onLoad = () => {
    setLoaded(true)
  }

  useEffect(() => {
    if (ref.current && ref.current.complete) {
      onLoad()
    }
  })

  return [ref, loaded, onLoad]
}

const SomeComponent = ({ src }) => {
  const [ref, loaded, onLoad] = useImageLoaded()

  return (
    <div>
      <img ref={ref} onLoad={onLoad} src={src} alt="" />
      {loaded && <h1>Loaded!</h1>}
    </div>
  )
}
Run Code Online (Sandbox Code Playgroud)


小智 6

即使 src 加载失败,img.complete 也是 true。

complete - 返回一个布尔值,如果浏览器已完成获取图像,无论成功与否。如果图像没有 src 值,它也会显示为真。

  1. 使用 naturalWidth 作为 img 加载成功与否的决定因素
    state = {
        isLoading: true,
        hasError: false,
    }

    myRef = React.createRef();

    componentDidMount() {
        const img = this.myRef.current;

        if (img && img.complete) {
            if (img.naturalWidth === 0) {
                this.handleOnError();
            } else {
                this.handleImageLoaded();
            }
        }
    }

    handleImageLoaded = () => {
        if (this.state.isLoading) {
            this.setState({ isLoading: false });
        }
    }

    handleOnError = () => {
        this.setState({ hasError: true });
    }

    render() {
        return (
            <img
                src={src}
                alt={alt}
                ref={this.myRef}
                onError={this.handleOnError}
                onLoad={this.handleOnLoad}
            />
        );
    }
Run Code Online (Sandbox Code Playgroud)
  1. 另一种方法是在 componentDidMount 中添加“检查”图像,并为其设置一个事件处理程序,并让检查图像成为处理 eventListeners 的图像
componentDidMount() {
   const testImg = new Image();
   testImg.onerror = this.handleOnError;
   testImg.onload = this.handleImageLoaded;
   testImg.src = this.props.src; // important to set eventlisteners before src
}

Run Code Online (Sandbox Code Playgroud)