如何在 Vue 中根据链接是外部还是内部动态渲染 <router-link> 或 <a>?

问题描述 投票:0回答:4
<template>
  <component
    :is="type === 'internal' ? 'router-link' : 'a'"
    :to="type === 'internal' ? link : null"
    :href="type !== 'internal' ? link : null"
  >
    <slot />
  </component>
</template>

<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";

@Component
export default class SiteLink extends Vue {
  @Prop({
    validator: (value: string) =>
      ["external", "internal"].includes(value)
  })
  private readonly type!: string;

  @Prop({ type: String })
  private readonly link!: string;
}
</script>

上面是一个 Vue 组件,它将在其中渲染链接。我删除了与问题无关的任何内容(即

rel
target
class
等)。

理解 - 我对 Vue Router 的理解是

<router-link to="/about">About</router-link>
<a href="/about">About</a>
都会在 DOM 中呈现为
<a href="/about">About</a>
,不同之处在于
<router-link>
版本将为链接提供 SPA 功能(即不提供 SPA 功能)不加载新页面,它会动态呈现组件)。

预期 - 当

type="internal"
时,它将渲染
<router-link>
版本。当
type="external"
时,它将渲染
<a>
版本。

<site-link type="external" link="https://stackoverflow.com">Stack Overflow</site-link>

Will render

<a href="https://stackoverflow.com">Stack Overflow</a>
<site-link type="internal" link="/about">About</site-link>

Will render

<router-link to="/about">About</router-link>

Which is then handle by VueRouter to render

<a href="/about">About</a>

实际 - 当

type="internal"
时,在 DOM 中呈现带有
no
<a>
href
。当
type="external"
时,它会按预期呈现。

<site-link type="external" link="https://stackoverflow.com">Stack Overflow</site-link>

Will render

<a href="https://stackoverflow.com">Stack Overflow</a>
<site-link type="internal" link="/about">About</site-link>

Will render

<router-link to="/about">About</router-link>

Which is then handle by VueRouter to render

<a>About</a> <!-- Notice there is no href -->

有什么想法可以实现我想要的吗?

html typescript vue.js hyperlink vue-router
4个回答
5
投票

更好、更干净的方法:

  <router-link v-if="type === 'internal' :to="link">
    <slot />
  </router-link>
  <a v-else :ref="link"> <slot /> </a>

您可以在根元素中使用

v-if
,这样它就可以解决您的问题

或者您可能只是错过了路径部分?

  <component
    :is="type === 'internal' ? 'router-link' : 'a'"
    :to="type === 'internal' ? { path: link } : null"
    :href="type !== 'internal' ? link : null"
  >
    <slot />
  </component>

1
投票

官方文档包含现在如何执行此操作的示例。

他们的方法是创建一个处理外部链接的自定义模板。


1
投票

...不同之处在于

<router-link>
版本将为链接提供 SPA 功能(即不加载新页面,而是动态呈现组件)。

不加载新页面,我想您的意思是它不会重新加载页面。是的,事实并非如此,因为

onclick
处理程序实际上被分配给一个函数,该函数 执行
preventDefault
(防止页面重定向),同时 将新条目推入历史堆栈

如果您查看 API 参考

<router-link>
为您所做的最引人注目的事情是它根据活动/当前路线在
active-class
之间切换。

因此,话虽如此,您可以通过

<a>
 在默认插槽内进行动态 
v-slot
nchor 渲染;因为此时,
href
slot 属性将是一个已解析的 URL,然后您可以安全地将其绑定到 DOM
href
属性。


编辑

添加了一个示例(未经测试)。

<router-link
  :to="link"
  v-slot="{ href, route, navigate, isActive, isExactActive }">
  <a
    :class="isActive ? 'your-custom-class' : 'anything'"
    :href="type !== 'internal' ? href : 'javascript:void(0);'"
    @click="customNavigate(navigate.bind($event))">
    <slot></slot>
  </a>
</router-link>

其中

customNavigate
处理程序可能类似于:

{
  methods: {
    customNavigate(navigate) {
      if (this.type === 'internal') {
        navigate();
        return false;
      }
    }
  }
}

您基本上可以根据插槽属性在组件内锚标记上添加任何属性,例如以某些方式导航,添加特殊类,具体取决于您的用例。


0
投票

您的代码是正确的,但它包含一个致命的错误

:href="type !== 'internal' ? link : null"

这一行的意思是“如果 type 是内部的,则将 href 属性设置为 null”。

router-link
组件将
to
属性转换为字符串,然后将其绑定为
href
属性,但它无法设置已解析的
href
属性,因为您已经将其设置为 null。

一种解决方案是仅绑定必要的属性:

const params = computed(() => {
    if (type === "internal") {
        return {
            to: props.to,
        };
    }

    return {
        href: props.href,
    };
})
<component
    :is="type === 'internal' ? 'router-link' : 'a'"
    v-bind="params"
>

希望有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.