从缓存数组中检索预加载的图像
Retrieve preloaded image from cached array
我在 JavaScript 中使用多个图像预加载,我正在为每个图像分配一些样式属性,这是可能的,因为这些是 HTML 个图像元素。我使用 Promise 技术,我在 Whosebug 上发现 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);
}
"srcs"的取值示例:
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');
。 我想保留我在预加载期间定义的 class 和样式属性。
这可能吗?如果是这样,我应该如何进行?
我试过 document.getElementsByClassName('myPreloadedClass')
但它 returns 是一个空结果,这意味着预加载的图像不是 DOM 的一部分(这很有意义)。
感谢您的帮助。
您将必须确保能够以某种方式检索您预加载的 img
元素。有很多方法可以做到这一点,但我马上想到了三种。
1。在 DOM
中添加加载图像
在您的示例中,您尝试使用查询选择器检索图像。这失败了,因为 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>
2。将加载的图像添加到文档片段
如果您不想将 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 中出现一次,将其附加到另一个元素会将其从其先前的父元素中删除。
3。一段可重用的代码
我建议创建闭包或 ES6 class,您可以在其中放置预加载图像和检索图像的所有功能。
来自下面代码片段的闭包 returns 两种方法:
preloadImages
需要一组图像进行预加载。
getImage
它采用有效的 CSS 选择器,用于从文档片段中检索所需的 img
元素。在返回元素之前,它将克隆它,这样您就可以多次将相同的预加载图像添加到 DOM.
克隆一个元素也会克隆它的ID,这点需要注意。我认为这不是什么大问题,因为 img
是在代码中创建的,因此您可以完全控制它。
我使用文档片段来存储预加载的图像,因为我认为这是比将图像添加到 DOM 更优雅的解决方案。这使得在不使用 getImage
方法的情况下获取 img
元素变得更加困难,从而防止预加载的 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>
我在 JavaScript 中使用多个图像预加载,我正在为每个图像分配一些样式属性,这是可能的,因为这些是 HTML 个图像元素。我使用 Promise 技术,我在 Whosebug 上发现 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);
}
"srcs"的取值示例:
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');
。 我想保留我在预加载期间定义的 class 和样式属性。
这可能吗?如果是这样,我应该如何进行?
我试过 document.getElementsByClassName('myPreloadedClass')
但它 returns 是一个空结果,这意味着预加载的图像不是 DOM 的一部分(这很有意义)。
感谢您的帮助。
您将必须确保能够以某种方式检索您预加载的 img
元素。有很多方法可以做到这一点,但我马上想到了三种。
1。在 DOM
中添加加载图像在您的示例中,您尝试使用查询选择器检索图像。这失败了,因为 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>
2。将加载的图像添加到文档片段
如果您不想将 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 中出现一次,将其附加到另一个元素会将其从其先前的父元素中删除。
3。一段可重用的代码
我建议创建闭包或 ES6 class,您可以在其中放置预加载图像和检索图像的所有功能。
来自下面代码片段的闭包 returns 两种方法:
preloadImages
需要一组图像进行预加载。getImage
它采用有效的 CSS 选择器,用于从文档片段中检索所需的img
元素。在返回元素之前,它将克隆它,这样您就可以多次将相同的预加载图像添加到 DOM.
克隆一个元素也会克隆它的ID,这点需要注意。我认为这不是什么大问题,因为 img
是在代码中创建的,因此您可以完全控制它。
我使用文档片段来存储预加载的图像,因为我认为这是比将图像添加到 DOM 更优雅的解决方案。这使得在不使用 getImage
方法的情况下获取 img
元素变得更加困难,从而防止预加载的 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>