mart cube
mart cube

Reputation: 665

Lazyload image in Vue/Nuxt gallery component

I'm trying to create a simple gallery component where if you click on some image a Light-Box will appear where you can see full size photo and have options like next and previous photo or close the Light-Box.

Currently When I need to change the image to next or previous I change the src of the img-tag and it works.

Here comes my problem. I want to lazy load my images. I use lazysizes in my project. So the simple implementation to have an image to load is to add the class "lazyload" and to pass the property data-src instead of src.

However if I change to data-src my methods for next and previous image are not working.

< script >
  export default {
    props: {
      data: {
        type: Array,
        required: true,
      },
    },
    data: () => ({
      visible: false,
      currentImage: 0,
    }),
    methods: {
      Toggle(index) {
        this.currentImage = index
        this.visible = !this.visible
      },
      Next() {
        if (this.currentImage !== this.data.length - 1) this.currentImage++
      },
      Prev() {
        if (this.currentImage !== 0) this.currentImage--
      },
    },
  } <
  /script>
<template>
  <div id="gallery" class="gallery">
  
    <!-- images grid -->
        <div v-for="(item, i) in data" :key="'gallery-image' + i" class="image">
            <img :src="item.image.thumbnail.url" @click.native="Toggle(i)" class="lazyload"/>
        </div>
    
    
    <!-- image lighbox on click -->
      <div v-if="visible" class="lightbox">
          <Icon class="cancel" @click="Toggle()"/>
          <Icon name="left" :class="{ disable: currentImage == 0 }"  @click="Prev()"/>
      <img :src="data[currentImage].image.url" class="lazyload"/> 
          <Icon name="right" :class="{ disable: currentImage == data.length - 1 }" @click="Next()"/>
      </div>
    
  </div>
</template>

UPDATE I forgot to add crucial code. To implement lazysizes in a Nuxt project we need to add in nuxt.config.js the fallowing code. You can read more here.

build: {
  extend(config, { isClient, loaders: { vue } }) { 
    vue.transformAssetUrls.img = ['data-src', 'src']
  },
},

As I investigate in the developer tools I found that when triggering click for method like Next image, the src of the image does not change, only the data-src. I'm guessing I need a way to trigger this transform so that everything can work as expected.

Upvotes: 1

Views: 2359

Answers (2)

mart cube
mart cube

Reputation: 665

Probably this is not the most elegant way to do it . I force re-render to my image component. You need to assign a key value to component and whenever the value changes a new instance creates of the component.

Upvotes: 0

kissu
kissu

Reputation: 46612

Also, on top of my comment, I do recommend looking into the official nuxt image module which do have native lazy loading out of the box: https://image.nuxtjs.org/components/nuxt-img

You could maybe combo this with some simple lightbox that does the trick for you. I've used vue-silentbox before, it is working pretty well.

You can have that kind of code there

<silent-box :gallery="photosToDisplay">
  <template #silentbox-item="{ silentboxItem }">
    <img :src="silentboxItem.src" :key="silentboxItem.id" />
  </template>
</silent-box>

So, I guess that you could totally swap img by a nuxt-img there, and have it lazy-loaded.
The images are not lazy-loaded in the project, but here is a small project that I did to try out the lightbox if you want to quickly look how it renders (URL in the top right corner).

Upvotes: 1

Related Questions