こんにちは、”はふぃ”です。

Vueアプリケーションを作成する際にNuxt.jsを利用することが多いと思いますが、Nuxtのリンクにはaタグではなくnuxt-link(またはrouter-link)を使用します。

Nuxt:Vue アプリケーションを作成するフレームワーク

参考:https://ja.nuxtjs.org/guide/

nuxt-link(router-link):ルーターが使用可能になっているアプリケーションでユーザーのナビゲーションを有効にするためのコンポーネント

参考:https://router.vuejs.org/ja/api/#router-link

nuxt-linkを使用することで、ページをリロードすることなく、ページ固有の要素のみを追加でロードするだけで画面遷移を行うことができます。

遷移先の指定にはtoを設定し、以下のように使います。

<!-- aタグ -->
<a href="/sample">aタグのリンク</a>

<!-- nuxt-linkタグ -->
<nuxt-link to="/sample">nuxt-linkのリンク</nuxt-link>

nuxt-linkの問題

nuxt-linkはVueアプリケーション内の遷移には便利なのですが、外部サイトへ遷移することができません

<!-- これはダメ -->
<nuxt-link to="https://hafilog.com">HAFILOGへ</nuxt-link>

<!-- 外部リンクの場合はaタグに -->
<a href="https://hafilog.com">HAFILOGへ</a>

しかし、内部リンクと外部リンクが混じった配列をv-forで回して表示するような場合にはnuxt-linkタグとaタグの両方を書かなければならずまとまりがなくなってしまいます。

<template>
  <ul>
    <li v-for="(link, i) in links" :key="`bad-sample_${i}`">
      <template v-if="isInternalLink(link.path)">
        <!-- 内部リンク -->
        <nuxt-link :to="link.path">{{ link.label }}</nuxt-link>
      </template>
      <template v-else>
        <!-- 外部リンク -->
        <a :href="link.path">{{ link.label }}</a>
      </template>
    </li>
  </ul>
</template>

<script>
export default {
  data () {
    return {
      links: [
        { label: '内部リンク', path: '/internal' },
        { label: '外部リンク(HAFILOGサイト)', path: 'https://hafilog.com' }
      ]
    }
  },
  methods: {
    isInternalLink (path) {
      return !/^https?:\/\//.test(path)
    }
  }
}
</script>

上の例でも間違いではないのですが、{{ link.label }}が共通の処理なので共通化したいですね。

共通化する方法

componentタグ

componentタグを利用することで処理を共通化することが可能です。

<template>
  <ul>
    <li v-for="(link, i) in links" :key="`bad-sample_${i}`">
      <component
        :is="isInternalLink(link.path) ? 'nuxt-link' : 'a'"
        :to="isInternalLink(link.path) ? link.path : ''"
        :href="isInternalLink(link.path) ? '' : link.path"
      >
        {{ link.label }}
      </component>
    </li>
  </ul>
</template>

<script>
export default {
  data () {
    return {
      links: [
        { label: '内部リンク', path: '/internal' },
        { label: '外部リンク(HAFILOGサイト)', path: 'https://hafilog.com' }
      ]
    }
  },
  methods: {
    isInternalLink (path) {
      return !/^https?:\/\//.test(path)
    }
  }
}
</script>

<component>v-bind:isを使うことで条件によってタグを変更することができました。

動的なコンポーネント

参考:https://jp.vuejs.org/v2/guide/components.html#%E5%8B%95%E7%9A%84%E3%81%AA%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88

clickイベント

これまでのカスタムタグを使った方法の他にclickイベント内で処理を分ける方法もあります。

<template>
  <ul>
    <li v-for="(link, i) in links" :key="`bad-sample_${i}`">
      <a href="javascript:void(0)" @click.prevent="onClick(link.path)">
        {{ link.label }}
      </a>
    </li>
  </ul>
</template>

<script>
export default {
  data () {
    return {
      links: [
        { label: '内部リンク', path: '/internal' },
        { label: '外部リンク(HAFILOGサイト)', path: 'https://hafilog.com' }
      ]
    }
  },
  methods: {
    isInternalLink (path) {
      return !/^https?:\/\//.test(path)
    },
    onClick (path) {
      if (this.isInternalLink(path)) {
        this.$router.push(path)
      } else {
        location.href = path
      }
    }
  }
}
</script>

リンクがクリックされた際にonClickメソッドが実行され、内部リンクならrouterを使った画面遷移、外部リンクならlocation.hrefによる画面遷移を行います。

this.$router.pushはルーターのインスタンスメソッドを利用したナビゲーションであり、この処理はnuxt-linkrouter-linkをクリックした時に内部的に呼ばれる

参考:https://router.vuejs.org/ja/guide/essentials/navigation.html

location.hrefaタグのメソッドバージョン

参考:http://www.pori2.net/js/location/1.html

まとめ

どんどん共通化して無駄のないコードにしていきましょー!

参考

今回のコードはgithubで公開中なので参考にしてみてください!↓

https://github.com/hafilog/vue-sample/tree/master/components/pages/sample

投稿者: はふぃ

若手のWEBフロントエンジニア。最近はバレーボールにハマってます!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA