やること
- Laravelの上にVue.jsを乗っけた(viewをVue.jsにお任せした)形でSPAを作成
→要ルーティングを設定 - js、cssプリプロセッサ(scssを利用)のコンパイラとして Laravel Mixを利用
- Vue.jsでコンポーネントを作成、リンクの設定
環境
・maxOS High Sierra
・php : v7.1
・Laravel : v5.6
・Laravel Mix : v2.0
・Node : v8.9
・npm : v5.7
・Vue : v2.5
・vue-router : v3.0
下準備
cd プロジェクトフォルダ作るところ
composer create-project --prefer-dist laravel/laravel プロフジェクト名
→プロフェクト名のフォルダができて、installされる
cd プロフジェクトのフォルダ
→php artian serve
http://localhost:8000 デフォルトページ表示される
特に急がないけど、とりあえず↓。
'timezone' => 'UTC+09:00',
'locale' => 'ja',
'fallback_locale' => 'ja',
nodeの準備
npm install
→npm run dev
/ npm run watch
できるようになる
ファイルの確認
Laravelのルーティング
Route::get('/', function () {
return view('welcome');
});
→HomeURLアクセスでresouces/view/welcom.blade.php
を見に行っているようです。
welcomもなんなので、お好みで変更。
welcom.blade.php →ファイル名変更→ app.blade.php
return view('welcom'); →書き換え→ return view('app');
Vue.jsの利用
(参考:https://jp.vuejs.org/index.html)
LaravelはデフォルトでVue.jsが入っており(参照:package.json)、↓な感じでvueなファイル発見。
├ components
│ └ ExampleComponent.vue
├ app.js
└ bootstrap.js
お試しexampleコンポーネントを表示してみる
Vue.component('example-component', require('./components/ExampleComponent.vue'));
とあるので、、、
<body>
<div id="app">
<example-component></example-component>
</div>
<script src="js/app.js"></script>
</body>
npm run dev (もしくはwatch)
→ http://localhost:8000 をアクセスして確認
vue-routerでSPA化
(参考:https://router.vuejs.org/ja/)
Vue.js側にルーターを設定し、SPA化。
Laravel側設定
どのURLでアクセスしても、同一のLaravelのviewファイルを返す。
Route::get('/{any}', function () {
return view('app');
})->where('any', '.*');
Vue.js側のviewのベース設定
とりあえず、exampleなコンポーネント表示と、vue-routerで表示されるとこ設定。
<template>
<div id="app">
<example-component></example-component>
<main><router-view></router-view></main>
</div>
</template>
<script>
export default {
name: 'app',
}
</script>
↑ <router-view></router-view>
のところに、vue-routerの設定に応じた中身が表示される。
LaravelのビューファイルにもVue.jsを表示させる部分を記載↓。
<body>
<div id="app"></div>
<script src="js/app.js"></script>
</body>
vue-router を設定
デフォルトでは入ってないのでインストール
npm install vue-router
appの設定とルーティング設定のファイルは別々にしとこうと思います。
require('./bootstrap');
import Vue from 'vue'
import VueRouter from 'vue-router'
import router from './router'
import app from './components/App.vue'
Vue.use(VueRouter)
new Vue({
el: '#app',
router: router,
template: '<app/>',
components: { app }
})
↑ app.blade.phpの<div id="app"></div>
に App.vue
が挿入される。
ルーティング設定ファイルも読み込んでおく。
↓ルーティング設定。とりあえず、ルーティング内でもexampleなコンポーネントを表示。
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
Vue.component('example-component', require('./components/ExampleComponent.vue'));
export default new VueRouter({
mode: 'history',
routes: [
{ path: '/',
component: require('./components/ExampleComponent.vue')
}
]
});
npm run dev (もしくはwatch)
→ http://localhost:8000 をアクセスして確認
sassのコンパイル設定(Laravel Mix)
(参考:https://readouble.com/laravel/5.6/ja/mix.html
https://github.com/JeffreyWay/laravel-mix/issues/879)
Laravel Mixなるものが、アセットのコンパイルをやってくれるらしい。
↓を書くと、
resources/assets/js/app.js
がpublic/js/app.js
、
resources/assets/sass/style.scss
がpublic/css/style.css(オプション:compressed)
として書き出される。
mix.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/style.scss', 'css', {outputStyle: 'compressed', outFile: 'public/css'})
.options({
processCssUrls: false,
});
if (!mix.inProduction()) {
mix.webpackConfig({
devtool: 'source-map'
})
.sourceMaps()
}
↑下部のif文を付け加えないと、sourcemapが作れなかった。どうして。。?
mix.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/style.scss', 'css', {outputStyle: 'compressed', outFile: 'public/css'})
.sourceMaps()
.options({
processCssUrls: false,
});
Laravel Mixを使って、jsやcssのファイルパスを書けるようになる。
<link rel="stylesheet" href="{{ mix('css/style.css') }}">
<script src="{{ mix('js/app.js') }}"></script> /*←すでに書いてあるものの書き換え*/
もうちょっとアプリなコンポーネント設定(ビューを増やしてリンク設定)
(参考:https://router.vuejs.org/ja/)
せっかくなので、ルーティングをもうちょっと試すべく、ヘッダーとビュー(ページ)を5つほど設定してみる。
テンプレートヘッダーの追加
exampleなコンポーネントを表示するのやめて、headerを追加。
<template>
<div id="app">
<app-header></app-header> /*<app-header>を表示*/
<main><router-view></router-view></main>
</div>
</template>
<script>
import appHeader from './AppHeader'
export default {
name: 'app',
components: {
'app-header': appHeader, /*「<app-header>はimportしたappHeaderだよ」と設定*/
}
}
</script>
<app-header>
の中身を作る。↓
<template>
<header>
<h1>logo</h1>
<nav>
<ul>
<li>menu</li>
</ul>
</nav>
</header>
</template>
<script>
export default {
name: 'appHeader',
}
</script>
npm run dev (もしくはwatch)
→ http://localhost:8000 をアクセスして確認
ビュー(ページ)を作成
ルーティングの設定
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
/*下部記載のルーティングに必要なコンポーネントのimport*/
import pageTop from './components/PageTop'
import pageAbout from './components/pageAbout'
import pageUser from './components/PageUser'
import UserProfile from './components/user/Profile'
import UserPosts from './components/user/Posts'
/*URLと↑でimportしたコンポーネントをマッピングする(ルーティング設定)*/
export default new VueRouter({
mode: 'history',
routes: [
{
path: '/',
component: pageTop
},
{
path: '/about',
component: pageAbout
},
{
path: '/user/:userName', /* 動的ルートのお試しとしてユーザー名を入れてみる*/
component: pageUser,
children: [ /* ネストのお試しとしてchildren設定してみる */
{
path: 'profile', /* URL: /user/ユーザーネーム/profile */
component: UserProfile
},
{
path: 'posts', /* URL: /user/ユーザーネーム/posts */
component: UserPosts
}
]
},
]
});
各コンポーネントを作成
<template>
<p>PageTop</p>
</template>
<script>
export default {
name: 'pageTop',
}
</script>
ひとまず、↑なノリでコンポーネント名を<p>
に入れて、前述でimportしたコンポーネントを全部作る。
ネストのルーティング用のビュー
(参考:https://router.vuejs.org/ja/essentials/nested-routes.html )
PageUser.vueについては、ネストがあるので、<router-view>
を追加
<template>
<div>
<p>PageUser</p>
<section><router-view></router-view></section>
</div>
</template>
<script>
export default {
name: 'pageUser',
}
</script>
リンクの作成
ヘッダーにナビゲーションリンクを作成↓
/*前後略*/
<nav>
<ul>
<li><a href="/">Top</a></li>
<li><a href="/about">about</a></li>
<li><a href="/user/abc">user</a></li> /*動的URLに値を渡す設定してないので、取り急ぎユーザー名適当に固定指定*/
</ul>
</nav>
ユーザーページにページリンクを作成↓
/*前後略*/
<div>
<p>PageUser</p>
<nav>
/*これはうまく行かない*/
<a href="./profile">profile</a>
<a href="./posts">posts</a>
/*これだとOK*/
<a href="/user/abc/profile">profile</a>
<a href="/user/abc/posts">posts</a>
</nav>
<section><router-view></router-view></section>
</div>
ってやってもいいけど、
下記の理由により
<router-link>
はハードコードする<a href="...">
よりも好ましいです。
- HTML5 history モードでも hash モードでも同じ方法で動作します。もしあなたがモードを切り替えたりする場合や、IE9 で hash モードにフォールバックする場合に、何も変更する必要はありません。
- HTML5 history モードにおいて、ブラウザがページのリロードをしないように router-link はクリックイベントに割り込みます。
- HTML5 history モードで base オプションを使っている時に、 to プロパティの URL にそれを含める必要がありません。
ということなで、<router-link>
に書きかえ。
方法1:URL指定
/*前後略*/
<nav>
<ul>
<li><router-link to="top">Top</router-link></li>
<li><router-link to="about">about</router-link></li>
<li><router-link to="user/abc">user</router-link></li>
</ul>
</nav>
/*前後略*/
<nav>
<router-link to="abc/profile">profile</router-link>
<router-link to="abc/posts">posts</router-link>
</nav>
方法2:名前付きルート
(参考:https://router.vuejs.org/ja/essentials/named-routes.html)
ルートに名前をつけておくことで、その名前を指定することでリンクが生成される
/*前後略*/
routes: [
{
path: '/',
name: 'top', /*←各ルートにnameを追記*/
component: pageTop
},
{
path: '/about',
name: 'about',
component: pageAbout
},
{
path: '/user/:userName',
name: 'user',
component: pageUser,
children: [
{
path: 'profile',
name: 'profile',
component: UserProfile
},
{
path: 'posts',
name: 'posts',
component: UserPosts
}
]
},
]
/*前後略*/
<nav>
<ul>
<li><router-link :to="{ name: 'top'}">Top</router-link></li>
<li><router-link :to="{ name: 'about'}">about</router-link></li>
<li><router-link :to="{ name: 'user', params: { userName: 'abc' }}">user</router-link></li>
</ul>
</nav>
/*前後略*/
<nav>
<router-link :to="{ name: 'profile', params: { userName: 'abc' }}">profile</router-link>
<router-link :to="{ name: 'posts', params: { userName: 'abc' }}">posts</router-link>
</nav>
動的ルートにプロパティを渡す
(参考:https://jp.vuejs.org/v2/guide/components.html#%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AE%E6%A7%8B%E6%88%90
https://jp.vuejs.org/v2/guide/components.html#%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%AB%E3%82%88%E3%82%8B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E4%BC%9D%E9%81%94
)
ユーザー名が動的なので、その仮設定を行う。
親コンポーネント
<template>
/*前後略*/
<main><router-view :user-info="user"></router-view></main>
</template>
<script>
/*前後略*/
export default {
name: 'app',
components: {
'app-header': appHeader,
},
data: function (){
return {
user: { /* 取り急ぎユーザー情報固定で設定 */
id: 123,
name: 'abc'
}
}
}
}
</script>
解説抜粋。
親コンポーネントで、データを取得(取り急ぎ仮に作成。)
<script>
/*前後略*/
export default {
data: function (){ /*dataは関数じゃなきゃいけない。とのこと。*/
return { /*後々、ajaxとかで受け取れるとして、とりあえず固定でオブジェクト作成。*/
user: {
id: 123,
name: 'abc'
}
}
}
}
</script>
親コンポーネントから子コンポーネントにデータを渡す。
<template>
<router-view :user-info="user"></router-view>
/*データの[user]を[userInfo]というプロパティで子コンポーネントに渡す。*/
</template>
子コンポーネント
<template>
/*前後略*/
<div>PageUser:{{userInfo.name}}</div>
<nav>
<router-link :to="{ name: 'profile', params: { userName: userInfo.name }}">profile</router-link>
<router-link :to="{ name: 'posts', params: { userName: userInfo.name }}">posts</router-link>
</nav>
</template>
<script>
export default {
name: 'pageUser',
props: ['userInfo']
}
</script>
解説抜粋。
/*親コンポーネントから渡ってきた[userInfo]をプロパティとして受け取る*/
<script>
export default {
props: ['userInfo']
}
</script>
/*[userInfo]プロパティのnameを表示する*/
<template>
<div>PageUser:{{userInfo.name}}</div>
<nav>
<router-link :to="{ name: 'profile', params: { userName: userInfo.name }}">profile</router-link>
<router-link :to="{ name: 'posts', params: { userName: userInfo.name }}">posts</router-link>
/*ルーティングで設定したパス、'/user/:userName'に合わせて、リンクのパラメータuserNameに[userInfo]のユーザー名を設定する*/
</nav>
</template>
ちなみに、こちらではうまくリンク作成されず↓。
<router-link to={userInfo.name}"/profile">profile</router-link>
<router-link to="{userInfo.name}/profile">profile</router-link>
<router-link to={userInfo.name +"/profile"}>profile</router-link>
<a :href="/{userInfo.name}/profile">profile</a>
<a :href="/"+{userInfo.name}+"/profile">profile</a>
ここまで!
Vue.jsのあれこれ深いところに入って行きそうなので、ここまで!
乱文失礼いたしました。