暑さが一段と厳しくなってまいりましたが、皆さまいかがお過ごしでしょうか。
こんな日は冷えっ冷えのぶっかけうどんを食べたいですね、香川出身マークアップエンジニアHAYです。
今回は最近使い始めたJSフレームワークAlpine.jsについて紹介したいと思います。
Alpine.jsは、「ちょっとした動き」をHTMLに加えたいときに適した軽量なJavaScriptフレームワークです。
特に次の点がナイスなポイントです。
Alpine.jsでは、「ディレクティブ」と呼ばれる専用のHTML属性を使って、さまざまな動きを加えます。
HTMLに「x-」から始まる属性を加えるだけで、機能が組み込めるのが特徴です。
ディレクティブ | 説明 |
---|---|
x-data | コンポーネントごとにデータを定義 |
x-bind | HTMLの属性にデータ等を結びつける |
x-on | イベントの監視(クリックなど) |
x-text | テキストコンテンツの設定 |
x-html | 内部HTMLの設定 |
x-model | データとフォーム入力の双方向同期 |
x-show | 要素の表示・非表示切り替え |
x-transition | アニメーションの追加 |
x-for | 繰り返し処理 |
x-if | 条件による要素の追加・削除 |
x-init | 初期化時に一度だけ実行 |
x-effect | データ変更時に処理を実行 |
x-ref | 要素への参照 |
x-cloak | 初期化完了まで非表示(ちらつき防止) |
x-ignore | Alpineによる初期化を無効化 |
これらのディレクティブを実際にどう使うのか、具体的なデモを見ていきましょう。
※ スタイルにはTailwind CSSを使っていますが、Alpine.js自体とは切り離して考えていただいて大丈夫です。
リンクをクリックすると、該当セクションまでスムーズにスクロールする機能です。JavaScriptで書くと少し面倒な処理も、Alpine.jsならHTMLにちょっと書き足すだけで済みます。
<div x-data="{
scrollTo(id) {
const el = document.querySelector(id);
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}">
x-data は、Alpine.jsのコンポーネントを宣言し、その中で利用できるデータや関数を定義する場所です。ここではscrollTo(id)という関数を定義しています。
この関数は、引数としてID(例:'#section1')を受け取り、そのIDを持つ要素をページ内から探し出して、scrollIntoView()で画面の先頭まで滑らかにスクロールさせます。
<a href="#section1" x-on:click.prevent="scrollTo('#section1')"> ... </a>
x-on属性はイベントを監視するディレクティブで、x-on:clickでクリックイベントを監視します(なお、x-on:eventNameは@eventNameと書き換えることも可能です)。
aタグに付けられた @click.prevent は、「クリックされた時」の動作を指示しています。
.preventは、aタグが本来持っている「指定された場所に一瞬でジャンプする」という動きをキャンセル(prevent)しています。
="scrollTo('#section1')" の部分で、先ほどx-dataで定義したscrollTo関数を呼び出し、引数としてスクロールさせたいセクションのIDを渡しています。
この組み合わせだけで、シンプルなスクロール機能が実現できます。
「同意する」にチェックを入れたら送信ボタンが押せるようになる、よくあるフォーム機能も簡単に作れます。
<div x-data="{ agreed: false }" ...>
agreedという名前の変数を作成し、その初期値をfalseに設定しています。
<input
x-model="agreed"
type="checkbox"
...>
x-modelは、フォームの入力要素(true/false)とx-dataで定義した変数agreedを双方向で結びつけます。これにより、チェックボックスの状態(チェックあり/なし)と、Alpine.jsが管理している変数agreedを自動的に同期させます。
初期状態ではagreedにはfalseが入っていますが、ユーザーがcheckboxにチェックを入れると、agreedの値が自動的にtrueに変わります。
<button x-bind:disabled="!agreed">
x-bind:は、HTMLの属性(ここではdisabled属性)に動的な値を設定するためのディレクティブです(なお、x-bind:attributeNameは「x-bind」を略して:attributeNameと書くこともできます)。
x-bind:disabled="true"となるとdisabled属性が有効になります。ここではdisabled="!agreed"なので、「agreed変数がfalseの時にdisabled属性を有効にする」という意味です。つまり、チェックボックスがチェックされるとagreedがtrueになりボタンの無効化が解除されます。
「次へ」を押すたびに、セクションが順番に表示されていくUIです。表示/非表示やボタンの制御を、shown という1つの変数だけで管理できるのがポイントです。
<div x-data="{ shown: 1 }" ...>
このshown変数に入れる数値によって、表示する要素を変化させていきます。
<button @click="if (shown < 4) shown++" >
ボタンをクリックする度にshownの値を1ずつ増やします。上限はセッション数の4です。
<section x-show="shown >= 1" x-transition x-cloak ...>
各セクションにx-showを付与し、shownの値に基づいて表示・非表示を切り替えます。例えばshownが2の時は、shown >= 1 と shown >= 2 の条件がtrueになるため、セクション1と2が表示されます。
x-transitionはx-showと組み合わせることで、セクションが表示される際に滑らかなアニメーション効果を加えます。
x-transitionのデフォルトはフェードアウトおよびスケールを150ミリ秒のtransitionで行います。durationやプロパティを変更する場合はx-transition.opacity.duration.500msと後ろに追加していきます。
さらに、x-cloakを付与することで「ちらつき」を防止します。x-cloakはAlpine.jsの準備が整うまで要素を非表示にし、ページの読み込み時に一瞬すべてのセクションが見えてしまう現象を防ぎます。
動作させるには
[x-cloak] { display: none !important; }
をCSSに追加します。
<span x-text="shown"></span>
x-textは値をテキストとして表示します。shown変数が増加すると、x-text内のテキスト(数値)も増加して表示されます。
<div x-bind:style="`width: ${(shown / 4) * 100}%`" ...>
shownの数値に合わせてwidthの幅を変えています。
【補足】ここではstyle属性を直接書き換えていますが、x-bind:classを使えばTailwind CSSのクラスを動的に付け替えることも可能です。ただし、Tailwind CSSでw-[25%]のような任意値を使う場合、ビルド時にクラスが生成されていないと適用されない可能性があるため、style属性でインラインで書く方が安全だと思います。
<button x-bind:disabled="shown === 4">
<span x-show="shown < 4">次のセクションを表示</span>
<span x-show="shown === 4">全てのセクションを表示しました</span>
</button>
x-bindによって、shown変数が4になると同時にボタンを無効化(disabled)します。 ボタン内のテキストも、shown変数が4になると「全てのセクションを表示しました」に切り替わります。
Alpine.jsは、HTMLの中にそっと機能を足していく感覚で、UIのちょっとした動きを実装できるツールです。
この基本的な流れを覚えるだけで、多くのUIをHTML上ですっきりと宣言的に記述できるようになります。
「そこまで重い仕組みはいらないけど、もう少し便利にしたいな」という場面で、気軽に試せる選択肢だと感じました。
ご興味があれば、ぜひ触ってみてください。