第17回 Vue.js入門 フック関数とナビゲーションガード

guard プログラミング

こんにちは、コンスキです。

今回は、フック関数とナビゲーションガードというものについて説明します。

フック関数とナビゲーションガードとは

Vue Routerのフック関数とは、router-link要素をクリックして「ページ遷移」が行われるタイミングをフックにして、処理を行う関数のことです。

実際は表示内容が変更されているだけで「ページ遷移」は行われていませんが、表示内容がルーティングされて表示内容が変更されることを指して「ページ遷移」と言っています。

このようなフック関数を使って、特定の条件のときにページにページ遷移させない、または、違うページにページ遷移させることをナビゲーションガードといいます。

フック関数はナビゲーションガードとして、リダイレクトを行う際などに使うことができます。

例えば、現在は使用されていないページへページ遷移が行われたタイミングをフックとして、現在使用されているページへ強制的にページ遷移し直すような「リダイレクト」を行うことができます。

フックの種類

Vueインスタンスのライフサイクルフックにも、フックとなるタイミングに種類がありました。

Vue Routerのフックにも、同じようにフックとなるタイミングに種類がありますが、Vue Routerのフックの場合、すべてのページにおける、ページ遷移時に有効なフックと、特定のルートや特定のコンポーネントへページ遷移した時のみ、またはそれらからページ遷移してきた時のみに有効なフックがあります。

すべてのページにおける、ページ内容の変更時に有効なフック

フックの種類関数が実行されるタイミング
beforeResolveあるページにページ遷移が行われる直前
afterEachあるページからページ遷移が行われた直後

特定ルートにおける、ページ内容の変更時に有効なフック

フックの種類関数が実行されるタイミング
beforeEnterあるページにページ遷移が行われる直前

特定のコンポーネントにおける、ページ内容の変更時に有効なフック

フックの種類関数が実行されるタイミング
beforeRouteEnterあるページにページ遷移が行われる直前
beforeRouteUpdate同じコンポーネントへページ遷移が行われる直前
beforeRouteLeaveあるページからページ遷移が行われた直後

フック関数の使い方

次の3つのフック関数では、to、from、nextの3つの引数を取ります。

toはページ遷移先のルートのオブジェクトで、fromはページ遷移元のルートのオブジェクトです。

nextはページ遷移を行う関数で、引数にページ遷移先のルートオブジェクトのpathが入ります。next関数を記述しないと、ページ遷移がずっと終わらなくなってしまうので、必ず記述する必要があります。

すべてのページにおける、ページ内容の変更時に有効なフック関数

var router = new VueRouter({
  //ここにroutesプロパティを設定します
})
router.フックの名前(function (to, from, next) {
  //ここにフック関数の処理を書来ます
})

例えば、現在使用していないページへページ遷移した場合、ページが移転されたことを知らせるページへリダイレクトするようなプログラムは次のようになります。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>ナビゲーションガード</title>
  <script src="https://unpkg.com/vue"></script>
  <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> 
</head>
<body>
  <div id="app">
    <router-link to="/page1">ページ1を表示</router-link>
    <router-link to="/newPage2">ページ2を表示</router-link>
    <router-link to="/oldPage2">ページ2を表示</router-link>
    <router-view></router-view>
  </div>
  <script>
    var Relocated = {
      template: `
        <div>
          <h1>このページは移転されました。</h1>
          <router-link to="/newPage2">新しいページ2を表示</router-link>
        </div>
      `
    }    
    var router = new VueRouter({
      routes: [
        {
          path: '/page1',
          component: {
            template: '<h1>ページ1です。</h1>'
          }
        },
        {
          path: '/newPage2',
          component: {
            template: "<h1>ページ2です。</h1>"
          }        
        },
        {
          path: '/oldPage2',
          component: {
            template: "<h1>旧ページ2です。</h1>"
          }        
        },
        {
          path: '/relocated',
          component: Relocated
        }
      ]
    })

    router.beforeEach(function (to, from, next) {
      if (to.path === "/oldPage2") {    //ページ遷移先のルートのpathが"/oldPage2"だった時に移転されたことを知らせる        
        next("/relocated")              //ページにリダイレクトします
      } else {
        next()              //それ以外のページ遷移は普通に行います
      }
    })

    var vm = new Vue({
      el: "#app",
      router: router
    })
  </script>
</body>
</html>

ブラウザには次のように表示されます。

ページ2へのリンクが2つあり、右の方は古いページ2へのリンクになっています。古いページ2へページ遷移しようとすると、移転を知らせるページヘリダイレクトされます。

特定ルートにおける、ページ内容の変更時に有効なフック関数

var router = new Vue Router({
  var lroutes = [
     {
       path: "このルートのURL",
       component: {
         template: "コンポーネントの内容"
       }
       フックの名前: function () {
         //ここにフック関数の処理を書きます
       }
     }
  ]
})

特定のコンポーネントにおける、ページ内容の変更時に有効なフック関数

var コンポーネント名 = {
  template: "コンポーネントの内容",
  フックの名前: function () {
    //ここにフック関数の処理を書きます
  }
}

var router = new Vue Router({
  var routes = [
     {
       path: "このルートのURL",
       component: コンポーネント名
     }
  ]
})

例えば、ページの内容が保存されずに、ページ遷移が行われたときに、ページの遷移をキャンセルして、警告を出すプログラムは次のようになります。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>ナビゲーションガード</title>
  <script src="https://unpkg.com/vue"></script>
  <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> 
</head>
<body>
  <div id="app">
    <router-link to="/page1">ページ1を表示</router-link>
    <router-link to="/page2">ページ2を表示</router-link>
    <router-link to="/page3">ページ3を表示</router-link>
    <router-link to="/page4">ページ4を表示</router-link>
    <router-link to="/page5">ページ5を表示</router-link>
    <router-link to="/page6">ページ6を表示</router-link>
    <router-view></router-view>
  </div>
  <script>
    var Page2 = {
      template: `
        <div>
          <h1>ページ2です。</h1>
          <textarea rows="4" cols="40"></textarea>
          <br>
          <button v-on:click="save()">{{ button }}</button>
          <p>保存状態:{{ displayState }}</p>
        </div>
      `,
      data: function () {
        return {
          button: "保存する",
          isSaved: false,
        }
      },
      computed: {
        displayState: function () {
          if (!this.isSaved) {
            return "保存されていません。"
          } else {
            return "保存済みです。"
          }          
        }
      },
      methods: {
        save: function () {
          this.isSaved = true
        }
      },
      beforeRouteLeave: function (to, from, next) {
        if (!this.isSaved) {
          alert("内容がまだ保存されていません。")
          next(false)
        } else {
          next()
        }
      }
    }
    
    var router = new VueRouter({
      routes: [
        {
          path: '/page1',
          component: {
            template: '<h1>ページ1です。</h1>'
          }
        },
        {
          path: '/page2',
          component: Page2        
        },
        {
          path: '/page3',
          component: {
            template: "<h1>ページ3です。</h1>"
          }
        },
        {
          path: '/page4',
          component: {
            template: "<h1>ページ4です。</h1>"
          }
        },
        {
          path: '/page5',
          component: {
            template: "<h1>ページ5です。</h1>"
          }
        },
        {
          path: '/page6',
          component: {
            template: "<h1>ページ6です。</h1>"
          }
        }
      ]
    })

    var vm = new Vue({
      el: "#app",
      router: router
    })
  </script>
</body>
</html>

ブラウザに表示すると次のようになります。

はじめは、6つのページヘのリンクがあります。「ページ2を表示」をクリックしてページ2へページ遷移して下さい。

すると次のようなテキストエリアとボタン、保存状態が表示されます。

「保存する」というボタンを押さずに他のページへのページ遷移を行おうとすると、ページ遷移は行われず、警告が出ると思います。

まとめ

  • Vue Routerのフック関数は、ページ遷移が行われるタイミングに実行される関数
  • 特定の条件のときに、ページ遷移をキャンセルあるいはリダイレクトさせることをナビゲーションガードという
  • フック関数には、グローバルなフック関数、ルート単位のフック関数、コンポーネント単位でのフック関数がある

コメント

タイトルとURLをコピーしました