Skip to content
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

Improvement of b-img-lazy component #1755

Closed
emanuelmutschlechner opened this issue Apr 19, 2018 · 14 comments · Fixed by #2382
Closed

Improvement of b-img-lazy component #1755

emanuelmutschlechner opened this issue Apr 19, 2018 · 14 comments · Fixed by #2382

Comments

@emanuelmutschlechner
Copy link
Contributor

@victorhramos, @KonradDeskiewicz
Let's continue the conversation here. Initial issue #1619

There is an initial check which is executed when <b-img-lazy> is mounted and activated but due to the missing getBoundingClientRect of the html element nothing happens.

I would like to improve this component because it is very useful. Currently lazy loading does only work when the page scrolls. Not optimal when you have dynamic content and want to lazy load, but there is not enough content for the page to scroll. See my codesandbox below.
https://codesandbox.io/s/z5pkrx89m

In addition it would be nice to have state classes like <router-link> has, e.g.

  • img-lazy-blank when blank image is shown. Could be used to apply opacity or other css filters
  • img-lazy-src when src image is shown.

And a last improvement that comes to my mind is async loading of src images e.g.

const prefetchImage = src => new Promise((resolve, reject) => {
    const img = new Image();
    eventOn(img, 'load', () => {
        resolve();
    });
    eventOn(img, 'error', () => {
        reject();
    });
    img.src = src;
});
@victorhramos
Copy link

Yes, was trying to use here: https://www.codemarket.com.br/
vue-lazyload worked as well, but in ordering to use pwa i removed that.
I made "b-img-lazy" get working with a small trick scrolling 1px down and turn it back at mounted event.

@derekphilipau
Copy link

derekphilipau commented Apr 26, 2018

@emanuelmutschlechner's suggestions would be wonderful, apart from blank not being replaced until scroll, also currently there's no way to add a blur to the preload image, which makes the component unusable for my requirements. In addition to adding css classes like img-lazy-blank, since adding a blur is such a common technique, it could even be added as a property, ala vue-progressive-image.

Also I think it should be possible to automatically replace the lazy-blank image and show the high-resolution image immediately after loading, rather than waiting for a scroll event or checking proximity.

@blaskovicz
Copy link

I'm noticing an issue as well when using a b-img-lazy withing a b-carousel-slide that's inside a b-table. When sorting rows, my work around to fire the scroll even when a b-carousel slides or the component is mounted doesn't work and the image is left blank until I re-scroll:
blaskovicz/house-rank@0118fc3

@kuus
Copy link

kuus commented Oct 16, 2018

I am using this weird stuff to fool the component to load immediately

window.scrollTo(window.scrollX, window.scrollY + 1)
window.scrollTo(window.scrollX, window.scrollY - 1)

@blaskovicz
Copy link

blaskovicz commented Oct 16, 2018

I had to add the scrolling in the updated() lifecycle callback as well to handle the case where the component b-img-lazy was within a b-table and the table rows got sorted. Even this is not an all-encompassing solution. It doesn't handle the case where the b-img-lazy was used with vue2-leaflet and a point on the map is clicked, exposing an l-popup:

blaskovicz/house-rank@27ca07d#diff-eeb590b1e0cd678b82a38fae02148e71R58
https://github.com/blaskovicz/house-rank/blob/master/src/lib/events.ts#L6

@tmorehouse
Copy link
Member

Adding a check on mounted/updated shouldnt be too difficult.

We could also probably add an option to specify the scroll parent to monitor (default is window/body).

But in the case of b-carousel, scrolling is not used to display the slides. Rather it is using transitions, which don't trigger a scroll event.

@tvld
Copy link

tvld commented Dec 21, 2018

For me all works fine as I simple invoke a scroll event whith every onslide start (until I have all slides:

  data () {
    return {
      nrScrolls: 1,
      nrSlides: 4
      ]
    }
  },
  methods: {
    onSlideStart () {
      // for lazy loading, we invoke scroll event for each slide once
      if (this.nrScrolls <= this.nrSlides) {
        // we did not lazy load all slides yet
        invokeScrollEvent('Sales deck slide ' + this.nrScrolls, 50)
        this.nrScrolls++
      }
    }
  }

the invokeScrollEvent.js

export default function (note = '...', wait = 100) {
  /* global Event */
  let event

  setTimeout(function () {
    var msg = `Force scroll Event for: "${note}" (${wait}ms)`
    if (typeof (Event) === 'function') {
      // we have a non-IE browser
      event = new Event('scroll')
    } else {
      // Microsoft, IE10/11
      msg += '(IE10/11)'
      event = document.createEvent('Event')
      event.initEvent('scroll', true, true)
    }
    console.log(msg)
    window.dispatchEvent(event)
  }, wait)
}

@dohomi
Copy link

dohomi commented Jan 3, 2019

I just found this issue while using the b-img-lazy component.

Is there any fix, dispatching a scroll event wouldn't be the best approach for my usecase because of side-effects with a toolbar. It would be great to set a prop 'active' manually to show the src, that would be very flexible

@tmorehouse
Copy link
Member

@dohomi that might be an option, or to use a setInterval to periodically check if hte image is in view (and clear the interval when the image is finally shown).

@dohomi
Copy link

dohomi commented Jan 3, 2019

@tmorehouse I have a wrapper component around the b-img-lazy so I do currently a check on mounted if its inside the viewport as simple as:

mounted(){
  this.inViewport()
},
methods:{
  inViewport(){
  const bounding = this.$el.getBoundingClientRect()
  const isView = bounding.top >= 0 &&
        bounding.left >= 0 &&
        bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
        bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
 }
}

I'm just facing the issue that I can't set a prop or do anything about triggering the src set. I would rather even think that the component itself should just fall back to b-img in case its inside of the viewport. Either way it would be great to programatically set the 'active' state of the component
UPDATE:
For now I just use
<component :is="isVisible ? 'b-img' : 'b-img-lazy'"/>

@tmorehouse
Copy link
Member

tmorehouse commented Jan 3, 2019

Another option we might be able to implement is an option to specify the scroll parent element (or automatically find the scroll parent element). Although this wouldn't handle the case where transitions bring the image into view though.

You could use the regular b-img, and specify a blank image (blank prop), and then dynamically set the src prop when the image is in view (which is basically what b-img-lazy does)

@dohomi
Copy link

dohomi commented Jan 3, 2019

@tmorehouse thanks currently I'm running good with the above snippet. I just think it would be great if the lazy version recognizes on mounted already per default that it is (and should be) visible. Because currently it feels buggy to me if I have to write code around the usecase that the component is initially already visible.

@tmorehouse
Copy link
Member

Yeah, let me check the code and see if we can make an adjustment to the mounted() hook.

tmorehouse added a commit that referenced this issue Jan 3, 2019
…1755)

Wraps initial inView check in nextTick to ensure DOM is complete.

Adds new syncable prop `show` to force image to show

Fixes #1755
@tmorehouse
Copy link
Member

PR #2382 should fix this issue, as well as adds in a new show prop to force show the image.

Also, bubbled transitonend events are now monitored, so b-img-lazy should work inside elements with transitions that show/slide/scroll the content (on browsers that support the transitionend event).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants