13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Alpine.jsでデータバインディング

Last updated at Posted at 2021-01-23

2021/10/20
3系がリリースされていたので、サンプルコード及び記事の修正を行いました。

はじめに

最近、Alpine.jsというライブラリを知りました。
Vue.jsに影響を受けているようで書き心地は似ているのですが、データバインディングに特化していてVue.jsよりも軽量なので、SPA用途でなくデータバインディング用途でVue.jsを使用しているという場合は、代替になり得ると感じました。
 →当時はなかったのですが最近はpetite-vueというライブラリが開発されているので、Vue.jsの代替という意味では現在はそちらを使う方が良さそうです。

Vue.jsと比較すると以下の点でメリットがあると感じます。

  1. 軽量
  2. データオブジェクトを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の処理も直感的に感じます。

今後、画面の一部でデータバインディングを使用したくなった際は、積極的に採用してみたいですね。

13
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?