CMCDragonkai
CMCDragonkai

Reputation: 6372

How to extend the onClick handler behaviour for a `router-link` in vue3 router

I have a <router-link /> that I want to use to navigate to another page in a Vue 3 application, but I also want to run another function when this link is clicked.

Right now I have to use an extra <span /> element to wrap the <router-link /> and add the @click attribute there to rely on event bubbling. Adding the @click handler on <router-link /> causes the router link not to work and the browser thinks it is just a normal anchor href.

    <span @click="handleClose(imageId)">
      <router-link
        :to="{name: 'image', params: {'imageId': imageId}}"
        class="permalink">
        Permalink
      </router-link>
    </span>

Is there a better way?

Upvotes: 5

Views: 7554

Answers (2)

LeBen
LeBen

Reputation: 2049

To avoid potential weird concurrency bugs (the view change could happen before your method being called, method which would then be attached to an unmounted component), I would do a programmatic navigation in your method:

<template>
  <button type="button" @click="handleClose(imageId)">
    Permalink
  </button>
</template>

<script>
import router from '@/wherever/your/router/is/initialized';

export default {
  methods: {
    handleClose(imageId) {
      // Do your stuff
      router.push({ name: 'image', params: {'imageId': imageId}});
    }
  }
}
</script>

Upvotes: 5

IVO GELOV
IVO GELOV

Reputation: 14259

You must use the .native modifier on the @click event of router-link. The reason is quite simple - router-link is a Vue component but it does not emit a click event. Therefore you have to listen for the native click event coming from the browser.

https://github.com/vuejs/vue-router/issues/800

var router = new VueRouter({
routes:
[
{path: '/', component: {
template: '#first',
methods:
{
  showAlert(text)
  {
    window.alert(text);
  }
}
}},
{path: '/second', component: {
template: '#second',
methods:
{
  showAlert(text)
  {
    window.alert(text);
  }
}
}},
]
});
new Vue(
{
template: '#main',
router: router,
}).$mount('#app');
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">test</div>
<template id="main">
<div>
<router-view></router-view>
</div>
</template>
<template id="first">
<router-link to="/second" @click.native="showAlert('second')">GOTO second</router-link>
</template>
<template id="second">
<router-link to="/" @click.native="showAlert('first')">GOTO first</router-link>
</template>

Upvotes: 4

Related Questions