2021/10/20
3系がリリースされていたので、サンプルコード及び記事の修正を行いました。
はじめに
最近、Alpine.jsというライブラリを知りました。
Vue.jsに影響を受けているようで書き心地は似ているのですが、データバインディングに特化していてVue.jsよりも軽量なので、SPA用途でなくデータバインディング用途でVue.jsを使用しているという場合は、代替になり得ると感じました。
→当時はなかったのですが最近はpetite-vueというライブラリが開発されているので、Vue.jsの代替という意味では現在はそちらを使う方が良さそうです。
Vue.jsと比較すると以下の点でメリットがあると感じます。
- 軽量
- データオブジェクトをPOJOで定義できるので、thisのコンテキストが明確
→こちらもVue.js本体と比較したらの話なので、現在はpetite-vueと比較する方が良いですね。
試してみる
Alpine.jsは「HTMLに属性値としてJavaScriptが書ける」ことを強みにしており、属性値で書くパターンとscriptタグで分けて書くパターンがありますが、今回はscriptタグで分けて書く場合にフォーカスを絞って、サンプルを紹介できたらと思います。
サンプルコード
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Alpine.js Sample</title>
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
<style>
/*
Alpine.jsの初期化が終わるとx-cloak属性が削除される。つまり、x-cloak属性にdisplay:noneを
定義すると、x-cloak属性を持つタグは初期化が終わるまで非表示になり、画面のちらつきを抑えられる。
*/
[x-cloak] {
display: none
}
</style>
</head>
<body>
<!-- データバインディングしたいタグをx-data属性で定義 -->
<div x-data="app" x-cloak>
<!-- Vue.jsと違いinnerTextの定義に {{ hoge }} が使えないため、x-text属性に定義する -->
<h1 x-text="`Hello, ${fullname}!`"></h1>
<h3 class="js_subtitle"></h3>
<p x-text="`2way-binding: ${inputValue}`"></p>
<!-- x-on:eventは@eventで省略可能 preventなどのmodifierも使用できる -->
<form @submit.prevent="handleSubmit">
<!-- x-modelによる双方向バインディングも使用可能 -->
<input type="text" x-model="inputValue">
<input type="submit" value="Submit">
</form>
</div>
<script>
const app = () => ({
// プロパティはそのままリアクティブになる
// Vue.jsにおけるdataオブジェクトに相当
firstName: 'Taro',
lastName: 'Tanaka',
inputValue: '',
// Vue.jsにおけるcomputedオブジェクトに相当
get fullname() {
return `${this.firstName} ${this.lastName}`;
},
// Vue.jsにおけるmethodsオブジェクトは、そのままメソッドとして書ける
init() {
// initメソッドはマウント後に実行される
console.log('Initialize');
// コンポーネント内のDOMを掴みたいときはthis.$elで参照できる
this.$el.querySelector('.js_subtitle').textContent = 'This is manual binding.';
// プロパティの変更を監視したい場合は、this.$watchのコールバックで定義できる
// Vue.jsのwatchオブジェクトに相当
this.$watch('inputValue', (currentValue) => {
console.log(`updated inputValue: ${currentValue}`);
});
},
handleSubmit() {
console.log(`submited with inputValue: ${this.inputValue}`);
this.inputValue = '';
}
});
// Alpine.jsの初期化終了時にバインディング処理を実行する
document.addEventListener('alpine:init', () => {
// x-data="app" に対してバインディング
Alpine.data('app', app);
});
</script>
</body>
</html>
x-ifやx-forをtemplateタグ内に書く必要があったりと、Vue.jsと微妙に違う点がいくつかありますが、この例をベースにドキュメントを読み進んで頂ければ、理解の助けになるかと思います。
良いと思った点
Vue.jsと違いデータオブジェクトがプレーンなので、thisのコンテキストをエディタが推論可能になります。
今回はVSCodeを使用して書きましたが、拡張機能の追加なしにthisのプロパティやメソッドが推論されるのは良いですね。
メソッドがそのまま定義できますし、ゲッターを使用したcomputedの処理も直感的に感じます。
今後、画面の一部でデータバインディングを使用したくなった際は、積極的に採用してみたいですね。