やること

  • 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 デフォルトページ表示される

特に急がないけど、とりあえず↓。

config/app.php 書きかえ後
'timezone' => 'UTC+09:00',
'locale' => 'ja',
'fallback_locale' => 'ja',

nodeの準備

npm install

npm run dev / npm run watch できるようになる

ファイルの確認

Laravelのルーティング

routes/web.php
Route::get('/', function () {
    return view('welcome');
});

→HomeURLアクセスでresouces/view/welcom.blade.phpを見に行っているようです。
welcomもなんなので、お好みで変更。

resources/views/
welcom.blade.php →ファイル名変更→ app.blade.php
routes/web.php
 return view('welcom'); 書き換え return view('app');

Vue.jsの利用

(参考:https://jp.vuejs.org/index.html)

LaravelはデフォルトでVue.jsが入っており(参照:package.json)、↓な感じでvueなファイル発見。

resouces/assets/js
 ├ components
 │  └ ExampleComponent.vue
 ├ app.js
 └ bootstrap.js

お試しexampleコンポーネントを表示してみる

app.js
Vue.component('example-component', require('./components/ExampleComponent.vue'));

とあるので、、、

resources/views/app.blade.php
<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ファイルを返す。

routes/web.php
Route::get('/{any}', function () {
    return view('app');
})->where('any', '.*');

Vue.js側のviewのベース設定

とりあえず、exampleなコンポーネント表示と、vue-routerで表示されるとこ設定。

resources/assets/js/components/App.vue ファイルを作成
<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を表示させる部分を記載↓。

resources/views/app.blade.php
<body>
    <div id="app"></div>
    <script src="js/app.js"></script>
</body>

vue-router を設定

デフォルトでは入ってないのでインストール

インストール
npm install vue-router

appの設定とルーティング設定のファイルは別々にしとこうと思います。

resources/assets/js/app.js ←app.blade.phpで読み込まれているapp.js
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なコンポーネントを表示。

resources/assets/js/router.js ←app.jsでimportしている./router
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.jspublic/js/app.js
resources/assets/sass/style.scsspublic/css/style.css(オプション:compressed)として書き出される。

webpack.mix.jp
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が作れなかった。どうして。。?

webpack.mix.jp これでは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のファイルパスを書けるようになる。

resources/views/app.blade.php
<link rel="stylesheet" href="{{ mix('css/style.css') }}">
<script src="{{ mix('js/app.js') }}"></script> /*←すでに書いてあるものの書き換え*/

もうちょっとアプリなコンポーネント設定(ビューを増やしてリンク設定)

(参考:https://router.vuejs.org/ja/)

せっかくなので、ルーティングをもうちょっと試すべく、ヘッダーとビュー(ページ)を5つほど設定してみる。

テンプレートヘッダーの追加

exampleなコンポーネントを表示するのやめて、headerを追加。

resources/assets/js/components/App.vue
<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> の中身を作る。↓

resources/assets/js/components/AppHeader.vue
<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  をアクセスして確認

ビュー(ページ)を作成

ルーティングの設定

resources/assets/js/router.js
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
        }
      ]
    },
  ]
});

各コンポーネントを作成

resources/assets/js/components/PageTop.vue
<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>を追加

resources/assets/js/components/PageUser.vue
<template>
  <div>
    <p>PageUser</p>
    <section><router-view></router-view></section>
  </div>
</template>

<script>
  export default {
    name: 'pageUser',
  }
</script>

リンクの作成

ヘッダーにナビゲーションリンクを作成↓

resources/assets/js/components/AppHeader.vue
/*前後略*/
  <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>

ユーザーページにページリンクを作成↓

resources/assets/js/components/PageUser.vue
/*前後略*/
  <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 にそれを含める必要がありません。

(引用:https://router.vuejs.org/ja/api/router-link.html)

ということなで、<router-link>に書きかえ。

方法1:URL指定

resources/assets/js/components/AppHeader.vue
/*前後略*/
  <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>
resources/assets/js/components/PageUser.vue
/*前後略*/
  <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)

ルートに名前をつけておくことで、その名前を指定することでリンクが生成される

resources/assets/js/router.js
/*前後略*/
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
      }
    ]
  },
]
resources/assets/js/components/AppHeader.vue
/*前後略*/
  <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>
resources/assets/js/components/PageUser.vue
/*前後略*/
  <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

ユーザー名が動的なので、その仮設定を行う。

親コンポーネント

resources/assets/js/components/App.vue
<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>

解説抜粋。

resources/assets/js/components/App.vue
親コンポーネントで、データを取得(取り急ぎ仮に作成。)
<script>
 /*前後略*/
  export default {
    data: function (){ /*dataは関数じゃなきゃいけない。とのこと。*/
      return { /*後々、ajaxとかで受け取れるとして、とりあえず固定でオブジェクト作成。*/
        user: { 
          id: 123,
          name: 'abc'
        }
      }
    }
  }
</script>
resources/assets/js/components/App.vue
親コンポーネントから子コンポーネントにデータを渡す。
<template>
  <router-view :user-info="user"></router-view>
  /*データの[user]を[userInfo]というプロパティで子コンポーネントに渡す。*/
</template>

子コンポーネント

resources/assets/js/components/PageUser.vue
<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>

解説抜粋。

resources/assets/js/components/PageUser.vue
/*親コンポーネントから渡ってきた[userInfo]をプロパティとして受け取る*/
<script>
  export default {
    props: ['userInfo']
  }
</script>
resources/assets/js/components/PageUser.vue
/*[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のあれこれ深いところに入って行きそうなので、ここまで!
乱文失礼いたしました。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.