特定のアンカータグの遷移処理をrouter.pushでさせたい

  • Web
  • NuxtJS

はじめに

HTMLでリンク機能を実現するタグといえばアンカータグ<a>がありますが、Nuxt.jsではそれに加えて<nuxt-link>というコンポーネントでページ遷移を実現する方法があります。

用途の使い分けとしては次のようになると思います。

  • <a> : サイト外へのリンク
  • <nuxt-link> : サイト内へのリンク(そもそもサイト外のパスは指定できないです)

<nuxt-link>を利用するメリットは公式ドキュメントの言葉をお借りすると、「ページ間のナビゲーションを提供するコンポーネントであり、先読みによってパフォーマンスを向上させるのに使用する」と。

たしかに、実際に2つのタグで比べると、アンカータグでサイト内ページに遷移するときと<nuxt-link>でサイト内ページに遷移するときとで挙動・表示の速さが異なりますので、積極的に使い分けましょう!

router.push

<nuxt-link>はコンポーネントであり、実際にブラウザで表示されるときはアンカータグです。それではなぜ挙動が異なるのか疑問に感じるかもしれません。実はリンクをクリックした時に内部的にrouter.pushというメソッドが呼ばれているからです。

このrouter.pushはJavaScriptコード中で利用することも可能です。例えば、<button>や特定の条件のタグのクリックイベントに遷移処理を仕込むといったことも可能です。非常に便利です!

今回やりたいこと

冒頭で特定のタグにrouter.pushを実行するイベントを仕込むことで、<nuxt-link>をクリックした時のページ遷移のような挙動を実現できると書きました。

ここでは、サイト内リンク(例 : パスが/about等)のアンカータグを対象にrouter.pushによって遷移させたいと思います。

理由

なんでこのようなケースを考えたかと言うと、Headless CMSといったサービスで記事中でサイト内ページへのリンクを書く場合に、ただのアンカータグによる遷移ではなく、router.pushによって遷移させたいといったことがあると思ったからです。

自分でページコンテンツをVueファイルで書く場合は<nuxt-link>を使えばよいのですが、外部から取得したコンテンツといった場合は配慮しなければなりません。(データ取得後にJSで適切なコンポーネントを使うように制御することも考えられます)

実装

Vueファイルのテンプレート部分を示します。(内容はサンプルなので)

PostContentというコンポーネントで外部から取得した記事本文が表示されるとします。

この記事本文部分を対象にします。

<template>
  <div class="page">
    <h1>Sample</h1>
    <div class="js-post-content">
      <post-content :content="content" />
    </div>
  </div>
</template>

続いて、スクリプト部分を示します。

export default {
  // headやcomponentsなどのプロパティは割愛します
  mounted() {
    this.$nextTick(this.addRouterPushEvents)
  },
  methods: {
    routeTo(e) {
      e.preventDefault()
      // href属性に記されたパスへ遷移
      this.$router.push(e.target.getAttribute('href'))
    },
    addRouterPushEvents() {
      // 「//」から始まるパス指定の場合は除く
      const selector = '.js-post-content a[href^="/"]:not([href^="//"])'
      const anchorNodeList = this.$el.querySelectorAll(selector)

      // Note: https://developer.mozilla.org/ja/docs/Web/API/NodeList
      // IE11はNodeList.prototype.forEach()未対応 (polyfill読み込ませて使ってもOK)
      for (let i = 0; i < anchorNodeList.length; i++) {
        anchorNodeList[i].addEventListener('click', this.routeTo, false)
      }
    },
  },
}

以上のようになります。補足でコメントを書いていますのでご参考になれば幸いです。

この記事を共有

アバター

K.Utsunomiya
男・20代
主にWebフロントエンド技術と気になった音楽について投稿していきます。
最近ハマっていることは、クロスバイクで走ることとジムでの運動です。
詳しいプロフィール

© 2020–2021 コレ棚