Vue and Airtable image loading issue with jQuery Lazy

I’m having trouble with lazy loading images from Airtable using Vue and jQuery Lazy. Can someone point me in the right direction?

I’ve set up a basic website that pulls images from my Airtable base using Vue. Here’s what my image tag looks like:

<img class="lazy" id="img1" :src="item.fields.Photo[0].thumbnails.large.url" alt="" v-if="item.fields.Photo">

I added jQuery Lazy to the mix, hoping it would help with performance. But it’s not working as expected. All the images load right away when the page opens.

I tried switching :src to :data-src like this:

<img class="lazy" id="img1" :data-src="item.fields.Photo[0].thumbnails.large.url" alt="" v-if="item.fields.Photo">

But now nothing shows up at all. I’m pretty new to Vue and Airtable, and coding in general. Any tips or suggestions would be super helpful! I feel like I’m close, but missing something important.

I’ve dealt with similar image loading challenges in Vue projects. One approach that worked well for me was using the Vue 3 Composition API with a custom composable for lazy loading. Here’s a quick outline:

Create a useIntersectionObserver composable:

import { ref, onMounted, onUnmounted } from 'vue'

export function useIntersectionObserver(options = {}) {
  const isIntersecting = ref(false)
  let observer = null

  onMounted(() => {
    observer = new IntersectionObserver(([entry]) => {
      isIntersecting.value = entry.isIntersecting
    }, options)
  })

  onUnmounted(() => {
    if (observer) observer.disconnect()
  })

  return { isIntersecting, observer }
}

Then in your component:

import { ref, onMounted } from 'vue'
import { useIntersectionObserver } from './useIntersectionObserver'

export default {
  setup() {
    const imgRef = ref(null)
    const { isIntersecting, observer } = useIntersectionObserver()

    onMounted(() => {
      if (imgRef.value) observer.observe(imgRef.value)
    })

    return { imgRef, isIntersecting }
  }
}

This approach is Vue-native and doesn’t require additional libraries. It’s worked well for me in production.

hey, i had a similar issue. try using a vue-specific lazy loading library instead of jquery lazy. vue-lazyload works great with vue and is pretty easy to set up. just install it, import it in your main.js, and use v-lazy directive on your img tags. that should do the trick!

I’ve been in your shoes, struggling with image loading in Vue. Here’s what worked for me:

Instead of using jQuery Lazy, I switched to Intersection Observer API. It’s native to modern browsers and works seamlessly with Vue.

First, create a simple directive:

Vue.directive('lazy', {
  inserted: el => {
    function loadImage() {
      const imageElement = Array.from(el.children).find(
        el => el.nodeName === 'IMG'
      )
      if (imageElement) {
        imageElement.addEventListener('load', () => {
          setTimeout(() => el.classList.add('loaded'), 100)
        })
        imageElement.addEventListener('error', () => console.log('error'))
        imageElement.src = imageElement.dataset.src
      }
    }

    function handleIntersect(entries, observer) {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          loadImage()
          observer.unobserve(el)
        }
      })
    }

    function createObserver() {
      const options = {
        root: null,
        threshold: '0'
      }
      const observer = new IntersectionObserver(handleIntersect, options)
      observer.observe(el)
    }

    if (window['IntersectionObserver']) {
      createObserver()
    } else {
      loadImage()
    }
  }
})

Then use it like this:

<div v-lazy>
  <img :data-src=\"item.fields.Photo[0].thumbnails.large.url\" alt=\"\">
</div>

This approach improved my site’s performance significantly. Hope it helps!