LoginSignup
23
29

More than 5 years have passed since last update.

Laravel&Vue.jsでSPAの下準備

Last updated at Posted at 2018-03-24

やること

  • 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のあれこれ深いところに入って行きそうなので、ここまで!
乱文失礼いたしました。

23
29
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
29