npmとかのセットアップは割愛する。
また、ぼくはDockerコンテナでLaravelを動かしている。
Homestead環境の人ならホットリロードができるらしい。調べてみるといいかも。
ビルドする
npm run dev
npm run watch
npm run prod
開発ビルドは警告やエラーがコンソールに表示される。
製品ビルドは警告がコンソールに表示されなくなる。
JavaScriptはブラウザによってしっかりとキャッシュされるので、ビルドしたらShift + Control + R
などでキャッシュ削除リロードをしてあげよう。
実行結果がビルド前と変わらなくて悲しい思いをすることになる
Vueが働きかける範囲
resources/js/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
という謎のワードが含まれている。
<!-- 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の要素を連携させるデータバインディングと呼ばれる機能がとても魅力的なフレームワークなんですって。
const app = new Vue({
el: '#app',
data: {
message: 'こんにちは'
}
});
<div id="app">
{{ message }}
</div>
<div id="app">
こんにちは
</div>
JavaScriptで変数を変更すればHTMLもそれに従って勝手に表示が切り替わるし、input要素とかに変数を割り付ければ、HTMLからの入力に従ってJavaScriptの変数の値も変わる。
<input v-model="message" placeholder="入力してください">
<p>{{ message }}</p>
テキストフィールドに入力した内容がすぐにp要素の中に反映される。すごい。
フォーム入力バインディング — Vue.js
重ねて言うことになるが、JavaScriptの変数の内容にしっかり代入されているのでJavaScript側でフォーム内容を取得するような処理をわざわざしなくていい。
何も面倒くさく無いじゃないか...!
Vue Component
HTMLタグを自作する的な気持ちでComponentなるものが作れる。
.vue
ファイルを別で作る方法をご紹介。
他にもいろいろ方法はあるらしいけど調べてない。
Componentを書く
Laravelがもとから用意してるサンプルを例にあげる。
PhpStormならファイル新規作成のとこからVue Cmponentが簡単につくれるようになってるので迷うことは無さそう。
<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つ以上親を記述してしまうとビルドが通らなくなる。
<template>
<div>
...
</div>
<div>
...
</div>
</template>
<script>
...
</script>
<template>
の中には他のVue Componentを含めることもできる
めちゃくちゃ汎用的なComponentを作れたらそれはそれで別個にしたほうが再利用性が高まるからどんどん小分けにしたほうがいいね!
vue-router
なんかを使ったSPA構築のときはページそのものをVue Componentとして記述する。
<slot>
タグ
<a
v-bind:href="url"
class="nav-link"
>
<slot></slot>
</a>
<navigation-link url="/profile">
Your Profile
</navigation-link>
<a
v-bind:href="url"
class="nav-link"
>
Your Profile
</a>
シビれるなぁ...!!
Componentを登録する
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行目ぐらいにこんなコードがある。
/**
* 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がこれまた丁寧で、とても優しい良い子です。