Làm cách nào để tạo một cuộc gọi lại JavaScript để biết khi nào một hình ảnh được tải?


Câu trả lời:


159

.complete + gọi lại

Đây là một phương pháp tuân thủ tiêu chuẩn mà không phụ thuộc thêm và chờ đợi không quá cần thiết:

var img = document.querySelector('img')

function loaded() {
  alert('loaded')
}

if (img.complete) {
  loaded()
} else {
  img.addEventListener('load', loaded)
  img.addEventListener('error', function() {
      alert('error')
  })
}

Nguồn: http://www.html5rocks.com/en/tutorials/es6/promises/


4
Điều này có thể sai nếu hình ảnh hoàn thành giữa img.completecuộc gọi và addEventListenercuộc gọi?
Thomas Ahle

@ThomasAhle Tôi không phải là chuyên gia, nhưng điều đó dường như là có thể. Hãy xem có ai có giải pháp không.
Ciro Santilli 郝海东 冠状 病 事件

Tôi đoán đó chỉ là một vấn đề đối với mã song song, mà hầu hết các javascript có lẽ không phải là ..
Thomas Ahle

4
@ThomasAhle Không thể, vì trình duyệt sẽ chỉ kích hoạt sự kiện tải khi hàng đợi sự kiện được quay. Điều đó nói rằng, loadngười nghe sự kiện phải ở trong một elsemệnh đề, như img.completecó thể trở thành sự thật trước khi loadsự kiện được kích hoạt, do đó nếu bạn không có khả năng đã loadedgọi hai lần (lưu ý điều này tương đối có khả năng thay đổi img.completechỉ trở thành sự thật khi sự kiện hỏa hoạn).
gsnedder

71

Image.onload () thường sẽ hoạt động.

Để sử dụng nó, bạn cần chắc chắn ràng buộc trình xử lý sự kiện trước khi bạn đặt thuộc tính src.

Liên kết liên quan:

Cách sử dụng ví dụ:

    window.onload = function () {

        var logo = document.getElementById('sologo');

        logo.onload = function () {
            alert ("The image has loaded!");		
        };

        setTimeout(function(){
            logo.src = 'https://edmullen.net/test/rc.jpg';         
        }, 5000);
    };
 <html>
    <head>
    <title>Image onload()</title>
    </head>
    <body>

    <img src="#" alt="This image is going to load" id="sologo"/>

    <script type="text/javascript">

    </script>
    </body>
    </html>


26
FYI: Theo thông số kỹ thuật của W3C, onload không phải là sự kiện hợp lệ cho các phần tử IMG. Rõ ràng các trình duyệt hỗ trợ nó, nhưng nếu bạn quan tâm đến thông số kỹ thuật và không chắc chắn 100% tất cả các trình duyệt bạn muốn nhắm mục tiêu hỗ trợ này, bạn có thể muốn suy nghĩ lại hoặc ít nhất là ghi nhớ nó.
Jason Bunting

3
Tại sao chờ 5 giây để đặt nguồn có vẻ là một ý tưởng tồi?
tuyệt vời

8
@quemished đó là lý do tại sao nó được gọi là "một ví dụ".
Diego Jancic

3
@JasonBunting Bạn đang nhìn gì khiến bạn nghĩ rằng loadsự kiện này không hợp lệ? html.spec.whatwg.org/multipage/webappapis.html#handler-onload là định nghĩa của onload trình xử lý sự kiện.
gsnedder

4
@ssnedder - bạn nhận ra, tôi cho rằng, khi tôi viết bình luận đó, tôi đã đề cập đến tiêu chuẩn còn tồn tại, không phải là tiêu chuẩn mà bạn đã chỉ ra, mới hơn 4,5 năm. Có phải bạn đã hỏi lại sau đó, tôi có thể đã chỉ vào nó, có lẽ. Đó là bản chất của web, phải không? Mọi thứ trở nên cũ kỹ hoặc bị di chuyển hoặc được sửa đổi, v.v.
Jason Bunting

20

Bạn có thể sử dụng thuộc tính .complete của lớp hình ảnh Javascript.

Tôi có một ứng dụng nơi tôi lưu trữ một số đối tượng Hình ảnh trong một mảng, nó sẽ được thêm động vào màn hình và khi chúng đang tải, tôi viết các bản cập nhật cho một div khác trên trang. Đây là một đoạn mã:

var gAllImages = [];

function makeThumbDivs(thumbnailsBegin, thumbnailsEnd)
{
    gAllImages = [];

    for (var i = thumbnailsBegin; i < thumbnailsEnd; i++) 
    {
        var theImage = new Image();
        theImage.src = "thumbs/" + getFilename(globals.gAllPageGUIDs[i]);
        gAllImages.push(theImage);

        setTimeout('checkForAllImagesLoaded()', 5);
        window.status="Creating thumbnail "+(i+1)+" of " + thumbnailsEnd;

        // make a new div containing that image
        makeASingleThumbDiv(globals.gAllPageGUIDs[i]);
    }
}

function checkForAllImagesLoaded()
{
    for (var i = 0; i < gAllImages.length; i++) {
        if (!gAllImages[i].complete) {
            var percentage = i * 100.0 / (gAllImages.length);
            percentage = percentage.toFixed(0).toString() + ' %';

            userMessagesController.setMessage("loading... " + percentage);
            setTimeout('checkForAllImagesLoaded()', 20);
            return;
        }
    }

    userMessagesController.setMessage(globals.defaultTitle);
}

Tôi đã sử dụng mã tương tự trong công việc của tôi trước đây. Điều này hoạt động tốt trong tất cả các trình duyệt.
Gabriel Hurley

2
Vấn đề với việc kiểm tra hoàn tất là bắt đầu với IE9, các sự kiện OnLoad được kích hoạt trước khi tất cả các hình ảnh được tải và thật khó để tìm ra trình kích hoạt cho chức năng kiểm tra ngay bây giờ.
Gene Vincent


8

Cuộc sống quá ngắn cho jquery.

function waitForImageToLoad(imageElement){
  return new Promise(resolve=>{imageElement.onload = resolve})
}

var myImage = document.getElementById('myImage');
var newImageSrc = "https://pmchollywoodlife.files.wordpress.com/2011/12/justin-bieber-bio-photo1.jpg?w=620"

myImage.src = newImageSrc;
waitForImageToLoad(myImage).then(()=>{
  // Image have loaded.
  console.log('Loaded lol')
});
<img id="myImage" src="">


1
Đây là một câu trả lời tuyệt vời nhưng tôi không nghĩ bạn thậm chí cần nhiều mã như vậy. Bạn đang làm cho nó trông khó hiểu bằng cách thêm vào srcvới JS.
Brandon Lợi ích

1
Thời gian là một hạn chế rất lớn trong lập trình. Từ kinh nghiệm của tôi, viết mã có thể đọc được (trong khi một thời gian dài) mang lại lợi ích lớn về thời gian.
Idan Beker

Tại sao bạn chỉ lưu trữ src vào một biến mới chỉ để tiêu thụ nó trên dòng tiếp theo? Nếu sự ngắn gọn là mục tiêu của bạn, thì đó là một mô hình chống. myImage.src = https://pmchollywoodlife.files.wordpress.com/2011/12/justin-bieber-bio-photo1.jpg?w=620không lừa
Giô

3

Đây là jQuery tương đương:

var $img = $('img');

if ($img.length > 0 && !$img.get(0).complete) {
   $img.on('load', triggerAction);
}

function triggerAction() {
   alert('img has been loaded');
}

1

Không phù hợp cho năm 2008 khi câu hỏi được hỏi, nhưng những ngày này nó hoạt động tốt với tôi:

async function newImageSrc(src) {
  // Get a reference to the image in whatever way suits.
  let image = document.getElementById('image-id');

  // Update the source.
  img.src = src;

  // Wait for it to load.
  await new Promise((resolve) => { image.onload = resolve; });

  // Done!
  console.log('image loaded! do something...');
}

0

các chức năng này sẽ giải quyết vấn đề, bạn cần thực hiện DrawThumbnailschức năng và có một biến toàn cục để lưu trữ hình ảnh. Tôi thích có được điều này để làm việc với một đối tượng lớp có ThumbnailImageArraybiến thành viên, nhưng đang gặp khó khăn!

gọi như trong addThumbnailImages(10);

var ThumbnailImageArray = [];

function addThumbnailImages(MaxNumberOfImages)
{
    var imgs = [];

    for (var i=1; i<MaxNumberOfImages; i++)
    {
        imgs.push(i+".jpeg");
    }

    preloadimages(imgs).done(function (images){
            var c=0;

            for(var i=0; i<images.length; i++)
            {
                if(images[i].width >0) 
                {
                    if(c != i)
                        images[c] = images[i];
                    c++;
                }
            }

            images.length = c;

            DrawThumbnails();
        });
}



function preloadimages(arr)
{
    var loadedimages=0
    var postaction=function(){}
    var arr=(typeof arr!="object")? [arr] : arr

    function imageloadpost()
    {
        loadedimages++;
        if (loadedimages==arr.length)
        {
            postaction(ThumbnailImageArray); //call postaction and pass in newimages array as parameter
        }
    };

    for (var i=0; i<arr.length; i++)
    {
        ThumbnailImageArray[i]=new Image();
        ThumbnailImageArray[i].src=arr[i];
        ThumbnailImageArray[i].onload=function(){ imageloadpost();};
        ThumbnailImageArray[i].onerror=function(){ imageloadpost();};
    }
    //return blank object with done() method    
    //remember user defined callback functions to be called when images load
    return  { done:function(f){ postaction=f || postaction } };
}

11
Hầu hết các mã này là không liên quan, bao gồm toàn bộ addThumbnailImageschức năng của bạn . Cắt nó xuống mã liên quan và tôi sẽ xóa -1.
Justin Morgan

0

Nếu mục tiêu là tạo kiểu cho img sau khi trình duyệt hiển thị hình ảnh, bạn nên:

const img = new Image();
img.src = 'path/to/img.jpg';

img.decode().then(() => {
/* set styles */
/* add img to DOM */ 
});

bởi vì trình duyệt đầu tiên loads the compressed version of image, sau đó decodes it, cuối cùng paintsnó vì không có sự kiện nào cho paintbạn nên chạy logic của bạn sau khi trình duyệt có decodedthẻ img.


-2

Nếu bạn đang sử dụng React.js, bạn có thể làm điều này:

render() {

// ...

<img 
onLoad={() => this.onImgLoad({ item })}
onError={() => this.onImgLoad({ item })}

src={item.src} key={item.key}
ref={item.key} />

// ...}

Ở đâu:

  • - onLoad (...) bây giờ sẽ gọi bằng một cái gì đó như thế này: {src: " https: //......png ", key: "1"} bạn có thể sử dụng cái này làm "key" để biết hình ảnh nào được tải chính xác và không.
  • - onError (...) nó giống nhau nhưng có lỗi.
  • - đối tượng "mục" là một cái gì đó giống như {key: "..", src: ".."} bạn có thể sử dụng để lưu trữ URL và khóa của hình ảnh để sử dụng trong danh sách hình ảnh.

  • Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
    Licensed under cc by-sa 3.0 with attribution required.