PreloadJS 加载图像,但我无法将其插入 DOM

PreloadJS loaded image, but I cannot insert it to DOM

我正在尝试使用 PreloadJS 预加载一张图片,然后将其插入到 DOM a 两次。但我只能插入一张图片。

var queue = new createjs.LoadQueue();
queue.addEventListener('complete', onComplete);
queue.loadManifest([{
  id: 'img',
  type: 'image',
  src: 'https://i.imgur.com/adSrF00g.png',
}, ]);
queue.load();

function onComplete(event) {
  var img = queue.getResult('img');
  var imgSrc = img.src;

  // this code inserts image to the DOM but 404 not found error appears in console
  document.getElementById('game').innerHTML = `<img src="${imgSrc}" />`;

  // this code do the same thing and 404 also appears
  var DOM_img = document.createElement("img");
  DOM_img.src = imgSrc;
  document.getElementById('game').appendChild(DOM_img);

  // this code insert the image to the DOM succesfully
  document.getElementById('game').appendChild(img);

  // but the last line does nothing - the img tag does not appear in the DOM and nothing error in the console
  document.getElementById('game').appendChild(img);
}
<script src="https://code.createjs.com/1.0.0/preloadjs.min.js"></script>
<div id="game"></div>

截图:https://i.imgur.com/VQwAABM.jpg

我不明白为什么只出现一张图片。我做错了什么?我怎样才能插入图像 a 两次?谢谢!

这很容易修复,但首先我想向您解释一下。

什么是Blob URLsObject-URLs Blob URL/Object URL 是允许 Blob 和 File 对象用作 URL 的伪协议图片、二进制数据的下载链接等内容的来源。

在您的情况下,如果您尝试打开这个 src="blob:https://yada.yada" blob url,它是已加载图像的 src,它会给您一个错误并且无法打开。

是的,我知道 Teo,但是为什么要使用 src 标签怎么可能呢?

嗯,Blob URLs只能由浏览器内部生成。因此,这些元素具有对 Blob 或 File 对象的特殊引用。这些 URL 只能在浏览器的单个实例和同一会话中本地使用(即 page/document 的生命周期)。

所以在这种情况下,src="blob:https://yada.yada" 链接到 LoadQueue 对象创建的 img 标签。

那么,如何在多个元素中使用同一张图片?

In the LoadQueue docummentation我们可以使用getResult()方法得到一个Blob对象。因此,为了重用 Blob URL 我们可以 "clone" Blob 对象。根据文档,getResult (value, [rawResult=false]) 方法被覆盖以接收此 rawResult 可选参数。如果此参数是 true,该方法将 returns 作为 Blob 对象 的原始结果,而不是格式化结果.如果没有原始结果,将返回格式化结果。

好的,但是如何在 <img> 元素中使用这个 blob?

嗯,我们可以使用URL.createObjectURL()方法。此方法创建一个包含新 Blob URL 的 DOMString,表示 Blob 对象参数中给定。

正如我上面所解释的,这个 Blob URL 生命周期与 window 中的文档相关联它是在其上创建的。

实现如下:

let queue = new createjs.LoadQueue();
queue.addEventListener('complete', onComplete);
queue.loadManifest([{
  id: 'sprite',
  type: 'image',
  src: 'https://i.imgur.com/ciIyRtu.jpg?1',
}, ]);
queue.load();

function onComplete(event) {
  // Get Blob object instead of a formatted result
  let blob = queue.getResult('sprite', true);

  // Create a Blob URL using the Blob object 
  let urls = [
    URL.createObjectURL(blob),
    URL.createObjectURL(blob),
    URL.createObjectURL(blob),
  ];

  // Create a new <img> element and assign a Blob URL
  urls.forEach(function(item, index, array) {
    let DOM_img = document.createElement('img');
    DOM_img.src = item;
    document.getElementById('game').appendChild(DOM_img);
  });
}
<script src="https://code.createjs.com/1.0.0/preloadjs.min.js"></script>
<div id="game"></div>

替代解决方案(不推荐用于大文件)

您还可以使用 loadManifest() 以不同的 ID 多次加载相同的图像。然后我们定义一个 fileload 事件而不是 complete 事件来捕获每个加载的元素,检查这个例子:

let queue = new createjs.LoadQueue();
queue.addEventListener('fileload', onFileLoad);
queue.loadManifest([{
  id: 'sprite1',
  type: 'image',
  src: 'https://i.imgur.com/ciIyRtu.jpg?1',
}, {
  id: 'sprite2',
  type: 'image',
  src: 'https://i.imgur.com/ciIyRtu.jpg?1',
}, {
  id: 'sprite3',
  type: 'image',
  src: 'https://i.imgur.com/ciIyRtu.jpg?1',
}, ]);

function onFileLoad(event) {
  // Get the image element after is successfully loaded
  let img = event.result;

  // This code insert the image to the DOM succesfully
  document.getElementById('game').appendChild(img);
}
<script src="https://code.createjs.com/1.0.0/preloadjs.min.js"></script>
<div id="game"></div>

刚刚找到另一个解决方案,加载图像一次,然后将其插入 dom a 两次。

var queue = new createjs.LoadQueue();
queue.addEventListener('complete', onComplete);
queue.loadManifest([{
  id: 'img',
  type: 'image',
  src: 'https://i.imgur.com/adSrF00g.png',
}, ]);
queue.load();

function onComplete(event) {
    // get loading results as blob (second argument is set to true)
    var blob = queue.getResult('img', true);
    
    // create two blob urls from one blob image source
    var blobUrl = URL.createObjectURL(blob);
    var blobUrl2 = URL.createObjectURL(blob);
    
    // create new IMG tag and set src as first blob url
    var DOM_img = document.createElement("img");
    DOM_img.src = blobUrl;
    document.getElementById('game').appendChild(DOM_img);

    // create new IMG tag and set src as second blob url
    var DOM_img2 = document.createElement("img");
    DOM_img2.src = blobUrl2;
    document.getElementById('game').appendChild(DOM_img2);
}
<script src="https://code.createjs.com/1.0.0/preloadjs.min.js"></script>
<div id="game"></div>