Webサイトをよりアプリっぽくするために
Vue.jsを試してみます。
開発環境
使用ツール名 | バージョン |
---|---|
Laravel | 5.7.14 |
Vue.js | 2.5.17 |
Homestead | 6.6.0 |
やること
- CDN版で試す
- NPMで試す
- 単一ファイルコンポーネント
とりあえず10分くらいで試したい場合
Vue.js公式が優しいので参考にしながら。
CDNから引っ張ってきてやるのが簡単です。
HelloWorld
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p>@{{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
});
</script>
</body>
</html>
blade使っている場合、二重中括弧の前に@付けないと正常に表示されません。
ルーティング
公式のサンプルを先程のHelloWorldに合体させます
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<p>@{{ message }}</p>
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
<router-view></router-view>
</div>
<script>
const Foo = { template: '<div>foo</div>' };
const Bar = { template: '<div>bar</div>' };
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
];
const router = new VueRouter({
routes // `routes: routes` の短縮表記
});
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
},
router: router
});
</script>
</body>
</html>
ただこれだとFooやBarのテンプレートの中に全てのHTMLを書かねばなりません。
ページ内の1コンポーネントならいいですがページ全体となると気が遠くなりますね。
そこで単一ファイルコンポーネントに行き着くのですが、この辺りからCDN版ではできなくなります。はやー
もう少し突っ込んで試したい場合
NPMインストール
Laravelだとこの辺り最初から揃っているのが嬉しいです(注:揃っているがインストールはされていない)
Laravelのインストールディレクトリ直下にpackage.jsonがあるのですが、何もいじらず以下のコマンドを入力します
$ vagrant ssh
$ npm install
後々、と言ってもすぐに必要になるのでvue-routerもインストールしてしまいます。
$ npm install vue-router
この後コンパイルすると、必要なファイル一式がどこどこ出来上がってきます。
Laravelの場合Laravel Mixというコンポーネントを使ってVue.jsと連携してくれます。
$ npm run dev
これで準備完了です。
NPM版に合わせてソース修正
既に単一ファイルコンポーネントが入ってしまってますが、こんな感じで。
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
</head>
<body>
<div id="app">
<p>@{{ message }}</p>
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
<router-view></router-view>
</div>
<script src="{{ mix('js/app.js') }}" ></script>
</body>
</html>
vueのソースを書いていた部分がjs/app.jsに移動しています。
import VueRouter from 'vue-router';
import page1 from './components/page1.vue';
import page2 from './components/page2.vue';
require('./bootstrap');
window.Vue = require('vue');
const routes = [
{ path: '/page1', component: page1 },
{ path: '/page2', component: page2 }
];
const router = new VueRouter({
routes // `routes: routes` の短縮表記
});
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
},
router: router
});
<template>
<div>foo</div>
</template>
<script>
</script>
<style>
</style>
page2.vueは同じソースなので省略します。
ここまで出来たらビルドして動作を確認します。
$ npm run dev
エラー類
- Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.
npm run devあたりで表示されるエラー
templateタグの中はdivで括らないと上記エラーが出ます。
画面遷移でずれる
absoluteで位置決めしておかないと画面遷移でパーツがいろいろずれます
その他メモ
全ページ共通のcssを読み込む
require('../../public/css/laravel-vue.css');
こんな感じで。
ブラウザ側から見えるパスではなく、サーバー内のパスで書いています。
bladeの範囲
.vueの単一ファイルコンポーネントの中はbladeの範囲外となります。
つづく
参考
https://jp.vuejs.org/
https://router.vuejs.org/ja/
https://blog.capilano-fw.com/?p=432
http://blog.asial.co.jp/1496
https://techblog.securesky-tech.com/entry/2018/09/03/