如何让 router-link 与自定义 link 组件一起工作?
How to make router-link work with custom link component?
<base-link>
分量
我有一个 Vue 组件 <base-link>
,每次我想要一个锚点时我都会使用它。它主要用于应用特定于 links 的样式,以便整个页面上的所有 links 在不应用全局样式的情况下看起来都一样。
使 <router-link>
使用 <base-link>
当使用 <router-link>
组件创建 link 时,我无法应用这些样式(<base-link>
样式是有范围的)除非 <router-link>
使用我的 <base-link>
用于创建锚元素的组件。
幸运的是 <router-link>
提供了 tag
attribute,它似乎正是这样做的。不幸的是我无法让它工作。我有 2 个问题:
我所有的组件都是在本地注册的(我使用 ES6 模块和 Webpack 并在每次需要时在本地导入组件)。 <router-link>
不知道 <base-link>
组件是什么,也无法渲染它。有没有办法注入本地组件供 <router-link>
使用?
为了解决问题 #1,我认为全局声明 <base-link>
组件就足够了。不幸的是它仍然不起作用。这次 <base-link>
组件可以正确呈现,但仍然无法正常工作 - 不会对点击事件做出反应。在我看来,问题是它的 href
属性根本没有设置。有没有办法让 <router-link>
正确设置? (无需手动设置)
问题
如何解决问题 #1 和 #2?我怀疑 #1 可能是不可能的,但我希望至少 #2 是。
代码示例
Here是笔下的代码,说明了这两个问题。
const router = new VueRouter({
routes: [
{
path: "/",
component: {
template: '<p>Homepage template</p>'
}
},
{
path: "/subpage",
component: {
template: '<p>Subpage template</p>'
}
}
]
});
// Globally registered BaseLink.
Vue.component('BaseLinkGlobal', {
props: {
href: String
},
template: `
<a
:href="href"
class="BaseLinkGlobal"
>
<slot />
</a>
`
})
const vue = new Vue({
el: "#app",
router,
components: {
// Locally registered BaseLink.
BaseLinkLocal: {
props: {
href: String
},
template: `
<a
:href="href"
class="BaseLinkLocal"
>
<slot />
</a>
`
}
},
template: `
<div>
<!-- 2 router links. One uses locally registered BaseLink
-- and the other one a globally registered one. -->
<nav>
<router-link
to="/"
tag="base-link-local"
>
Home
</router-link>
<router-link
to="/subpage"
tag="base-link-global"
>
Subpage
</router-link>
</nav>
<router-view />
</div>
`
});
您可以创建一个基础 link 组件,它可以兼作普通 a
标签或 <router-link>
当您需要时。
//Base link
<template>
<component :is="type" :class="{'base': type === 'a'}" v-bind="$attrs">
<slot></slot>
</component>
</template>
<script>
export default {
props: {
routerLink: {
type: Boolean,
default: false
}
},
computed: {
type() {
return this.routerLink ? 'router-link' : 'a'
}
}
}
</script>
<style scopex>
.base {
border: 1px solid red;
}
</style>
用法
当你想把它当作普通的 link 使用时,只要不提供 router-link
道具,如下所示:
<base-link>This is a base a tag</base-link>
要将其用作 router-link
,只需添加 router-link
属性和 to
属性:
<base-link router-link to="/">This is router-link</base-link>
关于base-link成分的说明:
- 我们使用 vuejs 提供的
component
来渲染 a
标签或 router-link
基于 routerLink
属性的真实性。
- 如果是正常的 link 即
a
,则添加 .base
的 class
我们绑定 $attrs
,这允许我们使组件更加透明,即允许我们使用 href
或 to
之类的属性,而无需将它们作为 props 传递。
<base-link href="https://google.com">go to google</base-link>
你可以看看here以获得更多关于$attrs
用法的解释
这是为了解决问题#2
全局组件不继承路由器的事件监听器link。您可以通过在全局组件中添加 v-on="$listeners"
使其继承。
// Globally registered BaseLink.
Vue.component('BaseLinkGlobal', {
props: {
href: String
},
template: `
<a
:href="href"
class="BaseLinkGlobal"
v-on="$listeners"
>
<slot />
</a>
`
})
link 添加后有效:https://codepen.io/jacobgoh101/pen/YvqJxL?editors=0010
<base-link>
分量
我有一个 Vue 组件 <base-link>
,每次我想要一个锚点时我都会使用它。它主要用于应用特定于 links 的样式,以便整个页面上的所有 links 在不应用全局样式的情况下看起来都一样。
使 <router-link>
使用 <base-link>
当使用 <router-link>
组件创建 link 时,我无法应用这些样式(<base-link>
样式是有范围的)除非 <router-link>
使用我的 <base-link>
用于创建锚元素的组件。
幸运的是 <router-link>
提供了 tag
attribute,它似乎正是这样做的。不幸的是我无法让它工作。我有 2 个问题:
我所有的组件都是在本地注册的(我使用 ES6 模块和 Webpack 并在每次需要时在本地导入组件)。
<router-link>
不知道<base-link>
组件是什么,也无法渲染它。有没有办法注入本地组件供<router-link>
使用?为了解决问题 #1,我认为全局声明
<base-link>
组件就足够了。不幸的是它仍然不起作用。这次<base-link>
组件可以正确呈现,但仍然无法正常工作 - 不会对点击事件做出反应。在我看来,问题是它的href
属性根本没有设置。有没有办法让<router-link>
正确设置? (无需手动设置)
问题
如何解决问题 #1 和 #2?我怀疑 #1 可能是不可能的,但我希望至少 #2 是。
代码示例
Here是笔下的代码,说明了这两个问题。
const router = new VueRouter({
routes: [
{
path: "/",
component: {
template: '<p>Homepage template</p>'
}
},
{
path: "/subpage",
component: {
template: '<p>Subpage template</p>'
}
}
]
});
// Globally registered BaseLink.
Vue.component('BaseLinkGlobal', {
props: {
href: String
},
template: `
<a
:href="href"
class="BaseLinkGlobal"
>
<slot />
</a>
`
})
const vue = new Vue({
el: "#app",
router,
components: {
// Locally registered BaseLink.
BaseLinkLocal: {
props: {
href: String
},
template: `
<a
:href="href"
class="BaseLinkLocal"
>
<slot />
</a>
`
}
},
template: `
<div>
<!-- 2 router links. One uses locally registered BaseLink
-- and the other one a globally registered one. -->
<nav>
<router-link
to="/"
tag="base-link-local"
>
Home
</router-link>
<router-link
to="/subpage"
tag="base-link-global"
>
Subpage
</router-link>
</nav>
<router-view />
</div>
`
});
您可以创建一个基础 link 组件,它可以兼作普通 a
标签或 <router-link>
当您需要时。
//Base link
<template>
<component :is="type" :class="{'base': type === 'a'}" v-bind="$attrs">
<slot></slot>
</component>
</template>
<script>
export default {
props: {
routerLink: {
type: Boolean,
default: false
}
},
computed: {
type() {
return this.routerLink ? 'router-link' : 'a'
}
}
}
</script>
<style scopex>
.base {
border: 1px solid red;
}
</style>
用法
当你想把它当作普通的 link 使用时,只要不提供 router-link
道具,如下所示:
<base-link>This is a base a tag</base-link>
要将其用作 router-link
,只需添加 router-link
属性和 to
属性:
<base-link router-link to="/">This is router-link</base-link>
关于base-link成分的说明:
- 我们使用 vuejs 提供的
component
来渲染a
标签或router-link
基于routerLink
属性的真实性。 - 如果是正常的 link 即
a
,则添加 我们绑定
$attrs
,这允许我们使组件更加透明,即允许我们使用href
或to
之类的属性,而无需将它们作为 props 传递。<base-link href="https://google.com">go to google</base-link>
.base
的 class
你可以看看here以获得更多关于$attrs
这是为了解决问题#2
全局组件不继承路由器的事件监听器link。您可以通过在全局组件中添加 v-on="$listeners"
使其继承。
// Globally registered BaseLink.
Vue.component('BaseLinkGlobal', {
props: {
href: String
},
template: `
<a
:href="href"
class="BaseLinkGlobal"
v-on="$listeners"
>
<slot />
</a>
`
})
link 添加后有效:https://codepen.io/jacobgoh101/pen/YvqJxL?editors=0010