vuejs / vitepress

Vite & Vue powered static site generator.
https://vitepress.dev
MIT License
12.89k stars 2.08k forks source link

The default click listener added by the router.ts level is too high #4075

Closed shellRaining closed 2 months ago

shellRaining commented 2 months ago

Describe the bug

I've been trying to add a view transition effect to the article links on the homepage recently, I saw such a display effect.

https://github.com/user-attachments/assets/6c0636c7-cd6e-495b-acee-3460bdf80f43

When I first clicked on the article link, the transition effect displayed normally. After clicking the same article link a second time, could see the article flicker for a moment.

Reproduction

The link below is my relevant code, which is very simple, containing only a template for an "a" link, and then there is a click event listener that executes a transition effect upon clicking.

https://github.com/shellRaining/blog/blob/main/theme/Home/PostItem.vue

After my investigation, I found that an event listener was at too high a level, preventing me from intercepting its actions.

https://github.com/vuejs/vitepress/blob/8f31a4c0780657af9137762c9394c56912f6e383/src/client/app/router.ts#L174-L239

I attempted to intercept this event by using the capture and stopImmediatePropagation functions, but due to the timing of the setup being relatively late, it was not possible to achieve this. When I replaced the a link with button, this bug no longer occurred.

Expected behavior

I hope to adjust the hierarchy of this listener so that users can customize link jump behavior.

System Info

System:
    OS: macOS 14.1
    CPU: (8) arm64 Apple M1
    Memory: 78.14 MB / 8.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 22.4.1 - /opt/homebrew/bin/node
    Yarn: 1.22.22 - /opt/homebrew/bin/yarn
    npm: 10.8.1 - /opt/homebrew/bin/npm
    pnpm: 9.6.0 - ~/Library/pnpm/pnpm
    Watchman: 2024.07.15.00 - /opt/homebrew/bin/watchman
  Browsers:
    Safari: 17.1
    Chrome: upon 111

Additional context

Is there any other way to solve this problem? I once wanted to use onBeforeRouteChange hook, but seems not suit my requirement.

Validations

brc-dd commented 2 months ago

In your case, since you are manually handling routing, you can add something like this to completely skip the router:

const viewTransitionsEnabled = ref('false')
onMounted(() => {
  viewTransitionsEnabled.value = 'startViewTransition' in document
})

<a
  :class="viewTransitionsEnabled && 'vp-raw'"
  ...
>
shellRaining commented 2 months ago
<script lang="ts" setup>
const viewTransitionsEnabled = ref(false);
onMounted(() => {
  viewTransitionsEnabled.value = "startViewTransition" in document;
});
</script>

<template>
  <a
    class="post-title"
    :class="viewTransitionsEnabled && 'vp-raw'"
    :href="withBase(post.url)"
    @click="changeRoute(post.url)"
  >
    {{ post.frontmatter.title }}
  </a>
</template>

still not work, and an error has occurred Hydration completed but contains mismatches.

https://github.com/user-attachments/assets/f845bac5-3bc4-4c7a-b79e-2db06e4a1d36

shellRaining commented 2 months ago

sorry I forget to add prevent modifier for event handle 😄, which cause this mismatches