如何根据链接是外部的还是内部的,在 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 组件,它将在其中呈现一个链接。我已经删除了与问题无关的任何内容(即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 功能(即不加载新页面,它会动态呈现组件)。
预期 - 当type="internal"
时,它将呈现<router-link>
版本。当type="external"
时,会渲染<a>
版本。
<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"
时,一个<a>
与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>
【讨论】:
这将是我的第二种方法,但是我的其他属性,例如rel
、target
、class
等将在它们之间重复。我试图不复制属性。
更新答案,立即查看
尝试了第二个选项,现在似乎没有渲染任何东西。
这是一个非常好的替代解决方案,唯一的缺点是在<router-link>
和<a>
中重复属性,例如rel
、class
和target
。如果可以在不重复属性的情况下建议一种干净的方法,我很乐意将其作为公认的答案。
@JDomleo 如果您同时为“内部”和“外部”锚点添加预期输出会很有帮助,例如取哪个属性(或者如果可以让它们都拥有一切)。我假设这些被剥离的属性是用于外部链接的,但我不太确定。【参考方案2】:
...不同的是
<router-link>
版本将为链接提供 SPA 功能(即不加载新页面,它会动态呈现组件)。
通过不加载新页面,我想您的意思是它不会重新加载页面。是的,这不是因为onclick
处理程序实际上被分配给does a preventDefault
(防止页面重定向)而pushing a new entry into the history stack 的函数。
如果您查看the API reference,<router-link>
为您所做的最引人注目的事情是它根据活动/当前路线在active-class
es 之间切换。
也就是说,您可以通过the v-slot
在默认插槽内进行动态<a>
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 既然我们都同意<router-link>
解析为<a>
,是否有任何具体原因导致我们不能直接跳转到最终输出(<a>
)?链接/href 不是这里的重要部分吗?以上是关于如何根据链接是外部的还是内部的,在 Vue 中动态渲染 <router-link> 或 <a>?的主要内容,如果未能解决你的问题,请参考以下文章
vue-打包为webapp,如何解决应用内跳转外部链接返回导致退出应用
如何使用 Vue-Loader / Webpack 指向外部(动态)资产