Reputation: 678
I've done some serious internet searching to find a popup gallery plugin for Vue 3 which supports both images and video files. Most of the plugins are written for Vue 2.
Anybody can recommend a good plugin? (something like fancybox/lightbox)
Upvotes: -1
Views: 4204
Reputation: 59
For some reason, none of the answers gave me fully working types for options. Here is my solution.
src/shared/ui/Fancybox.vue
<script setup lang="ts">
import { onMounted, onUnmounted, onUpdated, shallowRef } from 'vue';
import * as Fancyapps from '@fancyapps/ui';
const { Fancybox } = Fancyapps;
type FancyboxOptionsType = ConstructorParameters<typeof Fancybox>[1];
const props = defineProps<{
delegate?: string;
options?: Partial<FancyboxOptionsType>;
}>();
const { delegate = '[data-fancybox]', options = {} } = props;
const container = shallowRef(null);
onMounted(() => {
Fancybox.bind(container.value, delegate, options);
});
onUpdated(() => {
Fancybox.unbind(container.value);
Fancybox.close();
Fancybox.bind(container.value, delegate, options);
});
onUnmounted(() => Fancybox.destroy());
</script>
<template>
<div ref="container">
<slot></slot>
</div>
</template>
<style>
@import '@fancyapps/ui/dist/fancybox/fancybox.css';
</style>
src/pages/Example.vue
<template>
<Fancybox
:options="{
placeFocusBack: false,
Thumbs: {
type: 'classic',
},
}"
>
<div
v-for="(item, index) in items"
:key="item.id"
>
<a class="w-full aspect-w-16 aspect-h-9"
:href="item.src"
:data-fancybox="`gallery-${uId}`"
>
<img
class="object-cover"
:src="item.thumbSrc"
:alt="item.alt || ''"
/>
</a>
</div>
</Fancybox>
</template>
Upvotes: 0
Reputation: 448
The previous answers and the answer marked as correct are of course working, but they are not quite correct, since the proposed approaches do not provide flexibility in an application development.
When implementing a gallery, best to follow the recommendations of the library developer when using it with Vue 3.
As follows from the documentation, for the gallery to work, it is enough to simply create a wrapper for links with pictures.
For example, using Fancybox in a Vue 3 (Composition API) app with TypeScript would be:
Step one - install extension:
npm install --save @fancyapps/ui
Step two - create a Vue component with the following code:
<script setup lang="ts">
import { onMounted, onUnmounted, onUpdated, ref } from 'vue'
import type { Fancybox as FancyboxType } from '@fancyapps/ui/types'
import * as Fancyapps from '@fancyapps/ui'
const Fancybox: typeof FancyboxType = Fancyapps.Fancybox
const props = defineProps<{
options?: FancyboxType
}>()
const container = ref(null)
onMounted(() => {
Fancybox.bind(container.value, '[data-fancybox]', {
...(props.options || {}),
on: {
init: () => {
console.info('fancybox init')
},
done: (fancybox) => {
// here `fancybox` refers to the current instance
}
}
})
})
onUpdated(() => {
Fancybox.unbind(container.value)
Fancybox.close()
Fancybox.bind(container.value, '[data-fancybox]', {
...(this.options || {})
})
})
onUnmounted(() => Fancybox.destroy())
</script>
<template>
<ul ref="container">
<slot></slot>
</ul>
</template>
<style>
@import '@fancyapps/ui/dist/fancybox/fancybox.css';
</style>
Step three - we import the created component in the right place in our application, where we plan to use the gallery. And we wrap links with pictures in it, for example like this:
<Fancybox class="project-photos">
<li v-for="(photo, index) of photos" :key="index">
<a data-fancybox="group" :href="`/images/projects/${photo.projectId}/${photo.name}`">
<img :src="`/images/projects/${photo.projectId}/${photo.name}`" :alt="photo.description">
</a>
</li>
</Fancybox>
All !
Upvotes: 1
Reputation: 369
I came up with a Vue 3 component with script setup
.
First create a Fancybox.vue
file and put the code below in it:
<script setup>
import { onMounted } from 'vue'
import { Fancybox as NativeFancybox } from '@fancyapps/ui'
import '@fancyapps/ui/dist/fancybox.css'
const props = defineProps({
options: Object,
})
onMounted(() => {
const opts = props.options || {}
NativeFancybox.bind('[data-fancybox]', opts)
return () => {
NativeFancybox.destroy()
}
})
</script>
<template>
<slot />
</template>
Then, you can use it like this:
<script setup>
import { Fancybox } from './path/to/Fancybox.vue'
</script>
<template>
<Fancybox :options="{}">
<a href="./image.jpg" data-fancybox>
<img src="./image.jpg" />
</a>
</Fancybox>
</template>
Upvotes: 1
Reputation: 109
In composition API steps are really simple.
1.
<script setup>
import { Fancybox } from "@fancyapps/ui/src/Fancybox/Fancybox.js"
// Don't forget to include keys as src in you gallery since Fancybox only accepts that.
const gallery = [
{
src: "https://picsum.photos/785/501"
},
{
src: "https://picsum.photos/785/502"
},
{
src: "https://picsum.photos/785/503"
},
{
src: "https://picsum.photos/785/504"
},
{
src: "https://picsum.photos/785/505"
},
{
src: "https://picsum.photos/785/506"
},
];
const startFancy = () => Fancybox.show(gallery, {});
</script>
2.
<style lang="scss">
@import "@fancyapps/ui/dist/fancybox.css";
</style>
3.
<div v-for="item in gallery" :key="item">
<img :src="item.src" @click="startFancy" />
</div>
Upvotes: 1
Reputation: 678
I've managed to solve this with fancyapps. Since it is written in vanilla JS, I could include it in my Vue file easily. The only difference is you don't need to register it as a component.
P.S. In order to use fancyapps on page load, you will need to add the code for initialization in the activated()
lifecycle hook.
FancyboxItem.vue
First import the fancybox:
import {Fancybox} from "/@fancyapps/ui/src/Fancybox/Fancybox";
Also, css is required:
<style lang="scss" scoped>
@import "@fancyapps/ui/dist/fancybox.css";
</style>
Then in my template I've added a button with a click event.
<template>
<button id="play-button" @click="startFancy()"></button>
</template>
And in the methods, I've created a function that starts the fancybox:
methods: {
startFancy: {
var gallery = this.imgs; //your object with images
Fancybox.show(gallery, {}); //starts fancybox with the gallery object
}
}
Upvotes: 2