profile
西村 祐真
@variant3a
Alpine.jsでScroll Spyを実装する
calendar_today
2023-01-22
insights
views: 257
thumbnail images

Alpine.jsでScroll Spy機能を実装する方法が他のサイトになかったため、自分で実装してみた。
なお、ParserはCommonmarkを使用しているため、ヘッダーの出力結果が異なる場合がある。

環境

  • Laravel 9.x
  • Livewire 2.x
  • TailwindCSS 3
  • Alpine.js 3
  • Commonmark

コード

<!-- Anchor link list -->
<div class="hidden row-auto p-2 mb-1 space-y-1 font-mono bg-white rounded shadow md:block sm:mb-3 dark:bg-zinc-700 ring-1 ring-black/5"
    x-data="{ position: '', links: document.querySelectorAll(`[id^='content-']`) }">  
    <template x-for="link in links">
        <a class="flex justify-between w-full p-1 break-all rounded hover:bg-teal-500/50 text-neutral-700 dark:text-neutral-200 hover:text-white first:rounded-t last:rounded-b"
             x-bind:href="`#${link.id}`"
             x-bind:key="link.id"
             x-text="link.parentElement.innerText"
             x-on:scroll.window="position = [...links].filter(v => v.getBoundingClientRect().top > 0)[0].id"
             x-bind:class="{ 'bg-teal-500/50 text-white': position === link.id }"
             data-turbo="false">
        </a>
    </template>
</div>

<!-- Contents -->
<div class="markdown">
    <h2>
        <a id="content-1-Header" href="#content-1-Header" class="heading-permalink" aria-hidden="true" title="Permalink"></a>
        1. Header
    </h2>
</div>

説明

  1. x-dataでコンテンツ側からヘッダーのidを取得する
  2. <template>タグでforeachで回す
  3. x-bind:hrefでヘッダーのidのリンクを作成する
  4. x-textでヘッダーのテキストを取得する
  5. x-on:scroll.windowでwindowがscrollした時に、ヘッダー表示位置が一番高い(= top > 0)ものを絞り込み、最初の(= 一番上の)elementのidを取得する
  6. x-bind:classで一番上のヘッダーが現在のリンクなら、スタイルを設定する

注意

環境でhotwired/turboを使用している場合、アンカーリンクが効かない場合がある。その場合はdata-turbo="false"を設定しよう。

calendar_today
2023-01-22
insights
views: 257