Search code examples
vue.jsnuxt.jsrouterlink

How to wrap a block of template code in different elements depending on a condition?


My component has 2 props: link and isExternal. Depending on the latter, I'll wrap my template code either in a <NuxtLink (equivalent of native Vue <router-link>) or in a <a> element.

The code below achieves that by using twice the same template code - which is obviously atrocious.

Yet I can't think of a simple way to do it elegantly. Any idea?

<template>
  <NuxtLink
    v-if="!isExternal"
    to="link"
  >
    <div
      class="btn"
      :style="{
        'background-color': backgroundColor,
        'color': textColor
      }"
    >
      <img
        v-if="image"
        :src="image"
        class="image"
      >

      <div>{{ text }}</div>

      <svg-icon name="arrow-right" class="arrow" />
    </div>
  </NuxtLink>

  <a
    v-else
    href="link"
    target="_blank"
  >
    <div
      class="btn"
      :style="{
        'background-color': backgroundColor,
        'color': textColor
      }"
    >
      <img
        v-if="image"
        :src="image"
        class="image"
      >

      <div>{{ text }}</div>

      <svg-icon name="arrow-right" class="arrow" />
    </div>
  </a>
</template>

Solution

  • You may use component element like this:

    <template>
      <component
        :is="computedTag"
        v-bind="computedProps"
      >
        <div
          class="btn"
          :style="{
            'background-color': backgroundColor,
            'color': textColor
          }"
        >
          <img
            v-if="image"
            :src="image"
            class="image"
          >
    
          <div>{{ text }}</div>
    
          <svg-icon name="arrow-right" class="arrow" />
        </div>
      </component>
    </template>
    
    <script>
    export default {
      props: ['link', 'isExternal'],
      computed: {
        computedTag() {
          return this.isExternal ? 'a' : 'nuxt-link';
        },
        computedProps() {
          return this.isExternal
            ? { href: this.link, target: '_blank' }
            : { to: this.link };
        },
      },
    };
    </script>