Reputation: 6911
<base-link>
componentI have a Vue component <base-link>
, which I use every time I want to have an achor. It's mostly for applying styles specific to links, so that all the links across the whole page look the same without applying global styles.
<router-link>
use <base-link>
When using <router-link>
component to create a link, I cannot apply those styles (<base-link>
styles are scoped) unless <router-link>
uses my <base-link>
component to create the anchor element.
Fortunately <router-link>
provides tag
attribute, which seems to do exactly that. Unfortunately I can't get it to work. I have 2 problems:
All my components are locally registered (I use ES6 modules with Webpack and import components locally every time I need them). <router-link>
doesn't know what <base-link>
component is and can't render it. Is there a way to inject a local component for <router-link>
to use?
To solve problem #1, I thought it's enough to declare <base-link>
component globally. Unfortunately it still doesn't work. This time <base-link>
component gets rendered properly, but is still not functional - doesn't react to click events. It seems to me the problem is that it's href
attribute isn't set at all. Is there a way to make <router-link>
set it properly? (without setting it manually)
How do I solve problems #1 and #2? I suspect #1 might be not possible, but I hope at least #2 is.
Here is a pen with code below, which illustrates both problems.
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>
`
});
Upvotes: 1
Views: 4177
Reputation: 31362
You can create a base link component which can double as a normal a
tag or <router-link>
when you wish.
//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>
when you want to use it as a normal link just do not provide the router-link
prop as below:
<base-link>This is a base a tag</base-link>
To use it as a router-link
just add the router-link
prop along with the to
prop:
<base-link router-link to="/">This is router-link</base-link>
Explanation about the base-link component:
We use a component
which is provided by vuejs to render a
tag or router-link
base on the truthiness of the routerLink
prop.
A class of .base
is added if it is a normal link i.e a
we bind $attrs
which allows us to make the component more transparent i.e allows us to use attributes like href
or to
without passing them as props.
<base-link href="https://google.com">go to google</base-link>
You can have a look here for more explanation about usage of $attrs
Upvotes: 2
Reputation: 20845
This is for solving problem #2
The global component doesn't inherit the event listener of the router link. You can make it inherit by adding v-on="$listeners"
to the global component.
// Globally registered BaseLink.
Vue.component('BaseLinkGlobal', {
props: {
href: String
},
template: `
<a
:href="href"
class="BaseLinkGlobal"
v-on="$listeners"
>
<slot />
</a>
`
})
The link works after adding it: https://codepen.io/jacobgoh101/pen/YvqJxL?editors=0010
Upvotes: 1