如何根据条件将模板代码块包装在不同的元素中?

问题描述

我的组件有 2 个道具:linkisExternal。根据后者,我会将模板代码包装在 <NuxtLink(相当于原生 Vue <router-link>)或 <a> 元素中。

下面的代码通过使用两次相同的模板代码实现了这一点——这显然是很糟糕的。

然而,我想不出一个简单的方法来优雅地做到这一点。有什么想法吗?

<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>

解决方法

您可以像这样使用 component 元素:

<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>