本文書ではvue-cliコマンドを利用して作成したvueプロジェクトでのVue Routerの設定手順について説明を行なっています。最新のvue-cliのバージョンを利用するとVueのバージョンを選択することができます。本文書では最新バージョンのVue CLI v4.5.11で動作確認を行っているためVue2, Vue3の両方で動作確認を行っています。

Vue 2, Vue 3の両方の環境を使って説明を行っていますが本文書内でのバージョン間の違いはVueとRouterのインスタンス化に関するコードが記述されているmaiin.jsとrouter/index.jsファイルの2つとコンポーネントのroot要素が必ず1つという制限がVue3からなくなったことです。Vue Routerのルーティングの設定については違いはありません。

Vue Routerを利用することでページを移動する際にページの再読み込みを行わずページ内での更新が必要な箇所のみ更新が行われるためスムーズにページ遷移を行うことができます。Vue.jsでシングルページアプリケーションを構築したい場合はVue Routerを利用することになります。

Vue Routerを初めて使用する人であれば本文書を読む前に下記の文書を読んでVue Routerの基本を理解しておくことをおすすめします。

vue.jsのプロジェクトの作成

vue createコマンドを使ってvueプロジェクトの作成を行います。プロジェクトの名前は任意です。ここではvue-routerという名前で作成しています。指定した名前のフォルダがvueコマンドを実行したフォルダ内に作成されます。


 $ vue create vue-router

Vue CLI v4.5.11
? Please pick a preset: 
  Default ([Vue 2] babel, eslint) 
  Default (Vue 3 Preview) ([Vue 3] babel, eslint) 
❯ Manually select features 

プロジェクトの作成だけではなくRouterのインストールも同時に行うので、manually select features(手動での機能選択)を選択してください。manually select featuresではインストールする機能を選択できるので、Routerを選択してください。他の機能を使う予定がある場合は他のものも選択して進めてください。

Vue Routerを含め、表示される機能についてはプロジェクト作成後でもvue addコマンドを利用して追加機能をインストールすることは可能です。

? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
 ◉ Choose Vue version
 ◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
❯◉ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

Vueのバージョンの選択画面が表示されます。2.xまたは3.xを選択してください。


? Choose a version of Vue.js that you want to start the project with (Use arrow 
keys)
❯ 2.x 
  3.x (Preview) 
Vue Routerをどちらのバージョンでも利用することができますが、Vue 2ではVue Routerのバージョンは3.2.0ではVue 3ではバージョンは4.0.0と違いがあります。

次にhistory mode(ヒストリーモード)を使用するかどうか聞かれるのでYを選択してください。


? Use history mode for router? (Requires proper server setup for index fallback 
in production) (Y/n) 
モードにはhistoryとhashがあり、hashを選択するとURLに#が付与されます。例えば/aboutのURLは/#/aboutになります。本文書の後半でモードを変更し、動作確認を行います。

linterを聞かれるので選択を行なってください。本文書では、デフォルトのままでEnterを押します。


? Pick a linter / formatter config: (Use arrow keys)
❯ ESLint with error prevention only
  ESLint + Airbnb config
  ESLint + Standard config
  ESLint + Prettier

本文書ではLint on saveのままEnterを押します。


? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i
> to invert selection)
❯◉ Lint on save
 ◯ Lint and fix on commit

下記ではpackege.jsonを選択します。


? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? (Use arrow keys)
  In dedicated config files
❯  In package.json

今回の設定を保存するのか聞かれますがNを選択します。


? Save this as a preset for future projects? (y/N)

ここまでの選択が完了するとインストールが開始されます。

インストールが完了したら作成したディレクトリに移動して、npm run serveコマンドを実行してください。


$ cd vue-router/
$ npm run serve
  ・
  ・
 DONE  Compiled successfully in 5661ms                               

  App running at:
  - Local:   http://localhost:8080/
  - Network: http://192.168.2.114:8080/

  Note that the development build is not optimized.
  To create a production build, run npm run build.

実行後、ブラウザでhttp://localhost:8080/にアクセスすると下記の画面が表示されます。Vue Routerのインストールを行っているのでページ上部にHomeとAboutのリンクが表示されルーティングがデフォルトで設定されています。ルーティングが自動で設定されているためその設定コードを見ながらVue Routerの理解を深めることができます。

インストール直後の画面
インストール直後の画面

構成ファイルの確認

インストールが完了するとnode_modules、public, srcの3つのフォルダが作成されます。

srcフォルダの中でアプリケーションコードを記述していきます。アプリケーションコードの中でもっとも重要なメインファイルであるmain.jsファイルでVue Routerの設定を確認していきます。

main.jsファイルの確認(Vue3)

Routerをインストールするとmain.jsファイルではimport router from ‘./router’が追加されています。インポートされているrouterはsrcフォルダの下にあるrouterフォルダのindex.jsファイルです。index.jsファイルの名前の場合はindex.jsファイルの名前を省略しても自動でrouterフォルダにあるindex.jsファイルをimportしてくれます。createAppでVueのインスタンスを作成し、useメソッドでimportしたrouterを指定後にmounteメソッドでidがappを持つdiv要素にマウントしています。<div id=”app”>の内側がvue.jsの制御下に置かれることになります。


import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')

main.jsファイルの確認(Vue2)

Routerをインストールするとmain.jsファイルではimport router from ‘./router’が追加されています。インポートされているrouterはsrcフォルダの下にあるrouterフォルダのindex.jsファイルです。index.jsファイルの名前の場合はindex.jsファイルの名前を省略しても自動でrouterフォルダにあるindex.jsファイルをimportしてくれます。

$mount(‘#app’)によりpublicのindex.htmlにある<div id=”app”>にvue.jsがマウントされます。<div id=”app”>の内側がvue.jsの制御下に置かれることになります。


import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

router.jsファイルの確認(Vue3)

routerフォルダのindex.jsファイルにはルーティングに関する情報が記述されてVue Routerの設定ファイルです。/(ルート)と”/about”の2つのルーティングがroutesオブジェクトに登録されています。pathとnameとcomponentのプロパティが各ルーティングに設定されています。pathに設定したURLにアクセスした場合にcomponentに指定したコンポーネントファイルの中身が表示されます。nameは後ほどの名前付きルートで説明します。

createRouterメソッドでrouterのインスタンスを作成してexportを行っています。aboutのコンポーネントはlazy-loadedが設定されており、ブラウザから/aboutへのアクセスがあった場合にAbout.vueコンポーネントが読み込まれます。


import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

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

export default router
ヒストリーモードをhashに変更したい場合はcreateWebHistoryからcreateHashHistoryに変更します。

router.jsファイルの確認(Vue2)

router/index.jsファイルにはルーティングに関する情報が記述されています。ルーティングには”/”(ルート)と”/about”の2つが登録されています。aboutのコンポーネントはlazy-loadedが設定されており、ブラウザから/aboutへのアクセスがあった場合にAbout.vueコンポーネントが読み込まれます。


import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'

Vue.use(Router)

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
    }
  ]
})

lazy-loadedの設定について

lazy-loadedを設定しない場合、大きなサイズのvueファイルが存在するとビルドされて作成されるjsファイルも大きくなります。jsファイルのファイルサイズが大きい場合ブラウザからアクセスがあるとjsファイルの読み込みに時間がかかってしまうため、遅延を解消する目的でアクセスのあった場合のみ読み込みを行うlazy-loadedが使われています。

App.vueファイルの確認

main.jsの中でApp.vueファイルが指定されているのでブラウザからアクセスがあると最初にApp.vueファイルに記述されている内容がブラウザ上に描写されます。

App.vueファイルのtemplate部分がルーティングに関して重要な部分なので内容を確認していきます。


<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <router-view/>
  </div>
</template>
Vue2ではコンポーネントのroot要素が1つという制限があったため上記のようにdiv id=”app”が必要ですが、Vue3ではその制限がないためdiv id=”app”がありません。

templateタグの中にはdivタグもありますが、Vue Routerに必須なrouter-linkとrouter-viewという2つのタグを確認することができます。この2つのタグがVue Routerに関連するタグで、それぞれ以下のような役割を持っています。

  • router-linkタグはリンクを作成するために使用します。
  • router-viewタグは、それぞれのリンク先に紐づいた内容を表示するために使用します。

ブラウザに表示される画面とrouterタグの関係は以下の通りです。上部のHomeとAboutがrouter-linkタグによって作成され、その下の大きな赤線で囲んだ部分がrouter-viewタグによって作成されています。

routerタグと描写の関係
routerタグと描写の関係

Home.vue, About.vueファイルについて

router-linkタグでtoに設定されている”/”(ルート)と”/about”は/route/index.jsファイルに記述されているroutesプロパティのpathに対応します。”/”(ルート)にアクセスするとコンポーネントのHomeの内容がrouter-viewタグの場所に表示されます。


routes: [
  {
    path: '/',
    name: 'Home',
    component: Home
  },

Home.vueの中を確認するとHelloWorldタグを使っており、HelloWorld.vueがimportされていることがわかります。”/”(ルート)にアクセスした時に表示される内容は大半がHelloWorld.vueに記述されている内容です。


<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'home',
  components: {
    HelloWorld
  }
}
</script>

About.vueはシンプルで、他のvueファイルを読み込まずh1タグでThis is an about pageを記述しているのみです。


<template>
  <div class="about">
    <h1>This is an about page</h1>
  </div>
</template>

これをブラウザから見ると下記のように表示されます。Home、Aboutのrouter-linkタグの部分は”/”(ルート)と同じ内容で、router-viewタグの部分がAbout.vueのtemplateタグの中で記述した内容が表示されています。

Aboutページ
Aboutページ

“/about”ページがどのように設定されているかわかれば追加ページを作成することは簡単です。

postページを追加する

/aboutページを参考にpostページを追加してみましょう。

App.vueファイルへのrouter-linkの追加

最初にApp.vueにrouter-linkタグを追加します。router-linkタグのtoには/postを設定しています。


<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link>
      <router-link to="/about">About</router-link>
      <router-link to="/post">Post</router-link>
    </div>
    <router-view/>
  </div>
</template>

npm run serverを実行している場合は、router-linkを追加して保存するとビルドが自動で実行されブラウザに即座に変更内容が表示されます。HomeとAboutと横にPostの文字列が表示され、リンクが貼られている状態になります。

Postのリンクが追加
Postのリンクが追加

リンクが貼られているのでPostの文字列をクリックすることが可能でPostのリンクをクリックすると画面は移動しますが何も上部のリンク以外にはページには何も表示されません。

何も表示されない
何も表示されない

ページに何も表示されない理由は、router-linkを追加しただけ/postに関するルーティングの追加もルーティングに対応するvueファイルも作成していないためです。/postにアクセスした際にページが表示されるように/router/index.jsファイルに新たにpostに関するルーティンの追加を行います。

ルーティングの追加

/router/index.jsファイルを開いてルーティングを追加します。aboutのルーティングを参考に/aboutのルーティングの下にpostのルーティングを追加します。


{
  path: '/post',
  name: 'post',
  component: () => import(/* webpackChunkName: "post" */ './views/Post.vue')
},

上記の内容で保存を行うとPost.vueファイルが存在しないためビルドでエラーが発生します。

vueファイルの作成

About.vueと同様にviewsディレクトリの下にPost.vueファイルを作成します。作成したPost.vueファイルには以下を記述します。


<template>
  <div class="post">
    <h1>This is a post page</h1>
  </div>
</template>

/postに移動するとようやく下記の画面が表示されます。このようにデフォルトで作成されているaboutページを参考に設定を行うことで追加のページも簡単に作成することができます。

postページ
postページ

動的ルートの設定

ここまで3つのルーティングの設定を行ってきましたが/(ルート)にアクセスするつHome.vue, /aboutにアクセスするとAbout.vue, /postにアクセスするとPost.vueのファイルの内容が表示されURLと表示される内容が1対1に対応していました。

一般的なブログでよく見かける各記事のページのURLが/post/1, /post/2といった動的に変わる場合はVue Routerではどのように対応すればいいのか説明を行っていきます。

動的ルートの動作確認を行うためにidとtitleを持つオブジェクトを3つ持った配列postsをデータプロパティにに設定します。


<template>
  <div class="post">
    <h1>This is an Post page</h1>
</template>
<script>
export default {
  data(){
    return {
      posts: [
        {
          id:1,
          title:'vue.js'
        },
        {
          id:2,
          title:'react'
        },
        {
          id:3,
          title:'alpine.js'
        }
      ]
    }
  }
}
</script>

設定したデータプロパティpostsをv-forディレクティブで展開して展開したtitleに対してroute-linkタグでリンクをj貼ります。


<template>
  <div class="post">
    <h1>This is an Post page</h1>
    <div v-for="post in posts" :key="post.id">
        <router-link :to="`/post/${post.id}`">
        {{ post.title }}
        </router-link>
      </div>
  </div>
</template>
</script>

ブラウザ上ではpostsに設定した3つのタイトルが表示されます。

postsをv-forで展開しリンク設定
postsをv-forで展開しリンク設定

各タイトルにはリンクを貼っているのでクリックすることはできますが、クリックした先のページでは何も表示されません。/post/1, /post/2, /post/3に対応したルーティングが設定されていないことが原因なのでルーティングの追加を行います。

ルーティングの設定

/router/index.jsファイルにルーティングの設定を追加する必要がありますが動的ルートの場合はアクセスするURLの値が変わるので値が変わる部分は:idとします。idは任意の名前なので変更することは可能で、対応するコンポーネントにはPostShow.vueを設定します。


{
  path: '/post/:id',
  name: 'PostShow',
  component: () => import(/* webpackChunkName: "about" */ '../views/PostShow.vue')
},

PostShow.vueファイルはPost.vueファイルを元に作成を行います。


<template>
  <div class="post">
    <h1>This is an Post Show page</h1>
  </div>
</template>

設定後再度postページに表示されているリンクをクリックするとPostShow.vueファイルに記述した内容が表示されます。Postページに表示されている3つのリンクのどれをクリックしても表示されている内容は同じものとなります。

PageShow.vueの内容が表示される
PageShow.vueの内容が表示される

動的に変わるIDの値の取得方法

内容は同じですが各タイトルのリンク先であるURLは/post/1, /post/2, /post/3のように異なっています。PostShowページの内容は表示されたので次に/postの後ろについている値を取得する方法を確認します。ルーティングに関する情報は$routeオブジェクトに保存されており、コンポーネント上からアクセスすることができます。ライフサイクルフックのmountedでconsole.logを利用してにどのような情報が$routeに入っているか確認します。


<script>
export default {
  mounted(){
    console.log(this.$route)
  }
}
</script>

設定後にブラウザのデベロッパーツールを確認すると$routeオブジェクトの中身が表示されます。fullPathなどでもidの値を確認することができますがparamesのオブジェクトにid:”2″を確認することができます。このことから取得したいidの値は$route.params.idに保存されていることがわかります。

$routeオブジェクトの中身
$routeオブジェクトの中身

$route.parames.idを利用してブラウザ上にidの値を表示させてみましょう。


<template>
  <div class="post">
    <h1>This is an Post Show page</h1>
    <div>{{ $route.params.id }}</div>
  </div>
</template>
idは$route.params.idによって取得できましたが、アクセスしたURLを取得したい場合は $route.params.path, /post/1?test=aaaaのtest=aaaaなどを取得したい場合は$route.params.queryなどを利用することができます。

設定後には各リンクをクリックすると表示されるページ毎に異なる数字が表示されます。

idをブラウザ上に表示
idをブラウザ上に表示

このように動的に変わるURLのidの値を取得することができました。idを取得することはできましたがどのようにページ毎に表示される内容をidによって動的に変更するのでしょう。通常だとidを使って外部のサーバにアクセスを行いサーバから取得した個別のデータを取得することになります。本文書では外部のサーバを用意していないのでPostに設定したpostsデータをPostShow.vueコンポーネントでも再利用します。

$route.params.idで受け取った値とfindメソッドを利用してidの一致するpostを取得してブラウザ上に表示させます。


<template>
  <div class="post">
    <h1>This is an Post Show page</h1>
    <div>{{ post.id }}</div>
    <div>{{ post.title }}</div>
  </div>
</template>
<script>
export default {
  data(){
    return {
      posts: [
        {
          id:1,
          title:'vue.js'
        },
        {
          id:2,
          title:'react'
        },
        {
          id:3,
          title:'alpine.js'
        }
      ]
    }
  },
  computed:{
    post(){
      return this.posts.find(post => post.id == this.$route.params.id)
    }
  },
  mounted(){
    console.log(this.$route)
  }
}
</script>

リンク毎に異なる内容を表示することができます。下記ではidを3を持つpostの内容を表示しています。

リンク毎に異なる内容を表示
リンク毎に異なる内容を表示

propsを利用してidを渡す方法

idは$route.paramsから取得することができましたがpropsを利用してidを渡すこともできます。propsを利用する場合は/router/index.jsでpropsプロパティをtrueに設定する必要があります。


{
  path: '/post/:id',
  name: 'PostShow',
  component: () => import(/* webpackChunkName: "about" */ '../views/PostShow.vue'),
  props:true,
},

PostShow.vueコンポーネント側でのpropsの設定方法については従来の設定方法と同じです。受け取るpropsの型やrequiredプロパティを設定することができます。computedプロパティのfindメソッドでは$route.params.idからpropsで受け取ったthis.idへの変更も忘れずに行います。


<template>
  <div class="post">
    <h1>This is an Post Show page</h1>
    <div>{{ post.id }}</div>
    <div>{{ post.title }}</div>
  </div>
</template>
<script>
export default {
  props:{
    id:{
      type:String,
      required:true,
    }
  },
  data(){
    return {
      posts: [
        {
          id:1,
          title:'vue.js'
        },
        {
          id:2,
          title:'react'
        },
        {
          id:3,
          title:'alpine.js'
        }
      ]
    }
  },
  computed:{
    post(){
      return this.posts.find(post => post.id == this.id)
    }
  },
  mounted(){
    console.log(this.$route)
  }
}
</script>

propsを使っても同じようにリンク毎に異なる内容のページを表示させることができます。

propsを利用してページを表示
propsを利用してページを表示

404 Not Foundページの設定

ここまでの設定でルーティングに存在しないURL(/pfadfastfsa)にアクセスを行うとコンソールにはメッセージが表示されますがブラウザには何も表示されません。


vue-router.esm-bundler.js?6c02:71 [Vue Router warn]: No match found for location with path "/pfadfasfsa"

routesオブジェクトにpath: ‘/:pathMatch(.)‘,を設定していますが、設定値はVue Routerのバージョン4のドキュメントの値を利用しています。routesオブジェクトの先頭に追加していますが最後に追加しても動作は変わりません。


import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import NotFound from '../views/NotFound.vue'

const routes = [
  { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
  {
    path: '/',
    name: 'Home',
    component: Home
  },
//略
Vue Routerのバージョン3の場合は{ path: ‘*’, name: ‘NotFound’, component: NotFound }を設定しましたがバージョン4で設定するとコンソールにvue-router.esm-bundler.js?6c02:1307 Uncaught Error: Catch all routes (“*”) must now be defined using a param with a custom regexp.のエラーメッセージが表示されNotFound 404ページは表示されません。

NotFound.vueファイルの作成を行います。


<template>
  <div class="post">
    <h1>404 Not Found</h1>
  </div>
</template>

設定後に先ほどアクセスして何も表示されなかったルーティングに存在しないURL(/pfadfastfsa)にアクセスします。404 Not Foundが画面に表示されれば設定は問題なく行われています。/(ルート), /about, /postにアクセスするとこれまでのように各ページの内容が表示されることも確認してください。

404ページの表示
404ページの表示

404は存在しないURLにアクセスした場合にユーザにそのページは存在しないというるHTTPのステータスコードの404を意味します。通常のWebサーバを利用している場合はサーバからステータスコード404が戻されます。Vue Routerでは404 Not Fuondの設定前にルーティングに存在しないページにアクセスするとステータスコードは304 Not Modifiedが戻され、404 Not Foundを設定するとステータスコード200が戻されます。Vue Routerではクライアント側(ブラウザ)でルーティング処理が行われているためです。存在しないURLにアクセスした場合にステータスコードの404を戻すためにはサーバ側の設定が必要となります。

次にデータプロパティpostsに存在しない/posts/4にアクセスを行ってみましょう。ページには何も表示されておらずコンソールには”Uncaught (in promise) TypeError: Cannot read property ‘id’ of undefined”が表示されます。idを4を持つpostが存在しないためにエラーが発生しているのでv-ifディレクティブを利用して分岐を行うことで問題を回避することができます。


<template>
  <div class="post" v-if="post">
    <h1>This is an Post Show page</h1>
    <div>{{ post.id }}</div>
    <div>{{ post.title }}</div>
  </div>
  <div class="post" v-else>
    <h1>404 Not Found</h1>
  </div>
</template>

設定後に/posts/4にアクセスすると404 Not Foundが表示されます。

404ページの表示
404ページの表示

名前付きルートの設定

routes/index.jsファイル内のルーティングの設定ではルーティング毎にpath, name, componentを設定していました。ここまではpathとcomponentのみ利用していましたがnameは利用していません。nameを利用してリンクを設定することができます。nameを利用した場合はroute-linkでtoにURL(pathの値)を指定するのではなくオブジェクトでnameを設定することができます。実際に変更すると以下のようになります。


  <div id="nav">
    <router-link :to="{name:'Home'}">Home</router-link> |
    <router-link :to="{name:'About'}">About</router-link>
  </div>
  <router-view/>

nameを利用することでroute/index.jsファイルのpathを変更してもコードの変更を行う必要がなくなります。nameを利用していな場合にroute-linkタグでさまざまなコンポーネント上でリンクを貼っている場合は各タグのtoの値を変更する必要があります。例えばpathをaboutからaboutusに変更した場合にnameを利用している場合はrouter-linkの設定を変更する必要がありませんがnameを利用していな場合はtoの値をaboutからaboutusに変更する必要があります。

先ほど新たにルーティングにPostページを追加しました。

モードの変更(Vue2)

これまではhistoryモードで動作確認を行いましたが、別のモードであるhashモードではどのようにルーティング行われるのか確認します。

route.jsファイルに記述されているmode行をコメントします。


export default new Router({
  // mode: 'history',
  base: process.env.BASE_URL,

ブラウザでhttp://localhost:8080/にアクセスするとURLに#がlocalhost:8080/#/となります。

#が入ったURL
#が入ったURL

aboutページに移動しても#が入ったURL(localhost:8080/#/about)となります。

aboutページのURLにも#
aboutページのURLにも#