使用JavaScript(React、Jquery)应用程序预加载图像,但图像会加载两次。

3
  • 请查看下面的EDIT 3,因为我发现这不是React的问题,而是浏览器缓存机制的问题。

我正在尝试创建一个应用程序,从给定的图像URL数组中创建一些简单的轮播图。我编写了一个模块,帮助我在所有图像加载完成后调用回调函数,它看起来像这样:

ImagesLoader.js

export default {
    // a module that loads an array of images urls and when completes
    // calls a callback with the images elements array

    load(imagesUrlsArray, callback){
        const imagesLoaded = [];
        imagesUrlsArray.map((url) => {
            const img = new Image();
            img.onload = () => {
                imagesLoaded.push(img);
                if(imagesUrlsArray.length === imagesLoaded.length){
                    callback(imagesLoaded);
                }
            };
            img.src = url;
        });
    }
}

我知道可以使用Promise并在所有url加载完成后解决,目前不进行错误检查。
这是我的组件更新状态的位置,其中包含从上面模块中检索到的图像:
componentDidMount() {
    ImagesLoader.load(this.props.images, (loadedImages) => {
        const imagesStateData = this.calculateImagesStateData(loadedImages);
        this.setState(Object.assign({},
            imagesStateData,
            {
                loaded: true,
                loadedImages: loadedImages
            }
        ));
    });
}

每当我点击下一个或上一个按钮(请参见下面的截图),每次图片重新加载,我不明白为什么会这样。
这是我第一次使用Reactjs进行此类操作,使用jQuery没有问题。

Network tab on chrome

这是我传递图片URL的方法:

export default class App extends Component {
  render() {

    var images = [
      "http://www.wallpapereast.com/static/images/excellent-love-quotes-wallpaper-hd.jpg",
      "http://www.wallpapereast.com/static/images/My-Samsung-Galaxy-S3-Wallpaper-HD-Landscapes1.jpg",
      "https://s-media-cache-ak0.pinimg.com/236x/58/01/02/5801020fea36221ffba33633f99a7d81.jpg",
      "http://www.wallpapereast.com/static/images/pier_1080.jpg",
      "http://www.wallpapereast.com/static/images/wallpaper-black-hd-hd-wallpapers.jpg",
      "http://1.bp.blogspot.com/-dvg12YJKaKg/UnVfkMke7jI/AAAAAAAAUaU/O86x5FMgEuk/s1600/longcat.gif"
    ];

    var settings = {
      autoPlay: true,
      arrows: true
    };

    return (
      <Layout>
        <ReactCarousel images={images} width={500} height={300} settings={settings}/>
      </Layout>
    );
  }
}

编辑: 我成功提供了一个简短的例子。 http://codepen.io/anon/pen/ObyRPX 通过构建这个例子,我发现如果我不使用ImageItem组件,而是渲染一个简单的<img src='image.src'/>元素,它能够正常工作,所以我想我的问题可能出在ImageItem组件上。

编辑2: 这很奇怪http://codepen.io/anon/pen/eBpdjx,在这里我只是改变了ImageItem,让它呈现图像元素而不是背景图像在一个div上,它按预期工作。有人能解释一下区别吗?

编辑3:

显然,这不仅发生在React应用程序上,也发生在jQuery应用程序上,请看这里:

http://codepen.io/anon/pen/VmvyPZ

当我尝试将图像作为CSS的background-image属性加载时,浏览器不会缓存该图像并且会加载两次。

好的,我成功地给出了一个简短的例子。http://codepen.io/anon/pen/ObyRPX,从构建这个示例中我所看到的是,如果我不使用ImageItem组件,而是渲染一个简单的<img src='image.src'/>元素,它的效果很好,因此我想我的问题可能出在ImageItem组件上。你能帮我找出问题所在吗?编辑了我的问题。 - Dima Gimburg
1
进行一个小测试:ImagesLoader 直接在您的滑块包装器中加载图像(通常在此处执行 ImageItem)。所以计划是:启用加载程序,然后直接在您的滑块 <ul> 列表中加载图像,然后隐藏加载程序。我快速测试了一下,它可以工作(但我使用了您的提示来加载图像,而不是像您喜欢的那样使用 background: url(...),而是使用 <img src="img.jpg/>)。正如您稍后在网络选项卡(检查器)中看到的那样,您只会看到来自 "react.min.js" 的初始化器的图像。我不确定,但我认为 react 会像 jquery 预加载图像的常规方式一样做些其他事情。 - pleinx
好的,这很奇怪 http://codepen.io/anon/pen/eBpdjx 在这里我只是将其更改为图像元素而不是背景图像,它按预期工作。有人能解释一下其中的区别吗? - Dima Gimburg
你搞定了吗? - alexunder
最终我使用了<img src="..." />,但无法使其与背景图片一起工作。 - Dima Gimburg
显示剩余2条评论
2个回答

2
我遇到了完全相同的问题。图片会再次加载,因为浏览器没有保留您加载的图片的引用。
我所做的就是创建一个全局数组,并将所有图片推送到该数组中。
现在,这个数组是全局的,浏览器必须维护该数组,直到整个应用程序被销毁。"最初的回答"
var allImages = [];

function loadImages(imageUrls) {
imageUrls.forEach((q) => {
    const img = new Image();
    img.src = q;
    allImages.push(img);
});}

之后,即使离线,我也能在其他页面上加载图片。

最初的回答:After this, I was able to load the images on other pages, even when offline.


1
这个回答没有点赞和评论,但它确实拯救了我的生命,哈哈。 - aks.

0

Chrome在devtool中为一张图片显示了2个图像请求。尝试在network选项卡中取消选中disable cache选项。

Disable cache


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接