使用 picture 标签预加载图像以防止闪烁
Preload of images to prevent flickering using the picture tag
在我的代码中有一张标签图片,我更改了它的内容以加载另一张图片。但我注意到闪烁。这是我的玩具代码。
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>
当我使用 picture 标签而不是 img 标签时,如何预加载图像?
以数据的形式构建您的 <picture>
元素。这样我们就可以构建一个函数来接收数据并逐个构建元素。
执行此操作时,我们可以检查每个 <source>
标签的 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>
在我的代码中有一张标签图片,我更改了它的内容以加载另一张图片。但我注意到闪烁。这是我的玩具代码。
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>
当我使用 picture 标签而不是 img 标签时,如何预加载图像?
以数据的形式构建您的 <picture>
元素。这样我们就可以构建一个函数来接收数据并逐个构建元素。
执行此操作时,我们可以检查每个 <source>
标签的 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>