1. nobu-maple

    No comment

    nobu-maple
Changes in title
-Laravel5.6 + Vue2.5 でvue-routerとVuetifyを使ってみる
+Laravel5.7 + Vue2.5 でvue-routerとVuetifyを使ってみる
Changes in body
Source | HTML | Preview

Laravel でユーザ認証した後、Vue側でRouter使ってページを切り替えてみる
ユーザ管理(社員管理)のページとしてデータテーブルを使えるように Vuetify も使ったページを作成する

■1.各パッケージをインストール1.各パッケージをインストール

npm環境設定他関連記事はこちら でサクッと
今後のために日付処理系のmoment.js も入れておくLaravel + Vue + Vuetify で業務サイト作ってみる

npm install vue-router
npm install vuetify
npm install css-loader
npm install material-design-icons-iconfont
npm install moment
npm install vue-router
npm install vuetify
npm install css-loader
npm install material-design-icons-iconfont

インストール後はこんな感じ

package.json
{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "npm run development -- --watch",
        "watch-poll": "npm run watch -- --watch-poll",
        "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "axios": "^0.18",
        "bootstrap": "^4.1.2",
        "cross-env": "^5.2.0",
        "jquery": "^3.2",
        "laravel-mix": "^2.0",
        "lodash": "^4.17.4",
        "popper.js": "^1.12",
        "vue": "^2.5.7"
    },
    "dependencies": {
        "css-loader": "^1.0.0",
        "material-design-icons-iconfont": "^3.0.3",
        "moment": "^2.22.2",
        "vue-router": "^3.0.1",
        "vuetify": "^1.1.5"
    }
}
package.json
{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "npm run development -- --watch",
        "watch-poll": "npm run watch -- --watch-poll",
        "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "axios": "^0.18",
        "bootstrap": "^4.0.0",
        "cross-env": "^5.1",
        "jquery": "^3.2",
        "laravel-mix": "^2.0",
        "lodash": "^4.17.5",
        "popper.js": "^1.12",
        "vue": "^2.5.7"
    },
    "dependencies": {
        "css-loader": "^1.0.0",
        "material-design-icons-iconfont": "^3.0.3",
        "vue-router": "^3.0.1",
        "vuetify": "^1.2.9"
    }
}

■2.読み込み設定2.読み込み設定

追加したパッケージを読み込むように設定npm でサクッと vue-router vuetify を入れとく
vuetify はこちらを参考に

resources/assets/js/app.js
        /**
         * First we will load all of this project's JavaScript dependencies which
         * includes Vue and other libraries. It is a great starting point when
         * building robust, powerful web applications using Vue and Laravel.
         */

        require('./bootstrap');

        window.Vue = require('vue');
★1      window.Vuetify = require('vuetify');
★1      Vue.use(Vuetify);

★2      import 'vuetify/dist/vuetify.min.css';
★2      import 'material-design-icons-iconfont/dist/material-design-icons.css';


★3      import VueRouter from 'vue-router';
★3      Vue.use(VueRouter);

        Vue.component('example-component', require('./components/ExampleComponent.vue'));
        Vue.component('admin-component', require('./components/AdminComponent.vue'));

★4      const router = new VueRouter({
★4        mode: 'history',
★4        routes: [
★4          { path: '/', component: require('./components/DashboardComponent.vue')},
★4          { path: '/admin/user', component: require('./components/Admin/UserComponent.vue'  )},
★4        ]
★4      });



        /**
         * Next, we will create a fresh Vue application instance and attach it to
         * the page. Then, you may begin adding components to this application
         * or customize the JavaScript scaffolding to fit your unique needs.
         */


        const app = new Vue({
            el: '#app',
★4          router,
        });
resources/js/app.js
require('./bootstrap');

// Vue
import Vue from 'vue'


// Vuetify
import Vuetify from 'vuetify'
import colors from 'vuetify/es5/util/colors'

Vue.use(Vuetify, {
  theme: {
    primary: colors.indigo.base,
    secondary: colors.blue.base,
    accent: colors.amber.base,
  }
});
import 'vuetify/dist/vuetify.min.css'
import 'material-design-icons-iconfont/dist/material-design-icons.css'


// Vue-Router
import router from './router'


// Main app
const app = new Vue({
    el: '#app',
    router,
});

★1 Vuetify追加した 読み込み設定Vuetify router を読み込むように設定
★2 Vuetifyrouter 関連のCSS読み込み設定については外出しして管理しやすいようにしとく
★3 routerVuetify 読み込み設定
色設定★4 routerも入れておく ルーティング設定

router 用設定

■3.routerで切り替えるベースコンポーネント作成3.routerで切り替えるベースコンポーネント作成

vue-routerで切り替えるページのベースとなるコンポーネントを作成する
レイアウトは Vuetify のテンプレートを利用させてもらう

resources/assets/js/components/AdminComponent.vue
<template>
  <v-app id="app">
    <v-navigation-drawer v-model="drawer" clipped fixed app >
      <v-list dense>
        <router-link to="/home">
          <v-list-tile @click="drawer = !drawer">
            <v-list-tile-action> <v-icon>home</v-icon> </v-list-tile-action>
            <v-list-tile-content>
              <v-list-tile-title>HOME</v-list-tile-title>
            </v-list-tile-content>
          </v-list-tile>
        </router-link>

        <router-link to="/admin/user">
          <v-list-tile @click="drawer = !drawer">
            <v-list-tile-action> <v-icon>supervisor_account</v-icon> </v-list-tile-action>
            <v-list-tile-content>
              <v-list-tile-title>社員管理</v-list-tile-title>
            </v-list-tile-content>
          </v-list-tile>
        </router-link>
      </v-list>
    </v-navigation-drawer>

    <v-toolbar color="indigo" dark fixed app clipped-left>
      <v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
      <v-toolbar-title>Application</v-toolbar-title>
      <v-spacer></v-spacer>
      {{ name }}
      <v-btn icon @click="axiosLogout()">
        <v-tooltip left>
          <v-icon slot="activator" color="white" dark >exit_to_app</v-icon>
          <span>ログアウト</span>
        </v-tooltip>
      </v-btn>
    </v-toolbar>

    <v-fade-transition mode="out-in">
          <router-view></router-view>
    </v-fade-transition>

    <v-footer color="indigo" dark app fixed>
      <span class="white--text ml-3">
        &copy; 2018
        <a class="white--text" href="https://qiita.com/nobu-maple">Qiita nobu-maple</a>
      </span>
    </v-footer>
  </v-app>
</template>

<script>
  export default {
    data: () => ({
      drawer: false,
    }),

    props: {
      id: String,
      name: String,
      role: String,
      logout: String,
    },

    mounted() {
      console.log('Component mounted.')
    },

    methods: {
      axiosLogout: function() {
        var params = new URLSearchParams()
        axios.post(this.logout, params, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}})

        .then( function (response) {
          console.log(response)
        }.bind(this))

        .catch(function (error) {
          if (error.response.status === 401) {
            var parser = new URL(this.logout)
            location.href=parser.origin
          }
          console.log(error.response)
        }.bind(this))
      },

    },
  }
</script>
resources/js/components/AdminComponent.vue
<template>
  <v-app id="app">
    <v-navigation-drawer v-model="drawer" clipped fixed app >
      <v-list dense>
        <r-link linkname='home'></r-link>
        <r-link linkname='admin_user'></r-link>
      </v-list>
    </v-navigation-drawer>

    <v-toolbar color="primary" dark fixed app clipped-left>
      <v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
      <v-toolbar-title>{{title}}</v-toolbar-title>
      <v-spacer></v-spacer>
      {{ name }}
      <v-btn icon @click="axiosLogout()">
        <v-tooltip left>
          <v-icon slot="activator" color="white" dark >exit_to_app</v-icon>
          <span>ログアウト</span>
        </v-tooltip>
      </v-btn>
    </v-toolbar>

    <v-content>
      <v-container fluid fill-height
        <v-layout justify-center fluid column>
          <v-fade-transition mode="out-in">
            <router-view @axios-logout="axiosLogout"></router-view>
          </v-fade-transition>
        </v-layout>
      </v-container>
    </v-content>

    <v-footer color="primary" dark app fixed>
      <span class="white--text ml-3" v-html="footer"></span>
    </v-footer>
  </v-app>
</template>

<script>
  export default {
    name: 'AdminComponent',

    props: {
      name: String,
      logout: String,
    },

    data: () => ({
      drawer: false,
      footer: 'foo-----footer',
      title: 'tit------title',
    }),

    mounted() {
      console.log('AdminComponent mounted.')

      if (process.env.MIX_FOOTER) { this.footer = process.env.MIX_FOOTER }
      if (process.env.MIX_TITLE) { this.title = process.env.MIX_TITLE }
    },

    methods: {
      axiosLogout: function() {
        axios.post(this.logout)
        .then( function (response) {
          console.log(response)
        }.bind(this))

        .catch(function (error) {
          console.log(error)
          if (error.response) {
            if (error.response.status) {
              if (error.response.status == 401 || error.response.status == 419) {
                var parser = new URL(this.logout)
                location.href=parser.origin
              }
            }
          }
        }.bind(this))
      },
    },
  }
</script>
resources/js/components/RouterLink.vue
<template>
  <router-link :to="{name: linkname}">
    <v-list-tile>
      <v-list-tile-action>
        <v-icon>{{ getRoute( linkname, 'icon' ) }}</v-icon>
      </v-list-tile-action>
      <v-list-tile-content>
        <v-list-tile-title>{{getRoute( linkname, 'name' )}}</v-list-tile-title>
      </v-list-tile-content>
    </v-list-tile>
  </router-link>
</template>

<script>
  export default {
    name: 'routerlink',
    props: {
      linkname: String,
    },

    methods: {
      getRoute(name, key) {
        for(var i=0 ; i<this.$router.options.routes.length; i++) {
          if (this.$router.options.routes[i].name == name ) {
            return this.$router.options.routes[i].meta[key]
          }
        }
      },
    },

  }
</script>

<style>
  a:hover {
    text-decoration: none;
  }
</style>

■4.home4.home コンポーネント作成

リンク部分をコンポーネント化

とりあえず空のコンポーネント
Vuetifyで書いておく

resources/assets/js/components/HomeComponent.vue
<template>
  <v-content>
    <v-container fluid fill-height>
      <v-layout justify-center fluid>
        <v-flex xs12 offset-mx5>
          Home Component.
        </v-flex>
      </v-layout>
    </v-container>
  </v-content>
</template>

<script>
  export default {
    data: () => ({
    }),

    props: {
    },

    created() {
      console.log('Component created.')
      this.initialize()
    },

    mounted() {
      console.log('Component mounted.')
    },

    methods: {
      initialize: function() {
      },
    },

  }
</script>
resources/js/components/HomeComponent.vue
<template>
  <v-content>
    <v-container fluid fill-height>
      <v-layout justify-center fluid>
        <v-flex xs12 offset-mx5>
          Home Component.
        </v-flex>
      </v-layout>
    </v-container>
  </v-content>
</template>

<script>
  export default {
    data: () => ({
    }),

    props: {
    },

    created() {
      console.log('Home Component created.')
      this.initialize()
    },

    mounted() {
      console.log('Home Component mounted.')
    },

    methods: {
      initialize: function() {
      },
    },

  }
</script>

■5.ユーザ一覧を表示するコンポーネントを作成5.ユーザ一覧を表示するコンポーネントを作成

Vuetifyapp.js と同じ階層に router ディレクトリを掘っておくデータテーブルを利用します
ユーザ一覧は axios で取ってきてテーブルにデータをセット
検索とページングとソートの設定もしときます

resources/assets/js/components/Admin/UserComponent.vue
<template>
  <v-content>
    <v-container fluid fill-height>
      <v-layout justify-center fluid>
        <v-flex xs12 offset-mx5>
          <v-card xs12>

            <v-card-title class="title">
              <v-icon class="ml-2">supervisor_account</v-icon> 社員管理
              <v-spacer></v-spacer>
              <v-text-field
                v-model="search"
                append-icon="search"
                label="Search"
                single-line
                hide-details
              ></v-text-field>
            </v-card-title>

            <v-data-table
              :headers="headers"
              :items="users"
              :pagination.sync="pagination"
              :rows-per-page-items='[10,25,50,{"text":"All","value":-1}]'
              :loading="loading"
              :search="search"
              class="elevation-0"
            >

              <v-progress-linear slot="progress" color="blue" indeterminate></v-progress-linear>
              <template slot="items" slot-scope="props">
                <tr @click="props.expanded = !props.expanded">
                  <td class="text-xs-center" xs1>{{ (props.index + 1) + (pagination.page - 1) * pagination.rowsPerPage }}</td>
                  <td class="text-xs-left">{{ props.item.loginid }}</td>
                  <td class="text-xs-left">{{ props.item.name }}</td>
                  <td class="text-xs-left">{{ props.item.role }} - {{ props.item.role == '10' ? 'ユーザ' : '管理者' }}</td>
                </tr>
              </template>
            </v-data-table>

          </v-card>
        </v-flex>
      </v-layout>
    </v-container>
  </v-content>
</template>

<script>
  export default {
    data: () => ({
      loading: true,
      search: '',
      pagination: { sortBy: 'name', descending: true, },

      users: [],
      headers: [
        { align: 'center', sortable: false, text: 'No',       },
        { align: 'left',   sortable: true,  text: '社員ID',   value: 'loginid' },
        { align: 'left',   sortable: true,  text: '氏名',     value: 'name' },
        { align: 'left',   sortable: true,  text: '権限',     value: 'role' },
      ],
    }),

    props: {
    },

    created() {
      console.log('Component created.')
      this.initialize()
    },

    mounted() {
      console.log('Component mounted.')
    },

    methods: {
      initialize: function() {
        this.getUsers()
      },

      getUsers: function() {
        var params = new URLSearchParams()
        this.loading = true
        axios.post('/api/admin/user/', params, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}})

        .then( function (response) {
          this.loading = false
          console.log(response)
          this.users = response.data.users
        }.bind(this))

        .catch(function (error) {
          this.loading = false
          console.log(error.response)
        }.bind(this))
      },

    },
  }
</script>

■6.ユーザ用コントローラを作成6.ユーザ用コントローラを作成

ひな形をまず作って

php artisan make:controller UserController

一覧のデータとして全件を返す index を定義しときます

app/Http/Controllers/UserController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;

class UserController extends Controller
{
    public function index()
    {
       $users = User::all();
       return ['users' => $users];
    }
}
app/Http/Controllers/UserController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App/User;

class UserController extends Controller
{
  public function index()
  {
    $users = User::all();
    return ['users' => $users];
  }
}
app/User.php
<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
//        'email',
        'loginid',
        'password',
        'role',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];
}

■7.Laravel側のルーティング設定7.Laravel側のルーティング設定

権限(role)も表示対象にする

管理者以外はアクセスできないように定義したGATEで制限もかけときます

routes/web.php
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('home');
})->middleware('auth');

//Auth::routes();

// Authentication Routes...
Route::get('login', 'Auth\LoginController@showLoginForm')->name('login');
Route::post('login', 'Auth\LoginController@login');
Route::post('logout', 'Auth\LoginController@logout')->name('logout');

Route::get('/home', 'HomeController@index')->name('home');

Route::group(['middleware' => ['auth', 'can:admin-higher']], function () {
  Route::post('/api/admin/user', 'UserController@index')->name('admin/user');
});


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

Route::get('/', function () {
    return view('home');
})->middleware('auth');

// Authentication Routes...
Route::get('/login', 'Auth\LoginController@showLoginForm')->name('login');
Route::post('/login', 'Auth\LoginController@login');
Route::post('/logout', 'Auth\LoginController@logout')->name('logout');

// Admin
Route::group( ['middleware' => ['auth', 'can:admin']], function() {

  // USER
  Route::post('/api/admin/user', 'UserController@index')->name('admin/user');
});

// Other
Route::get('/{any}', function () {
  return view('home');
})->middleware('auth')->where('any', '.*');

■8.動作確認8.動作確認

コンパイルして、サーバを起動して

npm run dev
php artisan serve --host=172.16.0.100  --port=8000

ブラウザでアクセスして
http://172.16.0.100:8000/

↓↓

$ mkdir resources/js/router

ログインページへ飛ばされて作った ディレクトリに router 用設定ファイルを作成
http://172.16.0.100:8000/login
login.png

↓↓

resources/js/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)

//
import example_component from '../components/ExampleComponent.vue'
import admin_component   from '../components/AdminComponent.vue'
import r_link            from '../components/RouterLink.vue'

//
Vue.component('example-component', example_component)
Vue.component('admin-component', admin_component)
Vue.component('r-link', r_link)

//
import home              from '../components/HomeComponent.vue'
import admin_user        from '../components/Admin/UserComponent.vue'

export default new Router({
  mode: 'history',
  routes: [
    { path: '/',             name: 'home',          component: home,          meta: {name: 'ホーム',   icon: 'home'}},
    { path: '/admin/user',   name: 'admin_user',    component: admin_user,    meta: {name: '社員管理', icon: 'supervisor_account'}},
  ],
})

Userリンク用の文字とかアイコンをここに定義 の権限でログインしたら今までの Vue コンポーネントが表示されて
各画面で表示する文字とかアイコンはこの定義を参照することで変更も1か所で済むようにしておくuser.png

User の権限でログインしたら今までの Vue コンポーネントが表示されて
172.16.0.100_8000_js_colors.js.map.png

↓↓

ログアウトしてリンク毎に同じ定義を書くのもめんどくさいのでコンポーネントにして、アイコンやらタイトルやらは 今度はroute/index.js Adminの定義から設定できるようにしとく の管理者権限でログインしたら
login_admin.png

ログアウトして 今度は Admin の管理者権限でログインしたら

↓↓

Vuetify で作った Adminコンポーネントが表示されて
データテーブルを利用して登録済みのユーザ(社員)情報を一覧表示してみますadmin_top.png

Vuetify で作った Adminコンポーネントが表示されて
172.16.0.100_8000_js_colors.js.map.png

↓↓

メニューからユーザ情報は 「社員管理」を選ぶとaxios vue-routerで取ってきてデータテーブルにセット の機能で一覧のコンポーネントに切り替わり
検索とページングとソートの設定もしときます

メニューから 「社員管理」を選ぶと vue-router の機能で一覧のコンポーネントに切り替わり
172.16.0.100_8000_js_colors.js.map.png

admin_menu.pngデータテーブル構造は動的に headers に設定しているやつをセットするようにしてます
ついでに連番も表示するようにしておきました

↓↓

resources/js/components/Admin/UserComponent.vue
<template>
  <v-flex>
    <v-card xs12 class="m-3 px-3">

      <v-card-title class="title">
        <v-icon class="pr-2">{{ $route.meta.icon }}</v-icon> {{ $route.meta.name }} {{ /* 社員管理 */ }}
        <v-spacer></v-spacer>
        <v-spacer></v-spacer>
        <v-text-field
          v-model="search"
          append-icon="search"
          label="Search"
          single-line
          hide-details
        ></v-text-field>
      </v-card-title>

      <v-data-table
        :headers="headers"
        :items="tabledata"
        :pagination.sync="pagination"
        :rows-per-page-items='[10,25,50,{"text":"All","value":-1}]'
        :loading="loading"
        :search="search"
        class="elevation-0 p-1"
      >
        <v-progress-linear slot="progress" color="blue" indeterminate></v-progress-linear>

        <template slot="items" slot-scope="props">
          <tr>
            <td class="text-xs-center" xs1>{{ (props.index + 1) + (pagination.page - 1) * pagination.rowsPerPage }}</td>
            <template v-for="n in (headers.length - 1)">
              <td :class="'text-xs-' + headers[n].align" style="white-space: nowrap;" v-text="props.item[headers[n].value]"></td>
            </template>
          </tr>
        </template>

      </v-data-table>
    </v-card>
  </v-flex>
</template>

<script>
  export default {
    name: 'UserComponent',

    props: {
      logout: String,
    },

    data: () => ({
      loading: true,
      search: '',
      pagination: { sortBy: 'name', descending: false, },

      tabledata: [],
      headers: [
        { align: 'center', sortable: false, text: 'No',       },
        { align: 'left',   sortable: true,  text: '社員ID',   value: 'loginid' },
        { align: 'left',   sortable: true,  text: '氏名',     value: 'name' },
        { align: 'center', sortable: true,  text: '権限',     value: 'role' },
      ],
    }),

    created() {
      console.log('User Component created.')
      this.initialize()
    },

    methods: {
      initialize: function() {
        this.getUsers()
      },

      getUsers() {
        this.loading = true
        axios.post('/api/admin/user')

        .then( function (response) {
          this.loading = false
console.log(response)
          if (response.data.users) {
            this.tabledata = response.data.users
            this.setRole()
          }
        }.bind(this))

        .catch(function (error) {
          this.loading = false
          console.log(error)
          if (error.response) {
            if (error.response.status) {
              if (error.response.status == 401 || error.response.status == 419) {
                this.$emit('axios-logout')
              }
            }
          }
        }.bind(this))
      },

      setRole() {
        for (var i=0; i<this.tabledata.length; i++) {
          if (this.tabledata[i].role) {
            if (this.tabledata[i].role == 5) { this.tabledata[i].role = '管理者'  }
            if (this.tabledata[i].role == 10) { this.tabledata[i].role = 'ユーザ'  }
          }
        }
      },
    },
  }
</script>

User情報を権限(role)は数字で出されてもわかりにくいので日本語に変換(setRole)して表示するようにしています axios が取ってきて Vuetify のデータテーブルにセットして表示

User情報を axios が取ってきて Vuetify のデータテーブルにセットして表示
172.16.0.100_8000_js_colors.js.map.png

admin_userlist.pngApp/User.php でroleは隠す設定にしていたので、hiddenからfillableに変更

検索とかページングとかソートとかの動作もうまく動いているようです
172.16.0.100_8000_js_colors.js.map.png

検索とかページングとかソートとかの動作もうまく動いているようですログインページへ飛ばされて
http://172.16.0.100:8000/login

ヘッダーとフッターの環境設定

ヘッダーとフッターを環境変数から取得するようにしてあるので

resources/js/components/AdminComponent.vue
~~
    mounted() {
      console.log('AdminComponent mounted.')

      if (process.env.MIX_FOOTER) { this.footer = process.env.MIX_FOOTER }
      if (process.env.MIX_TITLE) { this.title = process.env.MIX_TITLE }
    },
~~

環境変数を設定

.env
~~

MIX_FOOTER="フッター文字列を指定"
MIX_TITLE="タイトル指定"

末尾に定義を追加

ついでにVuetifyの色設定も変更してみる

resources/js/app.js
~~~
Vue.use(Vuetify, {
  theme: {
    primary: colors.amber.base,
~~~

indigo 指定を amber 指定に変更

コンパイルして再表示

npm run dev
php artisan serve --host=172.16.0.100  --port=8000

色とタイトルとフッターが変わったよ
172.16.0.100_8000_admin_user.png

以上
Vue-Router でページを切り替えて
Vuetify でデータテーブルを表示できました

ソースはこちら
https://github.com/u9m31/u9m31/tree/step04