最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

css - How can I create a horizontal two-directional infinite scroll gallery with manual scrolling? (svelte) - Stack Overflow

programmeradmin3浏览0评论

I'm trying to build a horizontal gallery of images, that the user can manually scroll in both directions, and will show the same images over and over infinitely.

I'm using Svelte as my frontend framework with TailwindCSS to build the site.

In my current approach, when you scroll right, it continually adds photos the way I'd like more-or-less, but there is no leftward scrolling supported.

I attempted to have the gallery element start halfway scrolled (so that scrolling to the left immediately would work and I had a few images buffer to start to prepend new images), but no matter what I did the scroll value would attempt to update before the images were loaded into the gallery, resulting in a calculated scrollLeft value of 0.

How can I fix this? Any help is greatly greatly appreciated, even just resources to better understand.

<script lang='ts'>
    import Image from "$lib/image.svelte";
    import { imagesState } from "../store";
    import { onMount } from "svelte";

    let error = null;

    async function fetchImages() {
        try {
            const data = await fetch('/api/');
            if (!data.ok) throw new Error("Failed to feath images.");
            const files = await data.json();
            console.log('files:', files.tree);
            return files.tree;

        } catch (err: unknown) {
            if (err instanceof Error) {
                error = err.message;
            } else {
                error = String(err); // Handle unexpected error types
            }
        }
    }

    let gallery:HTMLElement | null = null;
    
    function handleScroll(event: Event) {
        if (Math.abs(event.deltaX) > Math.abs(event.deltaY) && Math.abs(event.deltaX) > 0) {
            scrollDirection = event.deltaX > 0 ? "right" : "left";
            console.log("Scroll direction:", scrollDirection);
        }
    }

    function observeImages() {
        const observer = new IntersectionObserver(entries => {
        entries.forEach(entry => {
            entry.target.classList.toggle('show', entry.isIntersecting)
            if (!entry.isIntersecting) return;
            console.log('entry:', entry, "type:", typeof entry)
            const clone = entry.target.cloneNode(true) as Element;
            console.log('clone:', clone)
            gallery?.append(clone);
            observer.observe(clone);
            })
        }, {
            root: gallery,
            threshold: 0.2,
        })
        if(gallery){
            for(let child of gallery.children){
                observer.observe(child);
            }
        }
    }

    onMount(async () => {
        console.log("mount");
        gallery = document.getElementById('galleryCont');
        if(gallery) {
            gallery.addEventListener('wheel', handleScroll);
            gallery.addEventListener('touchmove', handleScroll)
        }
        await imagesState.set(await fetchImages())
        observeImages();
        return () => {
            if(gallery) {
                gallery.removeEventListener('wheel', handleScroll);
                gallery.removeEventListener('touchmove', handleScroll);
            }
        }
    });


</script>

<div id="bg" class="bg-green-400 h-screen w-full flex justify-center">
    <div id="content" class="bg-red-200 w-full flex items-center">
        <div id="galleryCont" class="bg-yellow-200 w-full h-1/2 flex flex-row justify-start overflow-x-scroll overflow-y-hidden">
            {#if $imagesState}
                {#each $imagesState as image}
                    <Image imgSrc={image['path']} />
                {/each}
            {/if}
        </div>
    </div>
</div>

CSS:

.image {
    transform: translateY(300px);
    opacity: 0;
    transition: 300ms;
}

.image.show {
    transform: translateY(0px);
    opacity: 1;
}

Image Component:

<script lang="ts">
    export let imgSrc:string = ""
    export let imgAlt:string = ""
</script>

  <img src={"/images/" + imgSrc} alt={imgAlt} class="rounded-sm object-contain gallery-item image"/>

What I've Tried

I've tried programmatically removing the images from the dom after they no longer intersect and adjusting the scrollLeft value to the appropriate value, and that nearly worked but resulted in an infuriating "flashing", where the wrong image would appear in each spot for one frame, even after using tick() to ensure the state was updated before the scroll value was.

I even tried disabling all default scrolling behavior and creating my own "scroll" by removing one element and adding one element for each scroll interaction. I throttled the effect but for some reason I couldn't figure out the effect was doubled up (moving one picture further upon activation, and then again after the throttle time limit was up).

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论