预加载背景图像

2024-04-24

我正在构建一个循环显示 3 个不同背景的页面,每 750 毫秒更改一次。为此,我在主体中添加了一个带有相关背景图像的类,并使用 JS 进行了更改。对于第一次循环,它们会闪烁,因为图像必须加载,所以它不会立即出现。因此,我可以使用任何方法来预加载图像吗?

CSS:

&.backgrounds{
    background-position: center bottom;
    background-repeat: no-repeat;
    background-size: 130%;

    &.freddy{
        background-image: url(/img/illustrations/snapchat/snapchat_holding_page_freddy.jpg);
    }

    &.irene{
        background-image: url(/img/illustrations/snapchat/snapchat_holding_page_irene.jpg);
    }

    &.joe{
        background-image: url(/img/illustrations/snapchat/snapchat_holding_page_joe.jpg);
    }
}

JS:

setInterval(function() {
    if ( $('.backgrounds').hasClass('freddy') ){
        $('.backgrounds').removeClass('freddy').addClass('irene');

    } else if ( $('.backgrounds').hasClass('irene') ){
        $('.backgrounds').removeClass('irene').addClass('joe');

    } else if ( $('.backgrounds').hasClass('joe') ){
        $('.backgrounds').removeClass('joe').addClass('freddy');

    }
}, 750);

我会做这样的事情。loadImages返回一个 Promise,一旦所有图像加载完毕,该 Promise 就会解析。这.then附加到它调用cycleImages,这将启动间隔。因为无论如何你都需要 JS 中的 URL 来进行预加载,所以我直接操作background-image,这样您就可以从 CSS 中删除图像 URL 并节省一些冗余字节。这也使得将来扩展图像列表变得更容易,您只需要向图像数组中添加一个项目,而不是维护复杂的 if 语句。

function loadImages (images) {
  // each image will be loaded by this function.
  // it returns a Promise that will resolve once
  // the image has finished loading
  let loader = function (src) {
    return new Promise(function (resolve, reject) {
      let img = new Image();
      img.onload = function () {
        // resolve the promise with our url so it is
        // returned in the result of Promise.all
        resolve(src);
      };
      img.onerror = function (err) {
        reject(err);
      };
      img.src = src;
    });
  };

  // create an image loader for each url
  let loaders = [];
  images.forEach(function (image) {
    loaders.push(loader(image));
  });

  // Promise.all will return a promise that will resolve once all of of our
  // image loader promises resolve
  return Promise.all(loaders);
}


// the images we are going to display
let myImages = [
  'http://www.gifpng.com/400x200',
  'http://www.gifpng.com/400x200/ffffff/000000',
  'http://www.gifpng.com/400x200/000000/ffffff'
];

// $(document).ready(fn) is deprecated,
// use the $(fn) form instead
$(function() {

  // after the images are loaded this will be called with an array of the loaded images
  function cycleImages (images) {
    let index = 0;
    setInterval(function() {
      // since we need an array of the image names to preload them anyway,
      // just load them via JS instead of class switching so you can cut them
      // out of the CSS and save some space by not being redundant
      $('#backgrounds').css('backgroundImage', 'url("' + images[index] + '")');
      // increment, roll over to 0 if at length after increment
      index = (index + 1) % images.length;
    }, 750);
  }


  // load the images and start cycling through them after they are loaded
  loadImages(myImages).then(cycleImages).catch(function (err) {
    console.error(err);
  });
});
#backgrounds {
  height: 200px;
  width: 400px;
  border: 1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="backgrounds"></div>

Edit: Taking 只是一个学生 https://stackoverflow.com/users/962603/just-a-student考虑到 的评论,这里的版本只会在加载后切换图像,但如果加载则立即执行此操作。它还会跳过无法加载的图像。自从cycleImages不再通过调用.then,我还对其进行了更改,以便它接受目标元素(作为 jQuery 对象)以及图像承诺数组。这样,如果您愿意,您可以轻松地在页面上具有不同图像集的多个位置使用它。

function loadImages (images) {
  // each image will be loaded by this function.
  // it returns a Promise that will resolve once
  // the image has finished loading
  let loader = function (src) {
    return new Promise(function (resolve, reject) {
      let img = new Image();
      img.onload = function () {
        // resolve the promise with our url
        resolve(src);
      };
      img.onerror = function (err) {
        reject(err);
      };
      img.src = src;
    });
  };

  // return an array of image-loading promises
  return images.map(function (image) {
    return loader(image);
  });
}


// the images we are going to display
let myImages = [
  'http://www.gifpng.com/400x200',
  'http://www.invalid-domain-name.foo/this-url-certainly-does-not-exist.jpg',
  'http://www.gifpng.com/400x200/ffffff/000000',
  'http://www.gifpng.com/400x200/000000/ffffff'
];

// $(document).ready(fn) is deprecated,
// use the $(fn) form instead
$(function() {

  // this receives an array of the promises for each image
  function cycleImages ($target, images) {
    let index = 0,
      interval = 750; // how many ms to wait before attempting to switch images

    function nextImage () {
      // p is the promise for the current image
      let p = images[index],
        next = function (wait) {
          // increment our counter and wait to display the next one
          index = (index + 1) % images.length;
          setTimeout(nextImage, wait);
        };

      // wait for this image to load or fail to load
      p.then(function (src) {
        // it loaded, display it
        $target.css('backgroundImage', 'url("' + src + '")');
        next(interval);
      }).catch(function (err) {
        // this one failed to load, skip it
        next(0);
      });

    }

    // start cycling
    nextImage();
  }


  // load the images and start cycling through them as they are loaded
  cycleImages($('#backgrounds'), loadImages(myImages));
});
#backgrounds {
  height: 200px;
  width: 400px;
  border: 1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="backgrounds"></div>

您也可以将其作为参数传递,而不是对图像更改之间的间隔进行硬编码。但到那时,我将重构它以使用配置对象来传递除图像承诺数组之外的所有内容:cycleImages(myImages, {target: $('#backgrounds'), interval: 1000});

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

预加载背景图像 的相关文章