feat: update RefGallery to native scrolling
This commit is contained in:
parent
c77854667b
commit
d84c415b22
1 changed files with 58 additions and 13 deletions
|
@ -1,30 +1,64 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
|
import { debounce } from "@/helpers";
|
||||||
|
|
||||||
const activeImage = ref(0);
|
const activeImage = ref(0);
|
||||||
const images = ref<Array<Element>>([]);
|
const images = ref<Array<Element>>([]);
|
||||||
|
const element = document.createElement("div");
|
||||||
|
const galleryViewport = ref<HTMLElement>(element);
|
||||||
|
const galleryItemWidth = ref<number>(1);
|
||||||
|
|
||||||
const offset = computed(() => `margin-left: -${activeImage.value * 100}%`);
|
const resizeObserverCallback = (entries: Array<ResizeObserverEntry>): void => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
galleryItemWidth.value = entry.contentRect.width;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const setActive = (index: number) => {
|
const resizeObserver = new ResizeObserver(
|
||||||
|
debounce(resizeObserverCallback, 1000)
|
||||||
|
);
|
||||||
|
|
||||||
|
const setActiveImage = (index: number): void => {
|
||||||
activeImage.value = index;
|
activeImage.value = index;
|
||||||
|
galleryViewport.value.scrollTo({
|
||||||
|
left: galleryItemWidth.value * index,
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
};
|
};
|
||||||
const prev = () => {
|
|
||||||
|
const getActiveImage = (gallery: HTMLElement, itemWidth: number): number => {
|
||||||
|
return gallery.scrollLeft / itemWidth;
|
||||||
|
};
|
||||||
|
|
||||||
|
const prev = (): void => {
|
||||||
if (activeImage.value > 0) {
|
if (activeImage.value > 0) {
|
||||||
activeImage.value -= 1;
|
galleryViewport.value.scrollBy({
|
||||||
|
left: galleryItemWidth.value * -1,
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const next = () => {
|
|
||||||
|
const next = (): void => {
|
||||||
if (activeImage.value < images.value.length - 1) {
|
if (activeImage.value < images.value.length - 1) {
|
||||||
activeImage.value += 1;
|
galleryViewport.value.scrollBy({
|
||||||
|
left: galleryItemWidth.value,
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onScroll = (): void => {
|
||||||
|
const newImg = getActiveImage(galleryViewport.value, galleryItemWidth.value);
|
||||||
|
setActiveImage(newImg);
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const sel = ".gallery__viewport .figure";
|
resizeObserver.observe(galleryViewport.value);
|
||||||
const elements = document.querySelectorAll(sel);
|
images.value = Array.from(galleryViewport.value.children);
|
||||||
const imageArray = Array.from(elements);
|
galleryItemWidth.value =
|
||||||
images.value = imageArray;
|
galleryViewport.value.scrollWidth / images.value.length;
|
||||||
|
galleryViewport.value.addEventListener("scroll", debounce(onScroll, 100));
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -44,7 +78,7 @@ onMounted(() => {
|
||||||
v-show="activeImage < images.length - 1"
|
v-show="activeImage < images.length - 1"
|
||||||
></a>
|
></a>
|
||||||
|
|
||||||
<div class="gallery__viewport" :style="offset">
|
<div class="gallery__viewport" ref="galleryViewport">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -55,7 +89,7 @@ onMounted(() => {
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
:class="{ active: activeImage === idx }"
|
:class="{ active: activeImage === idx }"
|
||||||
@click.prevent="setActive(idx)"
|
@click.prevent="setActiveImage(idx)"
|
||||||
></a>
|
></a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -105,7 +139,16 @@ onMounted(() => {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
|
scroll-snap-type: x mandatory;
|
||||||
|
|
||||||
|
scrollbar-width: none;
|
||||||
|
|
||||||
transition: 0.3s all ease-in-out;
|
transition: 0.3s all ease-in-out;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.figure {
|
.figure {
|
||||||
|
@ -113,6 +156,8 @@ onMounted(() => {
|
||||||
padding: var(--gallery-image-padding);
|
padding: var(--gallery-image-padding);
|
||||||
flex: 1 0 100%;
|
flex: 1 0 100%;
|
||||||
|
|
||||||
|
scroll-snap-align: center;
|
||||||
|
|
||||||
&__meta {
|
&__meta {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue