Alpine.js をさわってみた（x-data編）

[Alpine.js](https://github.com/alpinejs/alpine) は、Vue.jsによく似たコードの書き方で、より簡単にリアクティブなサイトが構築できるJSフレームワークです。

今回は、`x-data` ディレクティブについての記事です。

# `x-data` ディレクティブ

`Alpine.js` の `x-data` ディレクティブは、簡単にいうと`Vue.js`の `dataプロパティ` のようなものです。`x-data` デレクティブにオブジェクトリテラルを書き込むと、書き込んだ要素およびその子要素でオブジェクトデータが使えるようになります。

```html:例１
<!-- flowerプロパティの値を'yuri'とする -->
<div x-data="{ flower: 'yuri' }">

  <!-- x-data のオブジェクトデータを x-text="プロパティ名" で表示する -->
  <div x-text="flower"></div>
</div>
```

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="masahiro111" data-slug-hash="zYKbaRZ" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="zYKbaRZ">
  <span>See the Pen <a href="https://codepen.io/masahiro111/pen/zYKbaRZ">
  zYKbaRZ</a> by Masahiro (<a href="https://codepen.io/masahiro111">@masahiro111</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>

---

ちなみに、`x-text` デレクティブを書く場所が、`x-data` を書いた要素の外だった場合は、その `x-data` のオブジェクトデータを参照することができません。

```html:例２
<div>
 <!-- flowerプロパティの値を'himawari'とする -->
 <div x-data="{ flower: 'himawari' }">
   <!-- x-data のオブジェクトデータがある要素内であるため参照できる -->
   <p>x-dataのある要素内</p>
   <div x-text="flower"></div>
 </div>
 <!-- x-data のオブジェクトデータがある要素外であるため参照できない -->
  <hr>
  <p>x-dataのある要素の外側</p>
 <div x-text="flower"></div>
</div>
```

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="masahiro111" data-slug-hash="wvzOXmL" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="wvzOXmL">
  <span>See the Pen <a href="https://codepen.io/masahiro111/pen/wvzOXmL">
  wvzOXmL</a> by Masahiro (<a href="https://codepen.io/masahiro111">@masahiro111</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>

---

複数のプロパティをカンマで区切って記述できます。

```html:例３
 <!-- 複数のプロパティ -->
 <div x-data="{ flower: 'himawari', season: 'summer' }">
   flower: <div x-text="flower"></div>
   season: <div x-text="season"></div>
 </div>
```

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="masahiro111" data-slug-hash="YzGgvvj" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="YzGgvvj">
  <span>See the Pen <a href="https://codepen.io/masahiro111/pen/YzGgvvj">
  YzGgvvj</a> by Masahiro (<a href="https://codepen.io/masahiro111">@masahiro111</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>

---

入れ子にすると注意が必要

```html:例４
<!-- 入れ子 -->
<div x-data="{ flower: 'himawari' }">
  <div x-data="{ season: 'summer' }">

    <!-- 入れ子にするとflowerプロパティが参照できなくなってしまう -->
    flower: <div x-text="flower"></div>
  </div>
</div>
```

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="masahiro111" data-slug-hash="dypaeYX" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="dypaeYX">
  <span>See the Pen <a href="https://codepen.io/masahiro111/pen/dypaeYX">
  dypaeYX</a> by Masahiro (<a href="https://codepen.io/masahiro111">@masahiro111</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>

---

`x-data` はデータと動作を繰り返し利用できる関数に抽出することができる。![Alpine.js](https://github.com/alpinejs/alpine) の日本語ドキュメントのドロップダウンの例を参考に、どういった動作をしているのかを追ってみた。

```html:例５
<div x-data="dropdown()">
    <button x-on:click="open()">オープン</button>

    <div x-show="isOpen()" x-on:click.away="close()">
       <p>ボタンもしくは、ボタンの外をクリックすると閉じます</p>
    </div>
</div>

<script>
    function dropdown() {
        return {
            show: false,
            open() { this.show = true },
            close() { this.show = false },
            isOpen() { return this.show === true },
        }
    }
</script>
```

1行目の `x-data="dropdown()"` のところで新しいコンポーネントスコープを宣言しています。`x-data`の関数は、`<script>`タグで定義されている`dropdown()`を呼び出しています。`dropdown` 関数を見てみると、

```js
    function dropdown() {
        return {
            // オブジェクトデータ
        }
    }
```

となっていて、オブジェクトデータの部分に `プロパティ＆値`を入れたり、さらに関数を定義できたりします。

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="masahiro111" data-slug-hash="ExgMqea" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="ExgMqea">
  <span>See the Pen <a href="https://codepen.io/masahiro111/pen/ExgMqea">
  ExgMqea</a> by Masahiro (<a href="https://codepen.io/masahiro111">@masahiro111</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>