Alpine.js やる
高校の卒業研究でWebアプリを作っている。技術について学習コストを考慮に入れるのはあまり好きではないのだが、メンバーの環境にBabelをセットアップしたりするのがあまりやりたくないという気持ちがあり、HTMLにテンプレート書いてライブラリを読み込めばサクッと動くというようなものが欲しい。
個人的にはReactでJSXを使って式をガチャガチャするのが好きなのだが、ライブラリ直に読み込むような場面ではJSXが使えずReact.createElement
を手書きすることになって心が温まるのであまり向いていないと思う。そこでVueやAlpineはHTMLにテンプレート書いてライブラリ読み込んで<script>
にふるまい書けば動くっぽそうなのでそれを使ってみたいなあという気がしています。ゆえにAlpineをやる。
とりあえず開発サーバーはどうしても必要になってしまう。@web/dev-server
に全幅の信頼を置いている。
"name": "alpine-de-asobu",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "web-dev-server --watch --root-dir dist/"
},
"license": "CC0",
"devDependencies": {
"@web/dev-server": "^0.1.24",
"prettier": "^2.4.1"
}
}
Alpine本体をCDNから入れた方がいいか、npmから入れてしまうかには考える余地があるかも。
を参考にしようと思ったがImport mapsがChromeにしか載っていなくてかなしくなった。
ふむ。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Alpine test</title>
<script
defer
src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"
></script>
</head>
<body>
<script type="module"></script>
<h1 x-data="{ message: 'Hello Alpine.js!' }" x-text="message"></h1>
</body>
</html>
インテリセンスあるとはいえちょっと文字列ベタ書きはあまりうれしくない。
Alpine公式サイトにはちゃんとシンタックスハイライト効いてるのずるい。おれのVSCodeにもくれ。
x-data="{ count:0 }"
とするとその要素以下のディレクティブでcount
が使えるようになる。count
が変更されるとそれを使っているディレクティブみんな反映される。
x-on:click="count++"
とするとその要素がクリックされたとき count++
する。この count
は上で定義したやつ。省略形として @click="count++"
と書くこともできる。
x-text="count"
と書くとJavaScript式を評価した結果がその要素の子のテキストノードになる。
<div x-data="{ open: false }">
<button @click="open = !open">Toggle</button>
<div x-show="open" @click.outside="open = false">hidden content</div>
</div>
x-show="expr"
とするとexprがtrueのとき表示、falseのとき非表示。ずいぶん高レイヤーな機能だ。
@click.outside
とすると その要素の外側をクリックしたときのイベントを使える。すげえ。
getterを使う例。
<div
x-data="{
search: '',
items: ['foo', 'bar', 'baz'],
get filteredItems () {
return this.items.filter(item => item.startsWith(this.search))
}
}"
>
<input x-model="search" placeholder="search..." />
<ul>
<template x-for="item in filteredItems" :key="item">
<li x-text="item"></li>
</template>
</ul>
</div>
<input x-model="search">
とするとsearchとinputの双方向バインディングができる。
Vueでいうcomputed propertyをgetterでやっている。
<template x-for="束縛する変数 in 配列">
でループできる。 <template>
を使うのが面白い。
<template x-for="item in filteredItems" :key="item">
<li x-text="item"></li>
</template>