-
Notifications
You must be signed in to change notification settings - Fork 441
🎉 Add loaded callback #86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🎉 Add loaded callback #86
Conversation
|
@joshwhatk this looks neat. While reviewing code, came across this line https://github.com/ApoorvSaxena/lozad.js/pull/86/files#diff-ada3201bd50efbeb7cff01652d1426cdR63 where |
`markAsLoaded` is required to run for the `isLoaded` method to be useful. Also added a negative test for when a custom `load` option is passed in.
|
@ApoorvSaxena good catch! Also, it appears that the markAsLoaded method is necessary for lozad to check whether elements have been loaded or not, so it shouldn't just be overridden. Instead, I added |
test/index.js
Outdated
| assert.equal(image.getAttribute('src'), image.dataset.src) | ||
| }) | ||
|
|
||
| // It('should run loaded function after loading an element', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems unwanted, better remove the commented code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
@ApoorvSaxena Will you be pushing a new bower "release" with this change? |
|
how will this help with being able to start f.ex an animation when the image is downloaded? wasnt that the purpose of #79 which was closed in favor of this one. |
|
I would like to fade in the images when they load. With is method with large images you will notice that the callback works only when the image is in view not when its fully loaded. So you still get a standard baseline load. Not very sexy. should be Then there should be a truly loaded method. Please look into pulling @aderaaij pull request, as I think it makes more sense. Am I not understanding something? The above post agrees aswell, something is not right. Please advise. |
|
@rgfx @perosb What exactly are you working with? I would probably hook into the onload event for the images if I wanted to fade them in on their load. Something like this: https://jsfiddle.net/joshwhatk/kxq8jbn8/5/ |
|
@joshwhatk as said here the data-loaded just happens when the strings get switched from data-src to src, that is not checking if the image is loaded. |
|
@jimblue, absolutely, the In the fiddle, I manually hook into the But I think I'm hearing that the |
|
@joshwhatk I'm not sure @ApoorvSaxena want to go in this direction as this PR took priority over. I've worked on a local solution that could help. For now it's working well, but you're probably right about adding another data-something to prevent lozad to load the image multiple times. Here is the code: // LAZYIMG
// ––––––––––––––––––––––
import 'intersection-observer'
export default () => {
// Get all of the elements that are marked up to lazy load
const elements = document.querySelectorAll('.lazyimg')
// Create the observer
let observer
const observe = elements => {
// Config
const config = {
rootMargin: '0px',
threshold: 0
}
// Create the observer instance
observer = new IntersectionObserver(onIntersection, config)
for (let i = 0; i < elements.length; i++) {
const element = elements[i]
// If the element has been handled, skip to the next element
if (isLoaded(element)) return
// Observes the element
observer.observe(element)
}
}
const fetchImage = imgSrc => {
// Create a promise to fetch an image
return new Promise((resolve, reject) => {
// Create a new image
const image = new Image()
// Handles errors
image.addEventListener('load', resolve)
image.addEventListener('error', reject)
// Set this image to the paramenter imgSrc
image.src = imgSrc
})
}
const applyImage = (element, imgSrc, type) => {
// Define element imgSrc
if (type === 'img') element.src = imgSrc
// Define element imgSrc
if (type === 'bg') element.style.backgroundImage = `url(${imgSrc})`
// Prevent this from being lazy loaded a second time
markAsLoaded(element)
}
const preloadImage = element => {
// Get imgSrc from the dataset
let imgSrc
let type
// If element is an image
if (element.dataset.src) {
imgSrc = element.dataset.src
type = 'img'
}
// If element is a background image
if (element.dataset.bg) {
imgSrc = element.dataset.bg
type = 'bg'
}
// If imgSrc or type is not found break
if (!imgSrc || !type) return
// Fetches imgSrc and applies it to the viewport
return fetchImage(imgSrc).then(() => applyImage(element, imgSrc, type))
}
// Mark element as loaded
const markAsLoaded = element => element.setAttribute('data-loaded', true)
// Check if element is loaded
const isLoaded = element => element.getAttribute('data-loaded') === 'true'
const onIntersection = entries => {
// Loop through entries
for (let i = 0; i < entries.length; i++) {
const entry = entries[i]
// If the element is in the viewport unobserve it
if (entry.intersectionRatio > 0) {
// Stop watching
observer.unobserve(entry.target)
// Load the element if it's not already
preloadImage(entry.target)
}
}
}
return observe(elements)
} |
|
@joshwhatk your last fiddle doesn't show any images for me. I thought perhaps it was your placeholders but it wasn't. Will your solution work for the Picture tag? To fade in images when fully loaded. @jimblue forgive my ignorance but what is import 'intersection-observer' are you using webpack or something? Will your script work with the picture tag as well, once I figure out how to use your script. Thanks guys. |
|
@rgfx yes I use webpack to import the intersection observer polyfill before the script to improve compatibility on old browser but picture tag currently doesn't work. |
|
The callback doesn't quite work as expected, but @joshwhatk's fiddle solution works great. Thank you @joshwhatk! |
Context
While the
loadconfig method is valuable, I don’t want to have to rewrite the entire includedloadfunction to extend the functionality just to get the default benefits provided by Lozad.As it currently sits, there is no way for me to test a custom implementation for retina support background-images (uses -webkit-image-set). without rewriting the entire default load function.
I also cannot currently override the
markAsLoadedmethod. I used the.lazy-loadclass and would like to modify it to be.lazy-loadedto make my query for unloaded items simpler:.lazy-loadvs.lazy-load:not([data-loaded]).Solution
With a
loadedcallback (name WIP) option, I could add any additional functionality that I want without having to duplicate functionality that will just get out of date.Example