Search code examples
sveltesveltekit

How to hide a div element when scrolling up from any part of the page the svelte way?


I am trying to make my menu(div) appear only when the user scrolls up, so I wrote this code the svelte way, but it's not working... What am I doing wrong?

<script>
    let y;

    let newY = [];
    let oldY = newY[1];
    function updateY(y){
        newY.push(y);
         if(newY.length > 5){newY.shift()}
}
</script>
<svelte:window on:scroll ={updateY} bind:scrollY={y}/>

{#if oldY < y }
< div> ... content </div>
{/if}

Solution

  • First off:

    let newY = [];
    let oldY = newY[1];  // newY[1] is undefined
    

    oldY will not be a reference to that position, even if it was set. If you want to update oldY when newY changes you can make it a reactive statement:

    $: oldY = newY[1];  // Each time newY changes, this statement will execute
    

    Next:

    function updateY(y){      // y(Event) overshadows the locally declared and bound y(window.scrollY, a Number)
        newY.push(y);         // Is a mutation so svelte won't nofity changes
        if(newY.length > 5) {
            newY.shift();     // Again
        }
    }
    

    Mutations don't trigger reactivity, but it can be solved by simply inserting a newY=newY; statement to the end of the function. It is just a hint to the compiler that the state has changed.

    Your final solution might look something like:

    <script>
        let y;
        
        let newY = [];
        $: oldY = newY[1];
        
        function updateY(event){
            newY.push(y);
            if(newY.length > 5) {
                newY.shift();
            }
            newY=newY;
        }
    </script>
    
    <svelte:window on:scroll={updateY} bind:scrollY={y}/>
    
    {#if oldY < y }
    <h1>Test</h1>
    {/if}
                             
    <div></div>
    
    <style>
        div {
            height: 200vh;
            background-color: red;
        }
    
        h1 {
            position: fixed;
            top: 100px;
            width: 100%;
            text-align: center;
        }
    </style>