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

Posted

技术标签:

【中文标题】如何根据链接是外部的还是内部的,在 Vue 中动态渲染 <router-link> 或 <a>?【英文标题】:How to dynamically render <router-link> or <a> in Vue depending on whether the link is exrternal or internal? 【发布时间】:2020-07-12 03:39:47 【问题描述】:
<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 组件,它将在其中呈现一个链接。我已经删除了与问题无关的任何内容(即reltargetclass 等)。

理解 - 我对Vue Router的理解是&lt;router-link to="/about"&gt;About&lt;/router-link&gt;&lt;a href="/about"&gt;About&lt;/a&gt;都会在DOM中渲染为&lt;a href="/about"&gt;About&lt;/a&gt;,不同的是&lt;router-link&gt;版本会给出链接SPA 功能(即不加载新页面,它会动态呈现组件)。

预期 - 当type="internal" 时,它将呈现&lt;router-link&gt; 版本。当type="external"时,会渲染&lt;a&gt;版本。

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

Will render

<a href="https://***.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" 时,一个&lt;a&gt;no href 在DOM 中呈现。当type="external" 时,它按预期呈现。

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

Will render

<a href="https://***.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 -->

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

【问题讨论】:

为什么不能同时使用router-link 我尝试了这个建议,始终将router-link 用于内部和外部链接,对于外部链接,它似乎以localhost:8080(或任何根URL)为前缀link作为道具传递。 请在下面查看我提出的解决方案,如果有帮助请告诉我? 好的,谢谢。让我试一试。 【参考方案1】:

更好更简洁的方法:

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

【讨论】:

这将是我的第二种方法,但是我的其他属性,例如reltargetclass 等将在它们之间重复。我试图不复制属性。 更新答案,立即查看 尝试了第二个选项,现在似乎没有渲染任何东西。 这是一个非常好的替代解决方案,唯一的缺点是在&lt;router-link&gt;&lt;a&gt; 中重复属性,例如relclasstarget。如果可以在不重复属性的情况下建议一种干净的方法,我很乐意将其作为公认的答案。 @JDomleo 如果您同时为“内部”和“外部”锚点添加预期输出会很有帮助,例如取哪个属性(或者如果可以让它们都拥有一切)。我假设这些被剥离的属性是用于外部链接的,但我不太确定。【参考方案2】:

...不同的是&lt;router-link&gt; 版本将为链接提供 SPA 功能(即不加载新页面,它会动态呈现组件)。

通过不加载新页面,我想您的意思是它不会重新加载页面。是的,这不是因为onclick 处理程序实际上被分配给does a preventDefault(防止页面重定向)而pushing a new entry into the history stack 的函数。

如果您查看the API reference,&lt;router-link&gt; 为您所做的最引人注目的事情是它根据活动/当前路线在active-classes 之间切换。

也就是说,您可以通过the v-slot 在默认插槽内进行动态&lt;a&gt;nchor 渲染;因为此时,href 插槽 prop 将是一个已解析的 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;
      
    
  

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

【讨论】:

嗯,我不确定我是否理解正确。您能否从问题中的代码中举一个例子?我尝试了上述建议,但我发现它很难。不知道是不是我理解错了。 @JDomleo 当然,给我一分钟。 谢谢@Yom S。这是我正在寻找的最接近的。然而,不完全是。 @JDomleo 既然我们都同意&lt;router-link&gt; 解析为&lt;a&gt;,是否有任何具体原因导致我们不能直接跳转到最终输出(&lt;a&gt;)?链接/href 不是这里的重要部分吗?

以上是关于如何根据链接是外部的还是内部的,在 Vue 中动态渲染 <router-link> 或 <a>?的主要内容,如果未能解决你的问题,请参考以下文章

有关C语言的内部函数和外部函数的定义说明

vue下载文件动态生成的a标签必须带上文件名吗

vue-打包为webapp,如何解决应用内跳转外部链接返回导致退出应用

如何使用 Vue-Loader / Webpack 指向外部(动态)资产

如何将外部 HTML 模板动态导入和解析到 Vue 组件中?

Linux查看命令是内部命令还是外部命令