fix: hashchange should only be triggered for same page navigations (#3768)

Co-authored-by: zonemeen <994718917@qq.com>
pull/3770/head
Divyansh Singh 1 year ago committed by GitHub
parent 5f28e74abf
commit 2a9fc2a26b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -38,6 +38,10 @@ interface VitePressData<T = any> {
isDark: Ref<boolean> isDark: Ref<boolean>
dir: Ref<string> dir: Ref<string>
localeIndex: Ref<string> localeIndex: Ref<string>
/**
* Current location hash
*/
hash: Ref<string>
} }
interface PageData { interface PageData {

@ -6,12 +6,14 @@ import {
readonly, readonly,
ref, ref,
shallowRef, shallowRef,
watch,
type InjectionKey, type InjectionKey,
type Ref type Ref
} from 'vue' } from 'vue'
import { import {
APPEARANCE_KEY, APPEARANCE_KEY,
createTitle, createTitle,
inBrowser,
resolveSiteDataByRoute, resolveSiteDataByRoute,
type PageData, type PageData,
type SiteData type SiteData
@ -47,6 +49,10 @@ export interface VitePressData<T = any> {
dir: Ref<string> dir: Ref<string>
localeIndex: Ref<string> localeIndex: Ref<string>
isDark: Ref<boolean> isDark: Ref<boolean>
/**
* Current location hash
*/
hash: Ref<string>
} }
// site data is a singleton // site data is a singleton
@ -82,6 +88,21 @@ export function initData(route: Route): VitePressData {
}) })
: ref(false) : ref(false)
const hashRef = ref(inBrowser ? location.hash : '')
if (inBrowser) {
window.addEventListener('hashchange', () => {
hashRef.value = location.hash
})
}
watch(
() => route.data,
() => {
hashRef.value = inBrowser ? location.hash : ''
}
)
return { return {
site, site,
theme: computed(() => site.value.themeConfig), theme: computed(() => site.value.themeConfig),
@ -95,7 +116,8 @@ export function initData(route: Route): VitePressData {
description: computed( description: computed(
() => route.data.description || site.value.description () => route.data.description || site.value.description
), ),
isDark isDark,
hash: computed(() => hashRef.value)
} }
} }

@ -66,16 +66,10 @@ export function createRouter(
async function go(href: string = inBrowser ? location.href : '/') { async function go(href: string = inBrowser ? location.href : '/') {
href = normalizeHref(href) href = normalizeHref(href)
if ((await router.onBeforeRouteChange?.(href)) === false) return if ((await router.onBeforeRouteChange?.(href)) === false) return
if (inBrowser) { if (inBrowser && href !== normalizeHref(location.href)) {
const currentUrl = new URL(location.href) // save scroll position before changing url
if (href !== normalizeHref(currentUrl.href)) { history.replaceState({ scrollPosition: window.scrollY }, document.title)
// save scroll position before changing url history.pushState(null, '', href)
history.replaceState({ scrollPosition: window.scrollY }, document.title)
history.pushState(null, '', href)
if (new URL(href, fakeHost).hash !== currentUrl.hash) {
window.dispatchEvent(new Event('hashchange'))
}
}
} }
await loadPage(href) await loadPage(href)
await router.onAfterRouteChanged?.(href) await router.onAfterRouteChanged?.(href)
@ -211,7 +205,12 @@ export function createRouter(
if (hash !== currentUrl.hash) { if (hash !== currentUrl.hash) {
history.pushState(null, '', href) history.pushState(null, '', href)
// still emit the event so we can listen to it in themes // still emit the event so we can listen to it in themes
window.dispatchEvent(new Event('hashchange')) window.dispatchEvent(
new HashChangeEvent('hashchange', {
oldURL: currentUrl.href,
newURL: href
})
)
} }
if (hash) { if (hash) {
// use smooth scroll when clicking on header anchor links // use smooth scroll when clicking on header anchor links

@ -1,12 +0,0 @@
import { inBrowser } from '../../shared'
import { ref } from 'vue'
const hashRef = ref(inBrowser ? location.hash : '')
if (inBrowser) {
window.addEventListener('hashchange', () => {
hashRef.value = location.hash
})
}
export { hashRef }

@ -1,13 +1,12 @@
import { computed } from 'vue' import { computed } from 'vue'
import { ensureStartingSlash } from '../support/utils' import { ensureStartingSlash } from '../support/utils'
import { useData } from './data' import { useData } from './data'
import { hashRef } from './hash'
export function useLangs({ export function useLangs({
removeCurrent = true, removeCurrent = true,
correspondingLink = false correspondingLink = false
} = {}) { } = {}) {
const { site, localeIndex, page, theme } = useData() const { site, localeIndex, page, theme, hash } = useData()
const currentLang = computed(() => ({ const currentLang = computed(() => ({
label: site.value.locales[localeIndex.value]?.label, label: site.value.locales[localeIndex.value]?.label,
link: link:
@ -29,7 +28,7 @@ export function useLangs({
currentLang.value.link.length - 1 currentLang.value.link.length - 1
), ),
!site.value.cleanUrls !site.value.cleanUrls
) + hashRef.value ) + hash.value
} }
) )
) )

@ -18,7 +18,6 @@ import {
getSidebarGroups getSidebarGroups
} from '../support/sidebar' } from '../support/sidebar'
import { useData } from './data' import { useData } from './data'
import { hashRef } from './hash'
export interface SidebarControl { export interface SidebarControl {
collapsed: Ref<boolean> collapsed: Ref<boolean>
@ -138,7 +137,7 @@ export function useCloseSidebarOnEscape(
export function useSidebarControl( export function useSidebarControl(
item: ComputedRef<DefaultTheme.SidebarItem> item: ComputedRef<DefaultTheme.SidebarItem>
): SidebarControl { ): SidebarControl {
const { page } = useData() const { page, hash } = useData()
const collapsed = ref(false) const collapsed = ref(false)
@ -155,7 +154,7 @@ export function useSidebarControl(
isActiveLink.value = isActive(page.value.relativePath, item.value.link) isActiveLink.value = isActive(page.value.relativePath, item.value.link)
} }
watch([page, item, hashRef], updateIsActiveLink) watch([page, item, hash], updateIsActiveLink)
onMounted(updateIsActiveLink) onMounted(updateIsActiveLink)
const hasActiveLink = computed(() => { const hasActiveLink = computed(() => {

Loading…
Cancel
Save