我使用JavaScript进行多个图像预加载,并且我为每个图像预分配了一些样式属性,这是可能的,因为它们是HTML图像元素。我使用Promise技术,我在StackOverflow上找到了here:
function preloadImages(srcs) {
function loadImage(imgToLoad) {
return new Promise(function(resolve, reject) {
var img = new Image();
img.onload = function() {
resolve(img);
};
img.onerror = img.onabort = function() {
reject(imgToLoad.src);
};
img.className = 'testimg'; //Test to see if I can retrieve img
img.src = imgToLoad.src;
img.style.top = imgToLoad.top;
});
}
var promises = [];
for (var i = 0; i < srcs.length; i++) {
promises.push(loadImage(srcs[i]));
}
return Promise.all(promises);
}
&#34; srcs&#34;的价值示例:
srcs[0].top = '15%';
srcs[0].src = 'img/myImage1.jpg';
srcs[1].top = '24%';
srcs[1].src = 'img/myImage2.jpg';
预加载部分工作正常,并且我可以在流程结束时获得所有预加载的图像,看到已应用样式属性,如下所示:
preloadImages(imgToLoad).then(function(imgs) {
// all images are loaded now and in the array imgs
console.log(imgs); // This works
console.log(document.getElementsByClassName('testimg')); //This doesn't
}, function(errImg) {
// at least one image failed to load
console.log('error in loading images.');
});
但是,稍后在我的代码中,我想从预加载图像数组中获取一些元素,因此我可以在不必精确设置样式属性的情况下附加它们。
由此,我的意思不仅仅是.append('aSrcThatHasBeenPreloaded');
。 我想保留我在预加载期间定义的类和样式属性。
这甚至可能吗?如果是这样,我该怎么办?
我尝试document.getElementsByClassName('myPreloadedClass')
但它返回一个空结果,这意味着预加载的图像不是DOM的一部分(这很有道理)。
感谢您的帮助。
答案 0 :(得分:1)
您必须确保以某种方式检索已预加载的img
元素。有很多方法可以做到这一点,但有三种方法可以立即浮现在脑海中。
在您的示例中,您尝试使用查询选择器检索图像。这会失败,因为img
元素未添加到DOM。您可以将它们附加到对用户隐藏的DOM元素。
var
images = [
{
src: '//placehold.it/550x250?text=A',
top: 0,
class:'img-a' // unique class name to retrieve item using a query selector.
},
{
src: '//placehold.it/550x250?text=B',
top: 0,
class:'img-b'
}],
imageCache = document.getElementById('image-cache');
function preloadImages(srcs) {
function loadImage(imgToLoad) {
return new Promise(function(resolve, reject) {
var img = new Image();
img.onload = function() {
// The image has been loaded, add it to the cache element.
imageCache.appendChild(img);
resolve(img);
};
img.onerror = img.onabort = function() {
reject(imgToLoad.src);
};
img.className = 'testimg ' + imgToLoad.class; //Test to see if I can retrieve img
img.src = imgToLoad.src;
img.style.top = imgToLoad.top;
});
}
var promises = [];
for (var i = 0; i < srcs.length; i++) {
promises.push(loadImage(srcs[i]));
}
return Promise.all(promises);
}
// Load all the images.
preloadImages(images)
.then(result => {
// Add img B from the cache to the proof div.
document.getElementById('proof').appendChild(imageCache.querySelector('.img-b'));
});
.hidden {
display: none;
}
<div id="image-cache" class="hidden"></div>
<div id="proof"></div>
如果您不想将img
添加到DOM,可以将它们添加到document fragment。这样,网站的访问者将无法轻松访问它们,您仍然可以使用查询选择器来检索图像。
var
images = [
{
src: '//placehold.it/550x250?text=A',
top: 0,
class:'img-a' // unique class name to retrieve item using a query selector.
},
{
src: '//placehold.it/550x250?text=B',
top: 0,
class:'img-b'
}],
// Create a document fragment to keep the images in.
imageCache = document.createDocumentFragment();;
function preloadImages(srcs) {
function loadImage(imgToLoad) {
return new Promise(function(resolve, reject) {
var img = new Image();
img.onload = function() {
// The image has been loaded, add it to the cache element.
imageCache.appendChild(img);
resolve(img);
};
img.onerror = img.onabort = function() {
reject(imgToLoad.src);
};
img.className = 'testimg ' + imgToLoad.class; //Test to see if I can retrieve img
img.src = imgToLoad.src;
img.style.top = imgToLoad.top;
});
}
var promises = [];
for (var i = 0; i < srcs.length; i++) {
promises.push(loadImage(srcs[i]));
}
return Promise.all(promises);
}
// Load all the images.
preloadImages(images)
.then(result => {
// Add img B from the cache to the proof div.
document.getElementById('proof').appendChild(imageCache.querySelector('.img-b'));
// And try to add img B from the cache to the proof2 div. The image will only be visible once in the site.
document.getElementById('proof2').appendChild(imageCache.querySelector('.img-b'));
});
.hidden {
display: none;
}
<div id="proof"></div>
<div id="proof2" style="margin-top:1em"></div>
第二种解决方案与第一种解决方案非常相似。您仍然可以使用查询选择器来访问图像。但是,两种解决方案都有相同的缺点,一旦您从站点上的任何其他位置放置图像,您就无法再从缓存中检索图像。这是因为一个元素只能在DOM中一次,并且将它附加到另一个元素会将其从前一个父元素中删除。
我建议创建一个闭包或ES6类,您可以在其中放置预加载图像和检索图像的所有功能。
以下代码段中的闭包会返回两种方法:
preloadImages
,它会将一系列图像预加载。getImage
,它采用有效的CSS选择器,用于从文档片段中检索所需的img
元素。在返回元素之前,它将克隆它,以便您可以多次向DOM添加相同的预加载图像。 克隆一个元素也会克隆它的ID,这是值得注意的。我认为这不是一个问题,因为img
是在代码中创建的,所以你可以完全控制它。
我使用文档片段来存储预加载的图像,因为我认为它比将图像添加到DOM更优雅。这使得在不使用img
方法的情况下获取getImage
元素变得更加困难,从而防止预先加载的img
元素以某种方式从图像缓存中删除。
var
images = [
{
src: '//placehold.it/550x250?text=A',
top: 0,
class:'img-a' // unique class name to retrieve item using a query selector.
},
{
src: '//placehold.it/550x250?text=B',
top: 0,
class:'img-b'
}];
var imagesPreloader = (function() {
var imagesCache = document.createDocumentFragment();
function loadImage(imgToLoad) {
return new Promise(function(resolve, reject) {
var img = new Image();
img.onload = function() {
imagesCache.appendChild(img)
resolve();
};
img.onerror = img.onabort = function() {
reject(imgToLoad.src);
};
img.className = 'testimg ' + imgToLoad.class ; //Test to see if I can retrieve img
img.src = imgToLoad.src;
img.style.top = imgToLoad.top;
});
}
function preloadImages(srcs) {
var promises = [];
for (var i = 0; i < srcs.length; i++) {
promises.push(loadImage(srcs[i]));
}
return Promise.all(promises);
}
function getImage(imageSelector) {
const
// Find the image in the fragment
imgElement = imagesCache.querySelector(imageSelector);
// When the selector didn't yield an image, return null.
if (imgElement === null) {
return null;
}
// Clone the image element and return it.
const
resultElement = imgElement.cloneNode();
return resultElement;
}
return {
getImage,
preloadImages
};
})();
imagesPreloader.preloadImages(images)
.then(result => {
console.log('Image with class "img-a": ', imagesPreloader.getImage('.img-a'));
document.querySelector('#proof').appendChild(imagesPreloader.getImage('.img-b'));
document.querySelector('#proof2').appendChild(imagesPreloader.getImage('.img-b'));
});
<div id="proof"></div>
<div id="proof2" style="margin-top:1em"></div>