0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Vue.jsのRouter機能を、v-showによる疑似的な画面切り替えとの対比で理解する

Last updated at Posted at 2022-06-01

概要

Vue.js のRouter機能について、以下の観点で説明する。

  • divタグ単位でのv-if / v-showディレクティブでの表示切り替えから、Router機能を用いた表示切替へ、移行する
    • vue create 時に「Router」を選択するだけで「Router機能による切り替えのサンプルコード(Demo)」が生成されるが、敢えて上述の比較でとらえる

※ほぼ「自身向けのメモ」であるので、悪しからず。

動作環境(検証環境)

  • BootStrap(BootStrap-Vue)を使いたい都合で、Vue.jsはV.2.x系とする
package.json
  "dependencies": {
    "bootstrap-vue": "^2.22.0",
    "core-js": "^3.8.3",
    "vue": "^2.6.14",
    "vue-router": "^3.5.1",
    "vuex": "^3.6.2"
  },

作成手順

Vue.jsのCLIでの動作環境の構築

作成済みの人は、本節(環境の構築)をSkipして構わない。

なお、Vue.jsのビルド済みファイルの表示にはhtppサーバーが
必須なので、ローカル環境での簡易確認を目的に
http-server」もインストールしておく。

npm init
npm i http-server --save-dev 
npm i @vue/cli  --save-dev 

npm init での質問項目は好きなように。
特にこだわり名が無ければ「npm init -y」として、
全てデフォルトで作成、でも良い。

Vue-CLIによるプロジェクト作成を、Router有効状態で実施

Vueコマンドで、Vue-cliプロジェクトを作成。

なお、作成済みのプロジェクト一式を
vue-router-if-show.zip
に置いているので、このZipファイルをダウンロードして、
展開後のフォルダ内で、「npm install」しても良い。

以下は、vueコマンドを用いてゼロから作成する場合の手順。
ここではプロジェクト名称を「cli-vue」とする。

npx vue   create cli-vue

プロジェクトの設定値は以下の通り。
後のことを考慮して、Routerの他にVuexも選択しておく。
(なお、Vuexは本記事の範囲で利用しない)

Vue CLI v5.0.4
? Please pick a preset:
  hoshimado-defualt-vuejs ([Vue 2] babel, eslint, unit-mocha) 
  Default ([Vue 3] babel, eslint)
  Default ([Vue 2] babel, eslint)
> Manually select features
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex, Linter, Unit
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) No
? Pick a linter / formatter config: Basic
? Pick additional lint features: Lint on save   
? Pick a unit testing solution: Mocha
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N) No

Vue-CLIのプロジェクト作成が完了したら、そのルートに
vue.config.js」ファイルを作成して(既にある場合は修正)、
次のように記述する。

これにより、Vue-CLIのプロジェクトフォルダである「cli-vue」と
同じフォルダ階層に「public」フォルダが生成され、
Vue-CLIのプロダクションBuild時には、そちらへ出力されるようになる。
この「public」フォルダーが、先にインストールした
簡易HTTPサーバー「http-server」の表示対象フォルダとなる。

vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  publicPath: './',
  outputDir : '../public',
  transpileDependencies: true
})

続いて、BootStrap-Vueをインストールする。
具体的には次のコマンドを実行。

npm i bootstrap-vue --save 

BootStrap-Vueのインストールを終えたら、
先ほど作成したVue.jsのプロジェクトフォルダ内の
main.js」ファイルを開いて、既存のimport記述に続けて、
以下を追記する。

main.js
// +++ add for bootstrap +++
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
// -------------------------

この状態でnpm run serveコマンドを実行すると、
デフォルトのVue-CLIでのRouterサンプルファイルの
表示確認が出来るが、今回は敢えてしない。

※デフォルトのサンプルファイルについては、以下のVue.jsの公式ページのガイドに記載があるので、そちらを参照。

まずは、Routerを使わずにページ切り替え(表示エリア切り替え)を行う

BootStrap(BootStrap-Vue)のメニューバーを用いたページ切り替えを、
Router機能を使わずに実装してみる。

そのサンプルコードは以下のようになる。

App.vueファイルを以下のように書き換える(HelloWorld表示の代わりに、MyClient.vueによるポータル/オプション設定/ヘルプ(About)の表示するように、変更する)。

App.vue
<template>
  <div id="app">
    <MyClient>
    </MyClient>
  </div>
</template>


<style>
/* Cssファイルはここへ配置する。 */
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
}
</style>


<script>
import MyClient from './components/MyClient.vue'


export default {
    name: 'app',
    components: {
      MyClient
    },
    data: function () {
        return {
        };
    }
}
</script>

表示先のMyClient.vueファイルは次のように作成する。

これは、上部ペイン(ヘッダー相当)にBootStrap-Vueによるメニューバーを表示し、
そこでのメニューのclickに応じて、その配下の表示領域をv-showで切り替える機能を実装している。

表示切替される対象のVueコンポーネントファイルは以下の通り。

  • import HomePortal from './HomePortal.vue';
  • import UserOptions from './UserOptions.vue';
  • import About from '../views/AboutView.vue';

Router機能を使わすに画面を切り替える実装の一例、と言える。

MyClient.vue
<template>
<div>
    <div>
        <b-navbar toggleable="lg" type="dark" variant="info">
            <b-navbar-brand href="#" @click="clickBrandTitle">アプリケーション名</b-navbar-brand>
            <b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
            <b-collapse id="nav-collapse" is-nav>
            
                <!-- (Default) Left aligned nav items -->
                <b-navbar-nav>
                    <b-nav-item @click="routerTag='/'">Home</b-nav-item>
                    <b-nav-item @click="routerTag='/useroptions'">設定</b-nav-item>
                </b-navbar-nav>

                <!-- Right aligned nav items -->
                <b-navbar-nav class="ml-auto">
                    <b-nav-item-dropdown right>
                        <!-- Using 'button-content' slot -->
                        <template #button-content>
                            <em>その他</em>
                        </template>
                        <b-dropdown-item @click="routerTag='/about'">About</b-dropdown-item>
                    </b-nav-item-dropdown>
                </b-navbar-nav>
            </b-collapse>
        </b-navbar>
    </div>
    <div>
        <div v-if="isHome">
            <home-portal></home-portal>
        </div>
        <div v-if="isUserOption">
            <user-options></user-options>
        </div>
        <div v-if="isAbout">
            <about></about>
        </div>
    </div>
</div>
</template>


<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
/* Cssファイルはここへ配置する。 */


</style>


<script>
import { BNavbar, BNavbarBrand, BNavbarToggle, BCollapse, BNavItem, BNavbarNav, BNavItemDropdown, BDropdownItem } from 'bootstrap-vue';
import HomePortal from './HomePortal.vue';
import UserOptions from './UserOptions.vue';
import About from '../views/AboutView.vue';


export default {
    name : "MyClient",
    components: {
        BNavbar, BNavbarBrand, BNavbarToggle, BCollapse, BNavItem, BNavbarNav, BNavItemDropdown, BDropdownItem,
        HomePortal, UserOptions, About
    },
    props: {
    },
    data : function () {
        return {
            routerTag: '/'
        }
    },
    mounted : function () {
    },
    computed : {
        isUserOption: function() {
            return (this.routerTag=='/useroptions');
        },
        isAbout: function() {
            return (this.routerTag=='/about');
        },
        isHome: function() {
            return (this.routerTag=='/');
        }
    },
    created : function () {
    },
    watch : {
    },
    methods : {
        clickBrandTitle : function () {
            /* var result = */ alert('サイトトップへ移動(しない)');
        }
    }
}
</script>

この状態で
npm run serveコマンドでデバッグ実行を行うと、次のように表示される。

なお、先に述べた
作成済みのプロジェクト一式「vue-router-if-show.zip
を展開して、「npm i」(は「npm install」の省略表現)した直後に、
npm run serve」した状態に、等しい。

初期表示画面としてのHome
初期表示画面としてのHome
Aboutページ

続いて、同じ機能をRouterを用いて実現する

前節まででの画面切り替え機能の実装を、Router機能を用いて実装する場合は、
MyClient.vueを次のように書き換える。

※書き換えた後のソースコードは、
先に述べた
作成済みのプロジェクト一式「vue-router-if-show.zip
内にある、
src\components\MyClient.router.vue
である。
(この「MyClient.router.vue」をそのまま使う場合は、
既存の「MyClient.vue」を削除したのちに、
MyClient.router.vue」を「MyClient.vue」へリネームすること)

<b-nav-item>タグのクリック時の切り替え操作を、
先の例では自前実装していたのに対して、Router機能を用いる場合は、
特に実装する必要が無い。属性toに指定したキーに応じて、
Router機能が処理してくれる。

MyClient.vue
<template>
<div>
    <div>
        <b-navbar toggleable="lg" type="dark" variant="info">
            <b-navbar-brand href="#" @click="clickBrandTitle">アプリケーション名</b-navbar-brand>
            <b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
            <b-collapse id="nav-collapse" is-nav>
            
                <!-- (Default) Left aligned nav items -->
                <b-navbar-nav>
                    <b-nav-item to="/">Home</b-nav-item>
                    <b-nav-item to="/useroptions">設定</b-nav-item>
                    <!-- 
                        Vue-Routerの「to」指定は、BootStrap Nav-itemでもサポートされている。
                        https://bootstrap-vue.org/docs/reference/router-links
                    -->
                </b-navbar-nav>

                <!-- Right aligned nav items -->
                <b-navbar-nav class="ml-auto">
                    <b-nav-item-dropdown right>
                        <!-- Using 'button-content' slot -->
                        <template #button-content>
                            <em>その他</em>
                        </template>
                        <b-dropdown-item to="/about">About</b-dropdown-item>
                    </b-nav-item-dropdown>
                </b-navbar-nav>
            </b-collapse>
        </b-navbar>
    </div>
    <div>
        <!-- 表示するコンポーネント管理は、Vue-Routerに任せる -->
        <router-view/>
    </div>
</div>
</template>


<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
/* Cssファイルはここへ配置する。 */


</style>


<script>
import { BNavbar, BNavbarBrand, BNavbarToggle, BCollapse, BNavItem, BNavbarNav, BNavItemDropdown, BDropdownItem } from 'bootstrap-vue';


export default {
    name : "MyClient",
    components: {
        BNavbar, BNavbarBrand, BNavbarToggle, BCollapse, BNavItem, BNavbarNav, BNavItemDropdown, BDropdownItem
    },
    props: {
    },
    data : function () {
        return {
        }
    },
    mounted : function () {
    },
    computed : {
    },
    created : function () {
    },
    watch : {
    },
    methods : {
        clickBrandTitle : function () {
            /* var result = */ alert('サイトトップへ移動(しない)');
        }
    }
}
</script>

Router機能への設定は、「route/index.js」で行う。
今回の例では、以下のようにする。

なお、ここで「home」(=つまり、「HomePortal.vue」)以外で
記述方法が異なるのは、ソース内のコメント
(はデフォルトサンプルコードに記載されている)にあるように、
「最初に表示されるモノ(=home)以外は、
 表示要求が発生してから(遅延)ロードするようにするため」
である。

route/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomePortalView from '../views/HomePortalView'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomePortalView
  },
  {
    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/AboutView.vue')
  },
  {
    path: '/useroptions',
    name: 'useroptions',
    component: () => import(/* webpackChunkName: "about" */ '../components/UserOptions.vue')
  }
]

const router = new VueRouter({
  routes
})

export default router

上記において、フォルダ「viwes」配下のVueコンポーネントを
切り替え先として書いているが、
Router機能を用いる場合は、対象のViewはフォルダ「viwes」配下に
配置するのが一般的だから、である。

その表示対象のViwe画面を構成する
「部品」の位置付けとなるVueコンポーネントはもちろん、
これまで通り「components」フォルダ配下に配置していく。
(今回の例では、View画面あたり1コンポーネントしか使わないので、ほぼスルーパスになっている)。

ここまでの書き換えを終えた状態で
npm run serve」コマンドでデバッグ実行を行うと、
表示としては、先の節と同じようになる。

「設定」と「その他>about」をclickした時の動作もほぼ同じである。
「ほぼ」と表現したのは、Router機能を用いた実装の場合は、
「表示状態毎にURLバーの表示が変わる」部分に差分があるからである。
Router機能を用いた場合は、表示したページの状態をURLでそのまま指定できる、と言える。

※URLバーの表示方法は「#を含む形式(Hash Mode)」と「含まない形式(History Mode, こちらはServer側でのURL処理の設定も合わせて必要)」とがある。詳細は、公式のガイドを参照。→ https://v3.router.vuejs.org/ja/guide/essentials/history-mode.html

Router機能での画面切り替えを、BootStrap-Vueのメニューコンポーネントと
組み合わせて利用するケース、v-show機能を用いた切り替えとの対比は、以上。

補足:プロダクションbuildしての動作確認について

本記事の解説では、プロダクションbuildする際の出力先は、
Vue.jsのプロジェクトのフォルダ「cli-vue」と同じ階層に
「public」フォルダを作成してそこに出力するようにしてある。
(上述の「vue.config.js」で指定)

従って、v-showrouterでのそれぞれのサンプルコードに対して、
コマンド「npm run build」を実行すると、「build」フォルダに
公開用のbuild済みファイルが出力される。

これをローカルで動作確認するには、フォルダ「public」の上位のフォルダで
以下のコマンドを実行する
(本記事の冒頭で「npm i http-server --save-dev」したフォルダ)。

npx   http-server

ローカルでHTTPサーバーが起動するので、ブラウザを開いて
http://127.0.0.1:8080/」へアクセスすることで、
最終的な表示状態を確認できる。

あとは、フォルダ「public」の中身を、任意の公開用HTTPサーバー上
(静的httpサーバーでOK)に配置すれば、公開完了となる。

改めて以上ー。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?