Laravelから触るVue.js 知見まとめ

npmとかのセットアップは割愛する。

また、ぼくはDockerコンテナでLaravelを動かしている。
Homestead環境の人ならホットリロードができるらしい。調べてみるといいかも。

# ビルドする

```shell:開発ビルド
npm run dev
```

```shell:変更を監視して自動ビルド
npm run watch
```

```shell:製品ビルド
npm run prod
```

開発ビルドは警告やエラーがコンソールに表示される。
製品ビルドは警告がコンソールに表示されなくなる。

JavaScriptはブラウザによってしっかりとキャッシュされるので、**ビルドしたら`Shift + Control + R`などでキャッシュ削除リロードをしてあげよう。**

実行結果がビルド前と変わらなくて悲しい思いをすることになる :scream: 

# Vueが働きかける範囲
`resources/js/app.js`に記述されているこのコードで決まってる。

```javascript:app.js
const app = new Vue({
    el: '#app'
});
```

初期状態ではHTMLタグのidがappの中でのみVue.jsが働きかけるようになっている。
Laravelが自動で生成した`app.blade.php`には`<body>`のすぐ中に`<div id="app">`があり、**ほとんどの要素や継承したBladeテンプレートに対して働きかけるように最初からなっている。**

特にいじらなくてよろし。

## app.jsが読み込まれるタイミング
`app.js`を読み込むコードに`defer`という謎のワードが含まれている。

```html
    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>
```

これは**HTMLの読み込みと同時に非同期でJavaScriptも読み込んじゃって、HTMLの解析後にこのスクリプトを実行するという記述**。
そのため、`app.js`の実行より先に`app.blade.php`やこれを継承するBladeテンプレート内に別個で記述したJavaScriptが実行されてしまうので、Vue.jsを始めとするライブラリがなにも使えない。

また、`defer`などをつけた`<script>`タグの読み込みや解析の順番が毎回同じである保証は無いので、別ファイルで読み込ませるとかじゃなく、`resources/js/app.js`に記述するかVue ComponentにJavaScriptを書いて、**ビルドした結果`public/js/app.js`にまとめられるようにすべきであろう**。

すなわち**BladeテンプレートにJavaScriptを書くんじゃねぇ**ってことなのかなって。

# データバインディング
Vue.jsは変数とViewの要素を連携させる**データバインディング**と呼ばれる機能がとても魅力的なフレームワークなんですって。

```javascript
const app = new Vue({
    el: '#app',
    data: {
        message: 'こんにちは'
    }
});
```

```html
<div id="app">
    {{ message }}
</div>
```

```html:実行結果
<div id="app">
    こんにちは
</div>
```

---

JavaScriptで変数を変更すればHTMLもそれに従って勝手に表示が切り替わるし、input要素とかに変数を割り付ければ、HTMLからの入力に従ってJavaScriptの変数の値も変わる。

```html
<input v-model="message" placeholder="入力してください">
<p>{{ message }}</p>
```

テキストフィールドに入力した内容がすぐにp要素の中に反映される。すごい。
[フォーム入力バインディング — Vue.js](https://jp.vuejs.org/v2/guide/forms.html)

重ねて言うことになるが、JavaScriptの変数の内容にしっかり代入されているので**JavaScript側でフォーム内容を取得するような処理をわざわざしなくていい**。
何も面倒くさく無いじゃないか...！

# Vue Component
HTMLタグを自作する的な気持ちで**Component**なるものが作れる。
`.vue`ファイルを別で作る方法をご紹介。

他にもいろいろ方法はあるらしいけど調べてない。

## Componentを書く
Laravelがもとから用意してるサンプルを例にあげる。
PhpStormならファイル新規作成のとこからVue Cmponentが簡単につくれるようになってるので迷うことは無さそう。

```vue:ExampleComponent.vue
<template>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Example Component</div>

                    <div class="card-body">
                        I'm an example component.
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        mounted() {
            console.log('Component mounted.')
        }
    }
</script>
```

`<template>`タグ内は親要素をひとつのみ記述する。
**2つ以上親を記述してしまうとビルドが通らなくなる。**

```vue:エラーになる例
<template>
    <div>
       ...
    </div>

    <div>
       ...
    </div>
</template>

<script>
    ...
</script>
```

### `<template>`の中には他のVue Componentを含めることもできる

めちゃくちゃ汎用的なComponentを作れたらそれはそれで別個にしたほうが再利用性が高まるからどんどん小分けにしたほうがいいね！

`vue-router`なんかを使ったSPA構築のときはページそのものをVue Componentとして記述する。

### `<slot>`タグ

```html:VueComponent
<a
  v-bind:href="url"
  class="nav-link"
>
  <slot></slot>
</a>
```

```html:HTML
<navigation-link url="/profile">
  Your Profile
</navigation-link>
``` 

```html:レンダリング結果
<a
  v-bind:href="url"
  class="nav-link"
>
  Your Profile
</a>
```

シビれるなぁ...！！

## Componentを登録する

```javascript:resources/js/app.js
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
```

`require()`には`.vue`のある相対パスを書いてあげる。

npmなどで導入したComponentなら`Vue.use(/* なんかインポートしたときの名前 */);`する。
ものによっては`Vue.component()`で登録せにゃならんのもあるのでUsageを確認するのが吉。

こうすることでHTMLに`<example-component></example-component>`って書くと、Componentがバッと展開されるようになる。

### Component全部を勝手に登録してもらうこともできる
`resource/js/app.js`の20行目ぐらいにこんなコードがある。

```javascript
/**
 * The following block of code may be used to automatically register your
 * Vue components. It will recursively scan this directory for the Vue
 * components and automatically register them with their "basename".
 *
 * Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
 */

// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
```

Docsコメントに記されている通りだが、コメントアウトされている最後の2行を使うことで**`resource/js/`配下の`.vue`ファイルすベてを勝手にComponentとして登録してくれる。**
その際、ファイル名をPascalCaseであるとして、HTMLからケバブケースで指定することで使えるようになる。

> `Eg. ./components/ExampleComponent.vue -> <example-component></example-component>`

便利だね！

# 触感まとめ

Vue.jsはjavascriptやjQueryでのDOM操作に苦労しまくった人がそれをめちゃくちゃ楽にやるためにつくったフレームワークって感じがした。

チェックボックスのチェックも変数を使って双方向データバインディング、CSSだってbool型変数と連携させクラスを付けたり消したり...
変数を変更すると意識せずともHTMLに即時反映されるから意識することが大幅に減ってとても楽に操作できて良いな...って思いました。

また、とてもナチュラルにHTMLとJavaScriptをセットで書けるからJavaScript書かなきゃな...って気持ちにならなくなりました。
これは良いものだ...！

日本語Docsがこれまた丁寧で、とても優しい良い子です。

# 参考
[はじめに — Vue.js](https://jp.vuejs.org/v2/guide/index.html)