【问题标题】:Preload of images to prevent flickering using the picture tag使用图片标签预加载图像以防止闪烁
【发布时间】:2021-05-25 00:38:55
【问题描述】:

在我的代码中,我有一张标签图片,我更改了它的内容以加载其他图片。但我注意到闪烁。这是我的玩具代码。

setTimeout(replaceImage,3000);

function replaceImage(){
let pictureNode = document.getElementById('picture-carousel');

let markup = `
               <source media="(min-width:50em)" srcset="http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/debris2_blue.png">
                
                  <source media="(min-width:25em)" srcset="http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/debris2_brown.png"> 
                  <source  srcset="http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/debris3_blue.png"> 
                  <img src='http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/debris2_blue.png' title='Bla bla' alt='bla bla'>
`

pictureNode.innerHTML = markup;
}
<div>
<picture id='picture-carousel'>
                  <source media="(min-width:50em)" srcset="http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/asteroid_blend.png">
                
                  <source media="(min-width:25em)" srcset="http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/asteroid_blue.png"> 
                  <source  srcset="http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/asteroid_brown.png"> 
                  <img src='http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/asteroid_blend.png' title='Bla bla' alt='bla bla'> <!--  fallback -->
               </picture>
               </div>

我知道要为图像添加闪烁,我可以像这样预加载图像:

function loadImage(){
var img = new Image(),
x=document.getElementById('myImg');
img.onload=function(){
  x.src = img.src;
}

img.src ='http://codeskulptor-demos.commondatastorage.googleapis.com/GalaxyInvaders/back03.jpg'; //  this is the new url img to load';
}
<img src='http://codeskulptor-demos.commondatastorage.googleapis.com/GalaxyInvaders/back02.jpg' id='myImg'>

<button onclick='loadImage();'>Load new Image</button>

当我使用图片标签而不是 img 标签时如何预加载图片?

【问题讨论】:

    标签: javascript html image responsive-design preload


    【解决方案1】:

    以数据的形式构造您的&lt;picture&gt; 元素。这样我们就可以构建一个函数来接收数据并逐步构建元素。

    执行此操作时,我们可以检查每个 &lt;source&gt; 标记的 media 值。使用该值,我们可以运行window.matchMedia() 来确定元素上的媒体查询是否与当前视图匹配。例如,您可以检查min-width: 50em 当前是否为真。

    有了这些知识,您就可以确定要预加载的图像。您只需加载与媒体查询匹配的图像。

    查看下面的示例,它执行上述过程。 如果您有任何问题,请与我们联系。

    const pictureData = [
      {
        tag: 'source',
        attributes: {
          media: '(min-width: 50em)',
          srcset: 'http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/debris2_blue.png'
        }
      },
      {
        tag: 'source',
        attributes: {
          media: '(min-width: 25em)',
          srcset: 'http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/debris2_brown.png'
        }
      },
      {
        tag: 'source',
        attributes: {
          srcset: 'http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/debris3_blue.png'
        }
      },
      {
        tag: 'img',
        attributes: {
          src: 'http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/debris2_blue.png',
          title: 'Bla bla',
          alt: 'bla bla'
        }
      }
    ];
    
    /**
     * Loads an image and returns a promise.
     * The promise will resolve on the load event of the image.
     */
    const preloadImage = url => new Promise((resolve, reject) => {
      const image = new Image();
      image.onload = () => resolve();
      image.onerror = error => reject(error);
      image.src = url;
    })
    
    /**
     * Takes in an object of pictureData.
     * It then creates a <picture> element and the children specified in the object.
     * Whenever a tag is source, it will use the media value, if present,
     * to detect if the image is elligable to be loaded. 
     * If so it will preload the image and resolve the promise after it has been loaded.
     */
    const buildPicture = async pictureData => {
      const picture = document.createElement('picture');
      let imageToPreload = null;
    
      // Loop through all the data and start constructing.
      for (const { tag, attributes } of pictureData) {
        const child = document.createElement(tag);
        
        if (imageToPreload === null) {
          // Check source tags for media queries.
          if (tag === 'source') {
            const { media, srcset } = attributes;
            
            // If there is a media query, check it.
            if (!media) {
              const { matches } = window.matchMedia(media);
    
              // If the query matches, use this as the image.
              if (matches === true) {
                imageToPreload = srcset;
              }
    
            // No media query found.
            } else {
              imageToPreload = srcset;
            }
          }
    
          // If no match has been found yet, just load the image.
          if (tag === 'img') {
            const { src } = attributes;
            imageToPreload = src;
          }
        }
        
        // Set all the properties and values of the attributes.
        for (const [ property, value ] of Object.entries(attributes)) {
          child.setAttribute(property, value);
        }
    
        picture.append(child);
      }
    
      if (imageToPreload !== null) {
        try {
          await preloadImage(imageToPreload);
        } catch (error) {
          console.error(error);
        }
      }
    
      return picture;
    };
    
    setTimeout(async () => {
      const currentPicture = document.getElementById('picture-carousel');
      const picture = await buildPicture(pictureData);
      currentPicture.replaceWith(picture);
    }, 2000);
    <picture id='picture-carousel'>
      <source media="(min-width:50em)" srcset="http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/asteroid_blend.png">
      <source media="(min-width:25em)" srcset="http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/asteroid_blue.png">
      <source srcset="http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/asteroid_brown.png">
      <img src='http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/asteroid_blend.png' title='Bla bla' alt='bla bla'>
      <!--  fallback -->
    </picture>

    【讨论】:

    • 这种方式,因为您使用javascript检查使用图片标签触发的媒体查询变得无用,我只能直接使用img标签
    • 当然,您可以仅使用 JavaScript 来完成。但是当屏幕尺寸发生变化时,您将失去更改图像的能力。
    • 是的,或者我应该对每个媒体查询大小的更改事件都有一个监听器
    猜你喜欢
    • 1970-01-01
    • 2014-01-10
    • 1970-01-01
    • 2019-04-08
    • 1970-01-01
    • 2019-09-28
    • 1970-01-01
    • 1970-01-01
    • 2014-09-15
    相关资源
    最近更新 更多