'Vue 3/Vue Router - Unplanned firing of onClick event listener
Working with Vue 3 and Vue Router. Event listeners work as planned on initial 'click' navigations, to and from Details.vue page. However, upon successive 'click' attempts, hideDetails() is immediately called without a perceived 'click' event.
Home.vue
<template>
<main class="rounded">
<item-one />
<item-two />
</main>
<aside class="details__modal">
<router-view></router-view>
</aside>
</template>
ItemOne.vue, ItemTwo.vue
<template>
<button @click="showDetails(id)">Item Name</button>
</template>
<script lang="ts">
import {showDetails} from '@/scripts/utils'
</script>
Vue Router
Details.vue is set up as a child of Home.vue. addEventListener() is called via global navigation guard.
...
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'home',
component: Home,
children: [
{
path: 'details',
name: 'details',
component: () =>
import(
/* webpackChunkName: "details" */ '../views/Details.vue'
),
props: route => route.params,
},
],
},
]
const router = createRouter({
history: createWebHistory(),
routes
})
router.afterEach(to => {
if (to.name === 'details')
document.addEventListener('click', handle_hideDetails)
})
Details.vue
On showDetails(), Details.vue is rendered as a child of Home.vue and displayed within a modal. If props.id does not exists, hideDetails() redirects to Home.vue. Before leaving page, removeEventListener() is called via the component navigation guard onBeforeRouteLeave().
<template>
<div class="details__wrapper">...</div
</template>
<script lang="ts">
...
export default defineComponent({
props: {
id: {
type: String
}
},
setup(props){
if(!props.id) hideDetails()
onBeforeRouteLeave(_ => document.removeEventListener('click', handle_hideDetails))
}
})
</script>
utils.ts
All utility functions are here.
import vm from '@/main'
export const handle_hideDetails = (e: Event): void => {
const el = <HTMLElement>document.querySelector('div.details__wrapper')
if (!e.composedPath().includes(el)) hideDetails()
}
export const showDetails = (id: string): void => {
document.querySelector('aside.details__modal')?.classList.add('show')
vm.$router.push({
name: 'details',
params: { id },
})
}
export const hideDetails = (): void => {
document.querySelector('aside.details__modal')?.classList.remove('show')
setTimeout(() => vm.$router.push({ name: 'home' }), 2000)
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
