<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 -->
有什么想法可以实现我想要的吗?
更好、更干净的方法:
<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>
...不同之处在于
版本将为链接提供 SPA 功能(即不加载新页面,而是动态呈现组件)。<router-link>
不加载新页面,我想您的意思是它不会重新加载页面。是的,事实并非如此,因为
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;
}
}
}
}
您基本上可以根据插槽属性在组件内锚标记上添加任何属性,例如以某些方式导航,添加特殊类,具体取决于您的用例。
您的代码是正确的,但它包含一个致命的错误:
: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"
>
希望有帮助!