desandro / imagesloaded

:camera: JavaScript is all like "You images done yet or what?"
https://imagesloaded.desandro.com
MIT License
8.88k stars 1.15k forks source link

Under-documented behaviour #281

Closed CaelanStewart closed 2 years ago

CaelanStewart commented 5 years ago

Hi, great plugin, been using it for ages, but on a specific use case right now, I need to know certain behaviours to solve a specific problem, but reading your documentation, you don't say much about the internal mechanisms.

I've just experienced an issue, I've built a lazy-loading image Vue component for a specific use case, and I used imagesLoaded to detect when the image has loaded so that dimensions can be retrieved and manipulations can take place. I, when the load is triggered, pass the <img> element directly to imagesLoaded(el, callback). However, in a strange twist, the specific listeners on each <img> element fire when an image that's inside the Image Library pop-up component within the app is loaded, even after the specific <img> passed to the imagesLoaded function has loaded. The images loaded inside the Image library popup are different variations of the same images with a different resolution (and different URLs). Perhaps it's some odd Vue quirk, where it re-renders the components on the page when ImageLibrary component is shown and loads it's own images. But it's certain that the components are not destroyed and re-created when this happens, the imagesLoaded event simply fires again for the already loaded image, when a different image is loaded in a specific context.

It isn't mentioned in the docs that you can pass the image element, the examples you give are all container elements, not individual <img> elements.

You did say, in the imagesLoaded function definition in your docs:

elem Element, NodeList, Array, or Selector String

But, it doesn't say HTMLImageElement (even though it derives from Element).

I'm thinking about changing the implementation so that I have an external system notifying the <lazy-load> components when an image has loaded, and the <lazy-load> component can ask the external image manager to be told when the given image is loaded.

But, you don't say if it knows new <img> elements are added, or if I'd have to remove and re-attach the event in the instance of new images being inserted, in order to detect them.

And on events, if I just do imagesLoaded(img, callback), does the event listener remove itself after load? In can infer that it doesn't from the problem posed above, but the point is I had to infer it from observations.

It'd be really great of there was a nice, full explanation of the library's behaviours and the specifics of how it works. I understand this takes a little bit of time, but it's the point that most documentation falls over on. All of the examples are well and good, but examples (and much more) can be derived from a good explanation of behaviour, removing the need for all except the most rudimentary surface examples (for those who quickly Googled a solution and copied-and-pasted it).

desandro commented 5 years ago

Let me first say thank you for thoughtful and consideration around imagesLoaded.

imagesLoaded was first created in 2011. Ages ago. Both browsers and JS development has advanced so much in that time that I often wonder if its utility is necessary. You mention you are already using Vue. In which case, you may likely be better served by creating an observable that looks directly at the <img> in question, rather than relying on old imagesLoaded.

But, you don't say if it knows new <img> elements are added, or if I'd have to remove and re-attach the event in the instance of new images being inserted, in order to detect them

imagesLoaded does not trigger again after a new image is added to a parent element or when an image's src is changed. And that's because it was designed for a different time, before Virtual DOM frameworks ever existed.

CaelanStewart commented 5 years ago

Let me first say thank you for thoughtful and consideration around imagesLoaded.

imagesLoaded was first created in 2011. Ages ago. Both browsers and JS development has advanced so much in that time that I often wonder if its utility is necessary. You mention you are already using Vue. In which case, you may likely be better served by creating an observable that looks directly at the <img> in question, rather than relying on old imagesLoaded.

But, you don't say if it knows new <img> elements are added, or if I'd have to remove and re-attach the event in the instance of new images being inserted, in order to detect them

imagesLoaded does not trigger again after a new image is added to a parent element or when an image's src is changed. And that's because it was designed for a different time, before Virtual DOM frameworks ever existed.

Hi,

Thank you for the explanation!

Yes, it would seem that approach would be preferable. I had so habitually used imagesLoaded on the occasion it were needed, that I hadn't thought to check if it was really that necessary in this context.

Thanks again.

jordanboston commented 5 years ago

@CaelanStewart would love to know what direction you took in Vue if you did no longer use ImagesLoaded. I'm having trouble with bugginess on initial load and I just can't seem to resolve it.

CaelanStewart commented 5 years ago

@jordanboston - I had gotten imagesLoaded to work correctly before @.desandro had responded.

But I did have some odd issues, like sometimes the imagesLoaded event would fire, when the naturalWidth and naturalHeight were still 0, and I needed those properties.

I had another weird issue, described in an above post, too. Though I think this issue is related.

I think it was perhaps related to Vue magic going on underneath the hood - not sure, but seemed the logical deduction.

To fix, when imagesLoaded fired, I checked the value of natural[Width|Height] and if both were 0, I set an interval to check again until the values were truthy, tying up to 20 times. when they became truthy, I would fire my own abstracted 'image loaded' event, which then triggered code that used those properties.

It was a hacky fix, and 20 is probably overkill, but it worked and there was (still is) tons more to get done and it's been working fine since.

I will likely revisit the component at some point.

Though, may I ask what other issues you had?

jordanboston commented 5 years ago

Thanks for the info @CaelanStewart