Skip to content

Commit 80ff286

Browse files
committed
fix: optimize SafeRouterLink.vue
1 parent 880a2a3 commit 80ff286

File tree

1 file changed

+60
-63
lines changed

1 file changed

+60
-63
lines changed
Lines changed: 60 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<template>
2+
<!-- 添加preventDefault防止a标签默认行为,避免页面闪白 -->
23
<component
34
:is="linkComponent"
45
v-bind="componentProps"
6+
@click="handleClick"
57
>
68
<slot></slot>
79
</component>
@@ -11,17 +13,20 @@
1113
// 注意:我们有意使用普通JavaScript而非Typescript
1214
// 这可以避免TS在编译期间检查导入的组件
1315
14-
import { shallowRef, computed, onMounted, onBeforeMount } from 'vue'
16+
import { shallowRef, computed, ref, onBeforeMount, onMounted } from 'vue'
1517
import { useRouter } from 'vuepress/client'
1618
1719
// 安全地检测我们是否在服务器上
1820
const isServer = typeof window === 'undefined'
21+
let router = null
22+
23+
// 标记RouterLink是否已经加载完成
24+
const routerLinkLoaded = ref(false)
1925
2026
// 获取路由实例
21-
let router = null
2227
if (!isServer) {
2328
try {
24-
router = useRouter()
29+
router = useRouter()
2530
} catch (e) {
2631
console.warn('SafeRouterLink: Error getting router instance', e)
2732
}
@@ -59,40 +64,11 @@ const componentProps = computed(() => {
5964
? props.to.path
6065
: '/'
6166
62-
if (isServer) {
63-
// 在服务器端使用正常的a标签
64-
return {
65-
class: 'router-link-fallback',
66-
href: toPath,
67-
// 添加 onclick 防止默认行为
68-
onclick: 'return false;',
69-
...props.$attrs
70-
}
71-
} else if (linkComponent.value === 'a') {
72-
// 在客户端但RouterLink还未加载完成时
73-
// 使用 a 标签并自己处理导航逻辑
67+
if (isServer || linkComponent.value === 'a') {
68+
// 在服务器端或当仍然使用 a 标签时
7469
return {
7570
class: 'router-link-fallback',
7671
href: toPath,
77-
// 实现对点击事件的处理,阻止页面刷新但仍然能实现路由跳转
78-
onClick: (e) => {
79-
e.preventDefault(); // 阻止默认行为
80-
81-
// 如果有路由实例,手动调用导航
82-
if (router) {
83-
const path = typeof props.to === 'string' ? props.to :
84-
(props.to && typeof props.to === 'object') ? props.to : '/';
85-
86-
if (props.replace) {
87-
router.replace(path);
88-
} else {
89-
router.push(path);
90-
}
91-
} else {
92-
// 如果没有路由实例,回退到正常行为
93-
window.location.href = toPath;
94-
}
95-
},
9672
...props.$attrs
9773
}
9874
} else {
@@ -107,42 +83,63 @@ const componentProps = computed(() => {
10783
}
10884
})
10985
110-
// 在组件创建前就开始加载 RouterLink
86+
// 处理点击事件
87+
const handleClick = (e) => {
88+
// 如果还在使用a标签时,防止默认行为并用编程式跳转
89+
if (linkComponent.value === 'a' && router) {
90+
e.preventDefault()
91+
const toPath = typeof props.to === 'string'
92+
? props.to
93+
: (props.to && typeof props.to === 'object' && props.to.path)
94+
? props.to.path
95+
: '/'
96+
97+
// 使用router导航而非页面刷新
98+
if (props.replace) {
99+
router.replace(props.to)
100+
} else {
101+
router.push(props.to)
102+
}
103+
}
104+
}
105+
106+
// 提前在组件挂载前就开始加载 RouterLink
111107
onBeforeMount(() => {
112108
if (!isServer) {
113-
// 使用缓存避免重复导入RouterLink
114-
if (window.__ROUTER_LINK_LOADED__) {
115-
linkComponent.value = window.__ROUTER_LINK_COMPONENT__
116-
return
117-
}
109+
loadRouterLink()
110+
}
111+
})
112+
113+
// 定义加载 RouterLink 的函数
114+
const loadRouterLink = () => {
115+
// 使用缓存避免重复导入RouterLink
116+
if (window.__ROUTER_LINK_LOADED__) {
117+
linkComponent.value = window.__ROUTER_LINK_COMPONENT__
118+
routerLinkLoaded.value = true
119+
return
120+
}
118121
119-
// 使用立即执行的异步函数
120-
(async () => {
121-
try {
122-
// 使用 await 等待导入完成
123-
const vuepress = await import('vuepress/client')
124-
if (vuepress.RouterLink) {
125-
// 缓存RouterLink组件引用
126-
window.__ROUTER_LINK_COMPONENT__ = vuepress.RouterLink
127-
window.__ROUTER_LINK_LOADED__ = true
128-
linkComponent.value = vuepress.RouterLink
129-
}
130-
} catch (e) {
131-
console.warn('SafeRouterLink: Failed to load RouterLink, using fallback link', e)
122+
try {
123+
import('vuepress/client').then(vuepress => {
124+
if (vuepress.RouterLink) {
125+
// 缓存RouterLink组件引用
126+
window.__ROUTER_LINK_COMPONENT__ = vuepress.RouterLink
127+
window.__ROUTER_LINK_LOADED__ = true
128+
linkComponent.value = vuepress.RouterLink
129+
routerLinkLoaded.value = true
132130
}
133-
})();
131+
}).catch(e => {
132+
console.warn('SafeRouterLink: Failed to load RouterLink, using fallback link', e)
133+
})
134+
} catch (e) {
135+
console.warn('SafeRouterLink: Error importing RouterLink', e)
134136
}
135-
})
137+
}
136138
137-
// 也保留 onMounted 钩子,确保 RouterLink 被正确加载
139+
// 确保组件挂载后也尝试加载 RouterLink
138140
onMounted(() => {
139-
if (!isServer && !window.__ROUTER_LINK_LOADED__) {
140-
// 如果 onBeforeMount 没有成功加载,再次尝试
141-
setTimeout(() => {
142-
if (window.__ROUTER_LINK_LOADED__) {
143-
linkComponent.value = window.__ROUTER_LINK_COMPONENT__
144-
}
145-
}, 0)
141+
if (!isServer && !routerLinkLoaded.value) {
142+
loadRouterLink()
146143
}
147144
})
148145
</script>

0 commit comments

Comments
 (0)