jQueryをAlpine.jsに置き換える小ネタ

jQueryをAlpine.jsに置き換える小ネタ

皆様こんにちは。塩田です。

今回はjQueryで実装していたエフェクト等をAlpine.jsに置き換えていくための小ネタを紹介いたします。

場合によってはまだまだ需要の高いjQueryですが、互換性や再利用性などの問題で利用を制限するケースも出てきています。

そんな時にAlpine.jsで同じことができれば非常に開発がスムーズに進みます。今まで何となくjQueryで作っていたものを今一度見直してみてはいかがでしょうか?

なおAlpine.jsについては過去にも記事を投稿しておりますので参考にしてください。

今回のテーマ

今回はタブによって表示が変わるアレをテーマにしたいと思います。

※スタイリングにはTailwindを使っていますので予めご了承ください。

jQueryを使った場合

See the Pen Untitled by shiota (@shioweb) on CodePen.

Alpine.jsを使った場合

See the Pen Untitled by shiota (@shioweb) on CodePen.

どうでしょうか?

JQueryは当然ながらJSをそれなりに書いていますが、Alpine.jsについてはインラインで完結しています。同一ファイル内で処理が完結するということは、再利用性やメンテナンスの観点からも非常に重要だと思います。

念のためAlpine.jsでの基本的な動きを説明しておくと、

x-data="{activeIndex: 0, hoverIndex: null}"

これが大元のプロパティとなります。 基本的にはここの値が変わる(変える)ことにより処理が行われていきます。

ではどこでx-dataの値を変えているのかというと以下になります。

 @click="activeIndex = 0"
 @mouseenter="hoverIndex = 0" @mouseleave="hoverIndex = null" 

見て大体おわかりだと思うのですが、”@click”でクリックされた要素のidを”activeIndex”に代入しています。また”@mouseenter”や”@mouseleave”でも同様に値の代入処理をおこなっています。

jQueryだと場合によってはこのあたりの参照がやや複雑になってきますので、直接要素を指定できるのは大きなメリットといえます。

元のコード

因みに下記が元のコードです。bladeテンプレート(Laravel)でループを使っているので若干コードが整理されていると思います。

<section class="mb-16 md:mb-36" x-data="{activeIndex:0,hoverIndex : null}">
    <div class="container px-8 lg:px-0 max-w-[850px] mx-auto">
      <div class="relative mb-16 md:mb-24 wow fadeInUp" data-wow-delay="0.2s">
        <h1 class="ttext-3xl md:text-4xl text-center pt-2 tracking-widest mb-8 md:mb-16">
募集要項
</h1>
      </div>
      <ul class="flex flex-col md:flex-row justify-center gap-y-8 md:gap-2 lg:gap-8 items-center mb-8 wow fadeInUp"
          data-wow-delay="0.4s">
        @foreach($jobs as $key => $job)
          <li
            @click="activeIndex = {{$loop->index}}"
            @mouseenter="hoverIndex =  {{$loop->index}}"
            @mouseleave="hoverIndex = null"
            :class="{
        'opacity-100': activeIndex === {{$loop->index}} || hoverIndex === {{$loop->index}},
        'opacity-50': activeIndex !== {{$loop->index}} && hoverIndex !== {{$loop->index}},
        'selected': activeIndex === {{$loop->index}}
    }"
            class="w-full md:w-1/3 text-center text-main-blue border-b border-main-blue cursor-pointer relative">
            <h3 class="pb-4">{{$job}}</h3>
          </li>
        @endforeach
      </ul>
      <div class="wow fadeInUp" data-wow-delay="1s">
        @foreach($requirement as $key => $detail)
          @if($key === 'job1')
            <dl class="leading-8 mb-16"
                x-show="activeIndex === {{$loop->index}}"
                x-transition:enter="transition ease-out duration-300"
                x-transition:enter-start="opacity-0"
                x-transition:enter-end="opacity-100">
              @foreach($detail as $job_desc)
                @foreach($job_desc as $k => $v)
                  <div class="py-4 md:py-8 border-b border-black flex flex-col md:flex-row items-center">
                    <dt class="w-full md:w-1/5 text-main-blue">{!! $k !!}</dt>
                    <dd class="w-full md:w-4/5">{!! $v !!}</dd>
                  </div>
                @endforeach
              @endforeach
            </dl>
          @else
            <div x-show="activeIndex === {{$loop->index}}"
                 x-transition:enter="transition ease-out duration-300"
                 x-transition:enter-start="opacity-0"
                 x-transition:enter-end="opacity-100"
            class="py-16">
              <p class="text-center text-xl md:text-2xl">現在募集しておりません。</p>
            </div>
          @endif
        @endforeach
      </div>
    </div>
  </section>

最後に

いかがでしたでしょうか?これまでご紹介したAlpine.jsの特徴を考えれば生産性はかなり上がると思います。もちろんjQueryを使ったほうが効率的なケースもありますが、Vue.jsやreactなどへの移行も考える場合、Alpine.jsを使用してコンポーネント化の手法を取り入れていくほうが得策だと思います。

最後までお読みいただきましてありがとうございました。