等待图像在 JavaScript 中加载

IT技术 javascript image load wait
2021-01-21 01:08:21

我正在执行 Ajax 调用,它会返回一些信息,包括图像路径。

我在我的 HTML 中准备了所有这些信息,这些信息将显示为一种弹出窗口。我只是将弹出 div 的可见性从隐藏切换到可见。

要设置弹出 div 的位置,我必须根据图像的高度进行计算。因此,在设置位置并将可见性切换为可见之前,我必须等待图像加载以了解其尺寸。

我尝试了递归、setTimeout、完整的 img 属性、while 循环……但没有成功。

那么,我该怎么做呢?也许我应该在我的 Ajax 调用中返回维度。

6个回答
var img = new Image();
img.onload = function() { alert("Height: " + this.height); }
img.src = "http://path/to/image.jpg";

请注意,按上述顺序执行此操作很重要:首先附加处理程序,然后设置src. 如果您以相反的方式执行此操作,并且图像在缓存中,则您可能会错过该事件。JavaScript 在浏览器中的单线程上运行(除非您使用网络工作者),但浏览器不是单线程的。浏览器看到src,识别资源可用,加载它,触发事件,查看元素以查看它是否有任何需要排队等待回调的处理程序,没有看到任何处理程序,并完成事件,这是完全有效的处理,所有之间src线和附加处理程序的线。(如果它们被注册,回调就不会在行之间发生,它们会在队列中等待,但如果没有,则不需要事件等待。)

@Marco 或cache: false在 XHR 上设置:) 虽然我认为这在这里无关紧要,因为 AJAX 调用返回的是图像的 URL,而不是图像本身。但是是的,我想他仍然可以使用随机查询字符串值来确保不会发生用户代理缓存。
2021-03-23 01:08:21
如果我改变第二行和第三行的顺序有关系吗?
2021-03-24 01:08:21
太好了!顺便说一句:我对 AJAX 主题非常无知,但以防万一使用 AJAX 获得的图像以与直接写入 HTML 代码的图像相同的方式缓存,您最终可以添加它以避免浏览器的图像缓存(显然仅在您需要时): img.src=" path/to/image.jpg"+"?refresh="+new Date().getTime();
2021-03-30 01:08:21
您也可以添加事件侦听器,或者正在替换onload方式?
2021-04-09 01:08:21
@IQAndreas:你可以使用img.addEventListener("load", ...),是的。(或img.attachEvent("onload", ...)在旧的 IE 上)。
2021-04-12 01:08:21

如果你使用 jQuery,你可以使用它的load事件。

看看这个例子:

$('img.userIcon').load(function(){
    if($(this).height() > 100) {
        $(this).addClass('bigImg');
    }
});
还请注意与图像一起使用时 load 方法的以下注意事项(取自api.jquery.com/load-event): > 它不能一致地工作,也不能可靠地跨浏览器 > 它不能在 WebKit 中正确触发,如果图像 src 设置为与以前相同的 src > 它没有正确地冒出 DOM 树 > 可以停止为已经存在于浏览器缓存中的图像触发
2021-03-17 01:08:21
除非请求 jquery,否则请不要使用 jquery
2021-03-28 01:08:21
-1:问题中没有提到 jQuery,所以这样的答案可能会很混乱。
2021-03-29 01:08:21

只需将您的图像 onload 包装在一个带有 promise 的函数中,然后使用 await 调用它。

async drawImg(ctx, image){

    return new Promise(resolve => {

          image.onload = function () {
                ctx.drawImage(image, 10, 10, 200, 180);
                resolve('resolved');
             }

    });

  }

它应该工作得很好

async这里关键字是不必要的——返回一个Promise对于调用者await来说就足够了Promise onerror 处理程序也是一个好主意,reject()以便调用者可以在加载失败时捕获错误。最后的建议:您可以将图像对象本身传递给,resolve(this)以便调用者可以绘制图像或用它做他们想做的事情。
2021-03-23 01:08:21

接受的答案是过时的,但确实表明了基本的Image#onload回调方法。如今,您可能希望Promise图像加载以避免回调地狱。

这个答案是Promise图像加载处理程序的好方法,但正如我的评论所指出的那样,缺少一些关键点

这是另一个Image更笼统的Promiseonerror处理程序中拒绝并将实际图像对象传递给解析器对于使函数的可重用性最小化很重要。

改进可能包括其他参数(crossOrigin例如 )。一个settings对象或提供一个Image作为参数是另一种泛化函数的方法(设置src触发请求,所以应该在添加处理程序后最后进行)。

const loadImage = src =>
  new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = src;
  })  
;

loadImage("http://placekitten.com/90/100").then(image => 
  console.log(image, `\nloaded? ${image.complete}`)
);

使用上述功能,Promise.all可用于并行加载一批图像(Promise.allSettled如果您想在某些图像未加载的情况下继续前进,则很有用)。

const loadImage = src =>
  new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = src;
  })  
;

const imageUrls = [
  "http://placekitten.com/85/150",
  "http://placekitten.com/85/130",
  "http://placekitten.com/85/110",
];
Promise.all(imageUrls.map(loadImage)).then(images => {
  const canvas = document.createElement("canvas");
  document.body.appendChild(canvas);
  const ctx = canvas.getContext("2d");
  images.forEach((image, i) =>
    ctx.drawImage(image, i * 90, 0, image.width, image.height)
  );
});

窗口加载事件怎么样?

window.addEventListener('load', (event) => {
  //do stuff with images
});

或者

window.onload = (event) => {
  //do stuff with images
};

https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event

这对我有用,我需要浏览器在运行布局脚本之前计算图像的大小。

这似乎并不能很好地回答这个问题,因为有很多次可以在页面本身加载后加载图像,包括这个例子。窗口上的 onload 事件会等待图像加载,但仅用于初始页面加载。在这个问题的上下文中, onload 事件应该直接绑定到正在加载的图像元素。
2021-04-03 01:08:21