Skip to content

is it possible to use luminous in Vue.js?

I am trying to create photo website with vue.js and Laravel, and use luminous to magnify the photo when it is clicked. My photos are stored in AWS S3 bucket.

My vue.js structure is like below.

1.PhotoComponent.vue

  • this component is literally rendering each photo.
<template>
    <div class="photo">
        <a class="luminous" :href="item.url">
            <img class="photo_image" :src="item.url" :alt="`photo taken by ~~`">
        </a>
    </div>
</template>

<script>
export default {
    name: "PhotoComponent.vue",
    props: {
        item: { // this item has photo info(like url)
            type: Object, 
            required: true
        }
    },
}
</script>

<style scoped>
 
</style>

2.PhotoListComponent.vue

  • this component is making a list of PhotoComponent.vue.
<template>
    <div class="photo-list">
        <div class="grid">
            <PhotoComponent
                class="grid_item"
                v-for="photo in photos"
                :key="photo.id"
                :item="photo"
            ></PhotoComponent>
        </div>
        <PaginateComponent :current-page="currentPage" :last-page="lastPage"></PaginateComponent>
    </div>
</template>

<script>
import {OK} from '../util';
import PhotoComponent from "./PhotoComponent";
import PaginateComponent from "./PaginateComponent";

export default {
    name: "PhotoListComponent.vue",
    components: {
        PhotoComponent,
        PaginateComponent
    },
    props: {
        page: {
            type: Number,
            required: false,
            default: 1,
        }
    },
    data() {
        return {
            photos: [],
            currentPage: 0,
            lastPage: 0
        }
    },
    methods: {
        async fetchPhotos() { // I get each photo information through this method.
            const response = await axios.get(`/api/photos/?page=${this.page}`);

            if (response.status !== OK) {
                this.$store.commit('error/setCode', response.status);
                return false;
            }
            this.photos = response.data.data;
            this.currentPage = response.data.current_page;
            this.lastPage = response.data.last_page;
        },
    },
    watch: {
        $route: {
            async handler() {
                await this.fetchPhotos();
            },
            immediate: true,
        }
    },
}
</script>

<style scoped>

</style>

There are three things that I have tried so far.

  1. put new Luminous() in PhotoComponent, and put the function in mounted section.
<template>
    <div class="photo">
        <a class="luminous" :href="item.url">
            <img class="photo_image" :src="item.url" :alt="`photo taken by ~~`">
        </a>
    </div>
</template>

<script>
import { Luminous } from 'luminous-lightbox';
export default {
    name: "PhotoComponent.vue",
    props: {
        item: { // this item has photo info(like url)
            type: Object, 
            required: true
        }
    },
   methods: {
       luminous() {
           new Luminous(document.querySelector(".luminous"));
       }
   },
  mounted: {
    this.luminous();
  }
}
</script>

In this case, first picture works, but “” opens as many as PhotoComponent.vue. For example, if I make a list of 9 pictures in PhotoListComponent and click the first photo, “” opens 9 times. However, other pictures won’t work at all, but the new tab opens.

  1. put new LuminousGallery() in PhotoListComponent, and put the function in mounted section.
<template>
    <div class="photo-list">
        <div class="grid">
            <PhotoComponent
                class="grid_item"
                v-for="photo in photos"
                :key="photo.id"
                :item="photo"
            ></PhotoComponent>
        </div>
        <PaginateComponent :current-page="currentPage" :last-page="lastPage"></PaginateComponent>
    </div>
</template>

<script>
import {OK} from '../util';
import PhotoComponent from "./PhotoComponent";
import PaginateComponent from "./PaginateComponent";
import {LuminousGallery} from 'luminous-lightbox';

export default {
    name: "PhotoListComponent.vue",
    components: {
        PhotoComponent,
        PaginateComponent
    },
    props: {
        page: {
            type: Number,
            required: false,
            default: 1,
        }
    },
    data() {
        return {
            photos: [],
            currentPage: 0,
            lastPage: 0
        }
    },
    methods: {
        async fetchPhotos() { // I get each photo information through this method.
            const response = await axios.get(`/api/photos/?page=${this.page}`);

            if (response.status !== OK) {
                this.$store.commit('error/setCode', response.status);
                return false;
            }
            this.photos = response.data.data;
            this.currentPage = response.data.current_page;
            this.lastPage = response.data.last_page;
        },
        luminous() {
            new LuminousGallery(document.querySelectorAll('.luminous'));
        },
    },
    watch: {
        $route: {
            async handler() {
                await this.fetchPhotos();
            },
            immediate: true,
        }
    },
  mounted: {
    this.luminous();
  }.
}
</script>

In this case, a new tab opens whenever the photo is clicked, which means that luminous does not work.

  1. not mounted, but add click event in those component.

For example…

<template>
    <div class="photo">
        <a class="luminous" :href="item.url" @click.prevent="luminous">
            <img class="photo_image" :src="item.url" :alt="`photo taken by ~~`">
        </a>
    </div>
</template>

<script>
import { Luminous } from 'luminous-lightbox';
export default {
    name: "PhotoComponent.vue",
    props: {
        item: { // this item has photo info(like url)
            type: Object, 
            required: true
        }
    },
   methods: {
       luminous() {
           new Luminous(document.querySelector(".luminous"));
       }
   },
}
</script>

In this case, the result is almost the same as pattern 1, but the first picture works perfectly as I expected. However, the other picutures won’t open anything even a new tab.

Sorry for ranting. I am stuck with this problem for a week. I really need someone’s help. Thank you for your cooperation.

Answer

Konnichiwa @wadakatu, Fred from @imgix here (maintainer of Luminous).

You should be able to make all of your solutions work.

For 1/ I think you need to be able to target only the image that exists within that component, so something like this could work:

<template>
  <div class="photo">
    <a class="luminous" :href="item.url">
      <img class="photo_image" :src="item.url" :alt="`photo taken by ~~`" />
    </a>
  </div>
</template>

<script>
import { Luminous } from "luminous-lightbox";
export default {
  name: "PhotoComponent.vue",
  props: {
    item: {
      // this item has photo info(like url)
      type: Object,
      required: true,
    },
  },
  methods: {
    luminous() {
      // only look for relevant elements *inside* this component. Should only match one element
      new Luminous(this.$el.querySelector(".luminous"));
    },
  },
  mounted() {
    this.luminous();
  },
};
</script>

For 2/ I think there might be an issue where the code isn’t actually finding the image elements and thus is providing nothing to the LuminousGallery call. Maybe you could try debug that to find your issue.