moso
moso

Reputation: 121

Vue.js: Add router-link-active to vue-router component loaded for root

I'm having some trouble with vue-router. My routes are set up like this:

const routes = [
    { path: '/', component: a },
    { path: '/a', component: a },
    { path: '/b', component: b },
    { path: '/c', component: c }
]

As you can see, I want to load component a when the page loads. But I don't want the URL to change to /a when the page loads. However I would like to trigger the router-link-active-class on the <router-link> related to the a component, even though I'm still at /.

I've tried with some simple JS like:

if(window.location.hash === '#/') {
    var el = document.querySelector('#drawerList').firstElementChild;
    el.className += 'router-link-active';
}

However vue is not removing the class again when I click on the link to /b or /c. Can any of you hint me in the corrent direction?

Upvotes: 2

Views: 4696

Answers (6)

YMH
YMH

Reputation: 3133

use could use exact-active-class on your router-link element.
Note: desiredClass is the class you want to apply if the URL matches the router-link's to attribute.

<router-link to="/about" exact-active-class="desiredClass">About</router-link>

Upvotes: 0

Alex
Alex

Reputation: 5257

In my case I had a use-case when I needed to have an active class whenever 1 of the following is true:

  • /users
  • /users/1/edit
  • /users/1/view

using vuejs 3 in main app.vue I have routes defined. The routes are then parameter-injected into sidemenu component (which is not important in this example)

app.vue dependencies

import { ref, watch } from "vue";
import { useRoute } from "vue-router";

setup() method (using composition API):

setup() {
const route = useRoute();

const myActiveClass = ref(null);

const checkIfMustActivateRoute = () => {
  return {
    active:
      window.location.pathname.startsWith("/users/view/") ||
      window.location.pathname.startsWith("/users/edit/"),
  };
};

watch(
  () => route.fullPath,
  async (_) => {
    myActiveClass.value = checkIfMustActivateRoute();
  }
);

myActiveClass.value = checkIfMustActivateRoute();

const routes = ref([
  { id: 0, name: "Home", href: "/", icon: "fas fa-home" },
  {
    id: 1,
    name: "Users",
    href: "/users",
    icon: "far fa-clone",
    class: myActiveClass,
  },
]);

return {
  routes,
};
},

NavLinks are dynamically generated like so:

  <li v-for="tab of routes" :key="tab.id" class="nav-item">
    <router-link :to="tab.href" class="nav-link" :class="tab.class">
      <div class="align-items-center">
        <span class="nav-link-icon"><i :class="tab.icon"></i></span>
        <span class="nav-link-text ms-3">{{ tab.name }}</span>
      </div>
    </router-link>
  </li>

Now whenever the router's path property changes I trigger the active class update function. This way we don't have to use aliases or any other trickery.

The result is - for all 3 paths I always enable active class.

Upvotes: 0

Jakarea Parvez
Jakarea Parvez

Reputation: 550

The best solution is use "exact" in root url

<router-link to="/" tag="a" exact>Home</router-link>

Upvotes: 6

moso
moso

Reputation: 121

This is my pre-answer - see solution instead.

I ended up doing something custom, rather than seeking a native solution. After looking at a few issues on GitHub, I realised that something like this, stupid as it is - I admit, doesn't exist natively in Vue.js.

My solution: adding an eventlistener that removes itself along with the class, once another link is clicked in the #drawerMenu:

HTML structure:

<ul id="drawerMenu">
  <li>
    <router-link to="/a">A</router-link>
  </li>
  <li>
    <router-link to="/b">B</router-link>
  </li>
  <li>
    <router-link to="/c">C</router-link>
  </li>
</ul>

JS:

if(window.location.hash === '#/') {
    var menu = document.querySelector('#drawerMenu');
    var el = menu.firstElementChild.firstChild;
    el.className += 'router-link-active';

    var removeRouterClass = function () {
        el.classList.remove('router-link-active');
        menu.removeEventListener('click', removeRouterClass);
    }

    menu.addEventListener('click', removeRouterClass);
}

I hope this helps others like me, and hopefully this will be built into Vue natively at some point.

Upvotes: 0

bast
bast

Reputation: 96

You can manually bind class to router-link like this

<router-link :class="{'router-link-active': $route.fullPath ==='/' || $route.fullPath === '/a'}" to="/a"></router-link>

Upvotes: 8

Egor Stambakio
Egor Stambakio

Reputation: 18156

Try <router-link to="/" exact>

It prevents active class inclusive match behavior.

Upvotes: 0

Related Questions