Vue3 + Vuetify3 + vue-router の組み合わせでプロジェクトを作成するときのメモ

# 主旨

vuetify3 と vue-router を同時に使うときのメモです。Vue3 を使います。

# 問題

`yarn create vuetify` で vue-router を使用する設定 (base) を使ってプロジェクトの初期化を行うと、`src/layouts` というディレクトリが作成されます。具体的には、下記のようにしてプロジェクトの初期化をした場合です。

```bash
$ yarn create vuetify
....
✔ Project name: … vue-router-vuetify3
✔ Which preset would you like to install? › Base (Vuetify, VueRouter)
✔ Use TypeScript? … No / Yes
✔ Would you like to install dependencies with yarn, npm, pnpm, or bun? › yarn
```

`src/layouts` 以下に追加されるコードは、Nuxt.js の `layouts`っぽい機能を実現できるようにするためのものです（多分）。`src/layouts` 以下のファイルを使うと、これまでの書き方に比べてページごとに異なるレイアウトを適用しやすくなります。

とはいえ、vuetify2 時代の書き方と変わる部分もあるので、これまでの書き方を踏襲したいということもあるかと思います。

そこで、以下では「従来に近い書き方をする方法」と「`layouts`を使う方法」の両方についてメモしておきます。

# 自力で後から vue-router を入れて vue2 時代っぽく書く

Vuetify2/Vue2 の時代に自力で `yarn add vuetify vue-router` などとしていた場合は、この方法が一番近い感じになります（多分）。

```bash
$ yarn create vuetify
...
✔ Project name: … legacy-vuerouter-vuetify3
✔ Which preset would you like to install? › Default (Vuetify)
✔ Use TypeScript? … No / Yes
✔ Would you like to install dependencies with yarn, npm, pnpm, or bun? › yarn
```

上記のように vue-router を含めないようにプロジェクトを作成します。次に、プロジェクトのディレクトリに入って `yarn add vue-router` します。

```bash
$ cd legacy-vuerouter-vuetify3
$ yarn add vue-router
```

この方法で `vue-router` を追加すると、`vue-router` のモジュール自体はプロジェクトに追加はされますが、`vue-router` を使うためのコードは自力で追加する必要があります。

具体的には、下記のファイルの変数および作成をします。

- `App.vue`: 編集
- `main.js`: 変数
- `src/router/index.js`: 作成
- `src/view/Home.vue`: 作成

最終的なファイル構成は下記のようになります。

```bash
$ tree src
src
├── App.vue
├── main.js
├── plugins
│   ├── index.js
│   └── vuetify.js
├── router
│   └── index.js
└── views
    └── Home.vue
```

## `src/App.vue`

繊維先のページを展開する `<router-vue/>` 要素をページ内に追加します。

```src/App.vue
<template>
  <v-app>
    <v-main>
      <router-view />
    </v-main>
  </v-app>
</template>

<script setup>

</script>
```

## `src/main.js`

```src/main.js
// Plugins
import { registerPlugins } from '@/plugins'
import router from './router' // 追加

// Components
import App from './App.vue'

// Composables
import { createApp } from 'vue'

const app = createApp(App).use(router) // 追加

registerPlugins(app)

app.mount('#app')
```

`vue-router` を読み込むコードと、アプリ内で使用するためのコードを追加します。上記のコードは、Vuetify2 時代のコードにやファイル構成近づけるようにわざと 'router/index.js` を読むようにしていますが、後述するように `plugin` 以下においた `vue-router` の初期化用のコードを読み出すようにすることもできます（その方法が今後のスタンダードになりそうです）。

## `src/router/index.js`

`vue-router` モジュールの初期化を行うコードを書きます。以下では、`/` に遷移したときに、`../views/Home.vue` を読み込んで `<router-view/>` の要素の位置に展開するように設定しています。

```src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router
```

## `src/views/Home.vue`

`/` に遷移したときに表示されるページの内容を記述します。下のコードは、Hello! というテキストが書かれたボタンがひとつあるページになっています。

```src/views/Home.vue
<template>
  <div>
    <v-btn color="primary">
      Hello!
    </v-btn>
  </div>
</template>
```

## テスト

```bash
$ yarn dev
```

ブラウザで `http://localhost:3000` にアクセスして、下記のような画面が出たら成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d63ba28e-17af-bf7b-7a36-d509d0ee458d.png)

## `/about` のページを追加

繊維先のいページを夜やしたい時は、`src/router/index.js` に繊維先のページの情報を追加し、実際に遷移したときに表示するページ内容を記述した `.vue` ファイルを追加します。

```bash
$ tree src
src
├── App.vue
├── main.js
├── plugins
│   ├── index.js
│   └── vuetify.js
├── router
│   └── index.js
└── views
    ├── About.js
    └── Home.vue
```

ファイル構成は上記のようになります。

```src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/Home.vue'
import AboutView from '../views/About.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    component: AboutView
  },
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router
```

`/about` の繊維先のページには、ABOUT！　と書かれたボタンをひとつ配置してみます。

```src/views/About.vue
<template>
  <div>
    <v-btn color="secondary">
      About!
    </v-btn>
  </div>
</template>
```

上記のようにファイルの書き換え、追加をしてから `yarn dev` とすると、http://localhost:3000/about` をブラウザで開いた時に下記の画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/1d57993d-74ef-354c-9cd7-1279290d95ad.png)

## ボタンを押したらページ遷移する

`/` と `/about` のページの間で、相互にページ遷移させる例も書いておきます。遷移の方法自体は、Vuetify とは関係なく `vue-router` の一般的な方法をそのまま使います。

```src/views/Home.vue
<template>
  <v-container>
    <p class="text-h5 my-2">ここは / です</p>

    <div>
      <v-btn color="primary" @click="$router.push('/about')">
        GO TO ABOUT
      </v-btn>
    </div>

    <router-link class="text-h6" to="/about">To About</router-link> |
  </v-container>
</template>
```

`<router-link>`　を使うと、ページ遷移のためのアンカーを設置できます。ただしアンカー扱いにあるので、スタイルはアンカー（またはテキスト）のものが適用されます。

ボタンなどのコンポーネントを操作したときに遷移させる場合は、`$router.push()`　を使います。Vuetify のコンポーネントを使って遷移させたい場合は、こちらの方法のほうが適しています。

```src/views/About.vue
<template>
  <v-container>
    <p class="text-h5 my-2">ここは /about です</p>

    <div>
      <v-btn color="secondary" @click="$router.push('/')">
        GO TO HOME
      </v-btn>
    </div>

    <router-link class="text-h6" to="/">To Home</router-link> |
  </v-container>
</template>
```

上記のようにコードを変更すると、`/` と `/about` のページとの間で、相互に遷移できるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/458d9e14-faca-7e45-a3dc-eb80c3e0abe3.png)

## ページ遷移しても変化しない固定レイアウト(Application Barなど）部分の記述

Application Bar や　Nativation Drawer などの固定レイアウト部分は、`src/App.vue` の中に記述します。

```App.vue
<template>
  <v-app>
    <v-app-bar color="primary">

      <v-app-bar-nav-icon 
        variant="text"
        @click.stop="drawer = !drawer">
      </v-app-bar-nav-icon>

      <v-app-bar-title>
        Application
      </v-app-bar-title>
    </v-app-bar>

    <v-navigation-drawer
      v-model="drawer"
      >
      <v-list>
        <v-list-item title="Home" value="home" @click="$router.push('/')"></v-list-item>
        <v-list-item title="About" value="about" @click="$router.push('/about')"></v-list-item>
      </v-list>
    </v-navigation-drawer>

    <v-main>
      <router-view />
    </v-main>

    <v-footer app color="primary">
      超Lチカ団 (c) 2023
    </v-footer>
  </v-app>
</template>

<script setup>
import {ref} from 'vue';
const drawer = ref(false);
</script>
```

ページ遷移したときに表示を変更したい部分に `<router-view />`　を設置します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d403bf6e-83af-8137-c74b-b0b82029a55e.png)

`layouts` を使わない場合は、このように `App.vue` の中に固定レイアウトの部分を直接書き込みます。この方法は、遷移によって変更される部分が　`<router-view />` の位置と一致しているので、ページの構成が直感的に把握しやすいです。

反面、遷移するページによって固定レイアウトの部分に変更を加えたいときは多少の工夫が必要になります。

## `src/plugins` に vue-router の初期化コードを書く

`yarn create vuetify` としてプロジェクトを初期化すると、vuetify 関連の初期化コードは `src/plugins` 内に配置されます。この作法に従って　vue-router 関連のコードも `src/plugins` 内に配置するには　`src/plugins/router.js` に従来の `src/router/index.js` に相当するコードを書き、`src/plugins/index.js` で `app.use(router)`　とします。

このようにすると、プラグイン関連のコードは `src/plugins` 内のコードを編集するだけでよくなり、`src/main.js` を変更しなくてよくなるため、全体のコードの見通しが良くなります（バグが減る）。

```bash
src
├── App.vue
├── main.js
├── plugins
│   ├── index.js
│   ├── router.js
│   └── vuetify.js
└── views
    ├── About.vue
    └── Home.vue
```

ファイル構成は上記のようになります。

```src/plugins/router.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/Home.vue'
import AboutView from '../views/About.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    component: AboutView
  },
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router
```

`src/plugins/router.js` に書くコードは、従来の `router/index.js`　の中身と全く同じです。

```src/plugins/index.js
import vuetify from './vuetify'
import router from './router'

export function registerPlugins (app) {
  app.use(vuetify)
  app.use(router)
}
```

`src/plugins/index.js` の中で `router.js` を読み込んで `app.use(router)` として vue-router を初期化するようにコードを書き換えます。このようにした場合、`src/main.js` は `yarn create vuetify` したときのままでOKです（編集の必要はありません）。

```src/main.js
// Plugins
import { registerPlugins } from '@/plugins'

// Components
import App from './App.vue'

// Composables
import { createApp } from 'vue'

const app = createApp(App)

registerPlugins(app)

app.mount('#app')
```

同様にして `webfontloader` のような初期化が必要なプログインを追加するときも、`src/plugins` に初期化のコードを追加するようにすることで、プラグイン関連のコードが `src/plugins` にまとまり、コード全体の見通しが良くなります。

# `src/layouts` に Application Bar などの固定レイアウト部分を記述する方法

`yarn create vuetify` としたときに、VueRouter を使う設定 (Base (Vuetify, VueRouter))　を使って初期化すると、`src/layouts` というディレクトリが作成されます。具体的には、下記のようにして初期化した場合です。

```bash
$ yarn create vuetify
....
✔ Project name: … vue-router-vuetify3
✔ Which preset would you like to install? › Base (Vuetify, VueRouter)
✔ Use TypeScript? … No / Yes
✔ Would you like to install dependencies with yarn, npm, pnpm, or bun? › yarn
```

以下は、この作法に従って、繊維先のページと固定レウアウトの部分を記述する方法についてのメモです。ルートのページ `/` を表示したときの見かけが、下記のようになるようにファイルを変数、追加していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/ccf208a6-c490-19b1-e076-0e51c84c9c66.png)

このページで　"GO TO ABOUT" と書かれたボタンをクリックするか、"To About" のアンカーをクリックすることで、`/about` に遷移するようにします。

`/about` のページの見かけは下記のようにします。"GO TO HOME" と書かれたボタンをクリックするか、"To Home" のアンカーをクリックすることで、`/` に遷移するようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/5d35dd43-95c8-bb89-4393-0f8c00ebab60.png)

また、Navigation Drawer　を使って各ページへ遷移できるようにもします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/8111746f-258d-966b-8fcc-62652cea7e88.png)

サイトの基本的なページ構成は「自力で後から vue-router を入れて vue2 時代っぽく書く」の項目で書いたものと同一になるようにしています。

## ファイル構成

ファイル構成は下記のようになります。プロジェクト初期化時に存在していないファイルには `#　追加` というコメントを入れています。

```bash
$ tree bash
src
├── App.vue
├── layouts
│   └── default
│       ├── AppBar.vue　　　　　　# 編集
│       ├── Default.vue　　　　# 編集
│       ├── Footer.vue 　　　　# 追加
│       └── View.vue     # 編集
├── main.js
├── plugins
│   ├── index.js
│   └── vuetify.js
├── router
│   └── index.js    　# 編集
└── views
　　   ├── About.js    # 追加
    └── Home.vue　　　　　　　　# 追加
```

## ざっくりした説明

`src/App.vue` に固定レウアウト部分を記述するのではなく、ページ全体のレイアウトを　`src/layouts`　以下にまとめて書きます。ページのレイアウトを `layouts` 以下に作ったディレクトリ毎にまとめて書いておき、表示する側のページでレイアウトを読み込んで適用するというイメージです。

`layouts` 以下のファイルの読み込みは、vue-router の設定ファイル `router/index.js` の中に書きます。

## `src/router/index.js`

`component: () => import('@/layouts/default/Default.vue')` というコードで、`layouts/default/Default.vue` をコンポーネントとして読み込んでいます。読み込んだコンポーネントは、`path: '/'` 以下の全てのページ（子ページ、孫ページ）で、最上位のコンポーネントとして使われます。

```router/index.js
// Composables
import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  {
    path: '/',
    component: () => import('@/layouts/default/Default.vue'),
    children: [
      {
        path: '',
        name: 'Home',
        component: () => import('@/views/Home.vue'),
      },
      {
        path: 'about',
        name: 'About',
        component: () => import('@/views/About.vue'),
      },
    ],
  },
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes,
})

export default router
```

## `src/App.vue`

```src/App.vue
<template>
  <router-view />
</template>

<script setup>
</script>
```

`src/App.vue` の中身は非常にシンプルです。`<router-view/>` の部分が、遷移先のページの内容に置き換えて表示されます。ただし、前記の`src/router/index.js`では `/` 以下の全てのページで `src/layouts/default/Default.vue` を読むように指定されているため、`<router-view/>` の部分は常に`src/layouts/default/Default.vue`　の内容で置き換えられることになります。

## src/layouts/default/Default.vue

このコンポーネントが、すべてのページの最上位コンポーネントとして使われます。このコンポーネントの中で、Application Bar と Navigation Drawer を配置している　`AppBar.vue`　と、遷移先のページを表示するための `View.vue`、Footer を配置している `Footer.vue` をそれぞれ読み込み、ページ内に配置しています。

```src/layouts/default/Default.vue
<template>
  <v-app>
    <default-bar />
    <default-view />
    <default-footer />
  </v-app>
</template>

<script setup>
  import DefaultBar from './AppBar.vue'
  import DefaultView from './View.vue'
  import DefaultFooter from './Footer.vue'
</script>
```

## src/layouts/default/View.vue

このファイルは、'/' 以下の個々のページの内容を表示させるためのものです。

```src/layouts/default/View.vue
<template>
  <v-main>
    <router-view />
  </v-main>
</template>

<script setup>
  //
</script>
```

`<router-view />` の部分には、`router/index.js` で `/` のパスの `children` で定義されている各パスに対応する components が読み込まれて置き換えられます。

```src/router/index.js
const routes = [
  {
    path: '/',
    component: () => import('@/layouts/default/Default.vue'),
    children: [
      {
        path: '',
        component: () => import('@/views/Home.vue'),
      },
    　　　{
        path: 'about',
        component: () => import('@/views/About.vue'),
      },
    ]
  }
]
```

上記のように `src/router/index.js` が定義されていると、vue-router は以下のような処理を行います。

- `App.vue` 内にある `<router-view/>` は `const routes` の最上位の component で置き換えられます。上記のコードの場合、最上位には `path: '/'` だけが定義されており、その中で `@/layouts/default/Default.vue`　を読み込んでいるので、 常に`Default.vue` の内容が　`Aue.vue` の　`<router-view/>`　の部分に読み込まれることになります。
- `Default.vue` 内にある　`<router-view/>`　は、コンポーネントが読み込まれたパスの子として定義されているパス内の component に置き換えられます。上記のコードの場合、`""` と `about` という二つのパスが定義されており、これらは実質的に `/` と `/about` というパス名として機能します。`/` に遷移したときは　`<router-view/>`　は　`views/Home.vue`　に置き換えられ、`/about` に遷移したときは　`<router-view/>`　は　`views/About.vue`　に置き換えられるという動作になります。

このような構造を利用することで、パスごとにレイアウトを統一したり、上位のページのレイアウトを下位のページで継承するような使い方ができます。

## src/layouts/default/AppBar.vue

固定レイアウトの Application Bar と Navigation Drawers を配置するためのファイルです。`Default.vue` から読み込まれます。

Navigation Drawer は　`/` と `/about` に遷移できるメニュー（リスト）を含んでいます。

```src/layouts/default/AppBar.vue
<template>
  <v-app-bar color="primary">

    <v-app-bar-nav-icon 
      variant="text"
      @click.stop="drawer = !drawer">
    </v-app-bar-nav-icon>

    <v-app-bar-title>
      Application
    </v-app-bar-title>
  </v-app-bar>

  <v-navigation-drawer
    v-model="drawer"
    >
    <v-list>
      <v-list-item title="Home" value="home" @click="$router.push('/')"></v-list-item>
      <v-list-item title="About" value="about" @click="$router.push('/about')"></v-list-item>
    </v-list>
  </v-navigation-drawer>
</template>

<script setup>
import {ref} from 'vue';

const drawer = ref(false);
</script>
```

## src/layouts/default/Footer.vue

固定レイアウトの Footer を配置するためのファイルです。`Default.vue` から読み込まれます。

```src/layouts/default/Footer.vue
<template>
  <v-footer app color="primary">
    超Lチカ団 (c) 2023
  </v-footer>
</template>

<script setup>
  //
</script>
```

## src/views/Home.vue

`/` に遷移したときに表示するページの内容です。`/about` へ遷移するためのボタンとアンカーを設置しています。

```src/views/Home.vue
<template>
  <v-container>
    <p class="text-h5 my-2">ここは / です</p>

    <div>
      <v-btn color="primary" @click="$router.push('/about')">
        GO TO ABOUT
      </v-btn>
    </div>

    <router-link class="text-h6" to="/about">To About</router-link> |
  </v-container>
</template>
```

## src/views/About.vue

`/about` に遷移したときに表示するページの内容です。`/` へ遷移するためのボタンとアンカーを設置しています。

```src/views/About.vue
<template>
  <v-container>
    <p class="text-h5 my-2">ここは / です</p>

    <div>
      <v-btn color="primary" @click="$router.push('/about')">
        GO TO ABOUT
      </v-btn>
    </div>

    <router-link class="text-h6" to="/about">To About</router-link> |
  </v-container>
</template>
```

## 動作テスト

以上のようにファイルの編集、追加を行なってから `yarn dev` します。`http://localhost:3000` をブラウザで開くと、下記のようなページが表示されるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b2650184-b8a8-e80a-3e2d-25697cce4702.png)

## ページ遷移したときのステータスの保持について

`App.vue` に Application Bar などを配置して、`<router-view/>` で遷移先のページを表示するという構造の場合は、ページ遷移がおきても `App.vue` 内に Application Bar が記述されています。このため、Application Bar で保持したいステータスがある場合でも、ページ遷移にかかわらずそのステータス保持されるだろうという期待ができます。

実際、`App.vue` を下記のように書いておくと、どのページに遷移しても `counter` の値は保持されます(`layouts`を使わない場合）。

```src/App.vue
<template>
<v-app>
  <v-app-bar color="primary">
    <v-app-bar-title>
      Application
    </v-app-bar-title>

    <template v-slot:append>
        <v-btn @click="counter++">
          Increse
        </v-btn>

        <v-btn variant="text">
          {{counter}}
        </v-btn>
      </template>
  </v-app-bar>
　　 <v-main>
      <router-view />
　　　　</v-main>
</v-app>
</template>

<script setup>
import {ref} from 'vue';

const counter = ref(0);
</script>
```

一方、`layouts` を使う場合は、ページ遷移するたびに `<router-view/>` の置き換えが行われ、そのたびに `AppBar.vue` が読み込まれる構造になっているので、`AppBar.vue` 内で保持したいステータスがあったときに、それが保持されるかについては若干不安があります。

```src/layouts/default/AppBar.vue
<template>
  <v-app-bar color="primary">
    <v-app-bar-title>
      Application
    </v-app-bar-title>

    <template v-slot:append>
        <v-btn @click="counter++">
          Increse
        </v-btn>

        <v-btn variant="text">
          {{counter}}
        </v-btn>
      </template>
  </v-app-bar>

</template>

<script setup>
import {ref} from 'vue';

const counter = ref(0);
</script>
```

結論から言えば、ステータスは保持されます。しかし、これは `src/router/index.js` が下記のように '/'  以下のパスへの遷移するときに、共通のコンポーネントとして　`layouts/default/Default.vue`　を読み込む構造になっているから、Default.vue の中で読み込まれている `AppBar.vue` のステータスが保持されているでけなのでは？という疑問もわきます。

```src/router/index.js
const routes = [
  {
    path: '/',
    component: () => import('@/layouts/default/Default.vue'),
    children: [
      {
        path: '',
        component: () => import('@/views/Home.vue'),
      },
    　　　{
        path: 'about',
        component: () => import('@/views/About.vue'),
      },
    ]
  }
]
```

そこで、`src/router/index.js` を書き換えて、'/' と '/about' で別々に　`layouts/default/Default.vue` を読み込むようにしてみます。このようにすると、'/' と '/about' で読み込まれる `Default.vue` は別のモジュール扱いになって、'/' と '/about'　との間で相互遷移させるとカウンターの値は保持されなくなりそうです。

```src/router/index.js
const routes = [
  {
    path: '/',
    component: () => import('@/layouts/default/Default.vue'),
    children: [
      {
        path: '',
        name: 'Home',
        component: () => import('@/views/Home.vue'),
      },
    ]
  },
  {
    path: '/about',
    component:  () => import('@/layouts/default/Default.vue'),
    children: [
      {
        path: '',
        name: 'about',
        component: () => import('@/views/About.vue'),    
      }
    ]
  }
]
```

で、結論としては「`AppBar.vue`内のステータスはやっぱり保持される」となりました。

ならば、`AppBar.vue` を読み込まないページを作って、そこへ遷移させたあとに再び `AppBar.vue` を読み込むページへ戻ったらどうなるでしょうか。

```router/index.js
const routes = [
  {
    path: '/',
    component: () => import('@/layouts/default/Default.vue'),
    children: [
      {
        path: '',
        name: 'Home',
        component: () => import('@/views/Home.vue'),
      },
    ]
  },
  {
    path: '/about',
    component:  () => import('@/layouts/default/Default.vue'),
    children: [
      {
        path: '',
        name: 'about',
        component: () => import('@/views/About.vue'),    
      }
    ]
  },
  {
    path: '/test',
    children: [
      {
        path: '',
        name: 'Test',
        component: () => import('@/views/Test.vue'),
      },
    ]
  },
]
```

```src/view/Test.vue
<template>
  test
</template>
```

これで '/', '/test', '/about' と遷移すると、さすがにステータス（カウンターの値）は保持されませんでした。まあ、これはそうなるだろうという感じですが、ページ遷移の順序や組み合わせの違いによって、ステータスが保持されたりされなかったりするのはやはり問題です。

以上のことから、`layouts` を使う場合で固定レイアウトのモジュール内で保持したいステータス（値）があるときは、横着せずに `App.vue` で保持するか、`vuex` などを使った方がよさそうです。

# 結論

`Nuxt.js` で `layouts` を使いましょう。