Nuxt3の動的コンポーネントにて、NuxtLinkを使用する
指定の条件でNuxtLink
とspan
タグの切り分けをしたいと思い、その時に試したことを共有します。
前提
- Nuxtのバージョンは
3.8.1
を使用しています。 - コンポーネントにて、指定のpropがある場合、
NuxtLink
タグ。ない場合はspan
タグを使用します。- コンポーネントのタグの切り替えをするために使用するpropsは
isLink
です。
- コンポーネントのタグの切り替えをするために使用するpropsは
NuxtLink componentについて
Dynamic Componentについて
結論
もし対応コード・原因のみを確認したい場合は、以下のコードをご覧いただくか、GitHub のissuesを参照していただければと思います。
<!-- コンポーネントでの記載 -->
<template>
<component :is="isLink ? NuxtLink : 'span'">
何かの要素
</component>
</template>
<script lang="ts" setup>
import { NuxtLink } from '#components'
withDefaults(
defineProps<{ isLink?: boolean }>(),
{
isLink: false,
},
)
</script>
<!-- 呼び出す際の処理 -->
<!-- NuxtLinkタグの場合 -->
<AnyComponent isLink />
<!-- spanの場合 -->
<AnyComponent /> <!-- or <AnyComponent isLink={false} /> -->
試してみた方法について
1. 通常のHTMLタグと同様に記載してみる
はじめとして、通常のタグと同様の感覚で、NuxtLink
を呼んでみました。
※NuxtLink
はNuxt3では auto importされるはずだと思っているため、import NuxtLink
のようなimport文についても記載はしておりません。
<template>
<component :is="isLink ? 'NuxtLink' : 'span'">
何かの要素
</component>
</template>
<script lang="ts" setup>
withDefaults(
defineProps<{ isLink?: boolean }>(),
{
isLink: false,
},
)
</script>
nuxtlink
のタグとして出力されるため、失敗
resolveComponent
を使用して、動的に表示させてみる
2. 次はresolveComponent
を使用し、script
の中で動的コンポーネントとして表示させることでうまくいくか試してみようと思います。
resolveComponent
の詳細については以下の記載を参照してください。
<template>
<component :is="LinkComponent">
何かの要素
</component>
</template>
<script lang="ts" setup>
const props = withDefaults(
defineProps<{ isLink?: boolean }>(),
{
isLink: false,
},
)
const LinkComponent = resolveComponent(props.isLink ? 'NuxtLink' : 'span')
</script>
参考までにNuxtLink
の部分を文字列ではなくコンポーネントとして行ってみましたが、システムエラー・typeエラーになるため、こちらもうまくいきませんでした。
<template>
<component :is="LinkComponent">
何かの要素
</component>
</template>
<script lang="ts" setup>
const props = withDefaults(
defineProps<{ isLink?: boolean }>(),
{
isLink: false,
},
)
const LinkComponent = resolveComponent(props.isLink ? NuxtLink : 'span')
</script>
NuxtLink
をのimport文を記載してみる
3. ここまでで、動的コンポーネント周りの設定というよりはNuxtLink
周りの設定周りが原因だと思ったため、Nuxt.jsのissuesを探してみたところ、以下のissuesを発見
issuesを見ていたところ、NuxtLinkはグローバルに登録はされていないというコメントを見つけたので、こちらを一度試してみます。
It's because NuxtLink isn't globally registered - it's auto-imported. Within a Nuxt project we detect resolveComponent('NuxtLink') and rewrite this into an import statement.
You can probably resolve this in your case by adding your ui library to build.transpile, and using import { NuxtLink } from '#imports'
<template>
<component :is="isLink ? NuxtLink : 'span'">
何かの要素
</component>
</template>
<script lang="ts" setup>
import { NuxtLink } from '#imports'
withDefaults(
defineProps<{ isLink?: boolean }>(),
{
isLink: false,
},
)
</script>
こちら、#imports
に以下のエラーが出力されるため、失敗
NuxtLink
にcomponents
を呼んで記載してみる
4. さらにissuesを読み進めていくと
For those wondering, the correct import is
import { NuxtLink } from '#components';
Then you can use:<component :is="to ? NuxtLink : 'div'" :to="to">
,
Nuxt need better documentation about the Virtual Files, they are helpful, but confusing.
こちら、#components
に変更してみたところ、うまく実行させることができました。
結論の箇所にも記載していますが、改めてこちらにもコードを記載します。
※to
などの他のpropsの値については省略しています。
<template>
<component :is="isLink ? NuxtLink : 'span'">
何かの要素
</component>
</template>
<script lang="ts" setup>
import { NuxtLink } from '#components'
withDefaults(
defineProps<{ isLink?: boolean }>(),
{
isLink: false,
},
)
</script>
Discussion