1
1
<template >
2
+ <!-- 添加preventDefault防止a标签默认行为,避免页面闪白 -->
2
3
<component
3
4
:is =" linkComponent"
4
5
v-bind =" componentProps"
6
+ @click =" handleClick"
5
7
>
6
8
<slot ></slot >
7
9
</component >
11
13
// 注意:我们有意使用普通JavaScript而非Typescript
12
14
// 这可以避免TS在编译期间检查导入的组件
13
15
14
- import { shallowRef , computed , onMounted , onBeforeMount } from ' vue'
16
+ import { shallowRef , computed , ref , onBeforeMount , onMounted } from ' vue'
15
17
import { useRouter } from ' vuepress/client'
16
18
17
19
// 安全地检测我们是否在服务器上
18
20
const isServer = typeof window === ' undefined'
21
+ let router = null
22
+
23
+ // 标记RouterLink是否已经加载完成
24
+ const routerLinkLoaded = ref (false )
19
25
20
26
// 获取路由实例
21
- let router = null
22
27
if (! isServer) {
23
28
try {
24
- router = useRouter ()
29
+ router = useRouter ()
25
30
} catch (e) {
26
31
console .warn (' SafeRouterLink: Error getting router instance' , e)
27
32
}
@@ -59,40 +64,11 @@ const componentProps = computed(() => {
59
64
? props .to .path
60
65
: ' /'
61
66
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 标签时
74
69
return {
75
70
class: ' router-link-fallback' ,
76
71
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
- },
96
72
... props .$attrs
97
73
}
98
74
} else {
@@ -107,42 +83,63 @@ const componentProps = computed(() => {
107
83
}
108
84
})
109
85
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
111
107
onBeforeMount (() => {
112
108
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
+ }
118
121
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
132
130
}
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)
134
136
}
135
- })
137
+ }
136
138
137
- // 也保留 onMounted 钩子,确保 RouterLink 被正确加载
139
+ // 确保组件挂载后也尝试加载 RouterLink
138
140
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 ()
146
143
}
147
144
})
148
145
</script >
0 commit comments