1111// 注意:我们有意使用普通JavaScript而非Typescript
1212// 这可以避免TS在编译期间检查导入的组件
1313
14- import { h , shallowRef , computed } from ' vue'
14+ import { shallowRef , computed , onMounted , onBeforeMount } from ' vue'
15+ import { useRouter } from ' vuepress/client'
1516
1617// 安全地检测我们是否在服务器上
1718const isServer = typeof window === ' undefined'
1819
20+ // 获取路由实例
21+ let router = null
22+ if (! isServer) {
23+ try {
24+ router = useRouter ()
25+ } catch (e) {
26+ console .warn (' SafeRouterLink: Error getting router instance' , e)
27+ }
28+ }
29+
1930// 使用 shallowRef 避免 Vue 深入解析导入的组件
2031const linkComponent = shallowRef (' a' )
2132
@@ -41,15 +52,51 @@ const props = defineProps({
4152
4253// 计算出给组件的属性
4354const componentProps = computed (() => {
55+ // 处理对象形式的 to 属性,确保在使用 a 标签时有正确的 href
56+ const toPath = typeof props .to === ' string'
57+ ? props .to
58+ : (props .to && typeof props .to === ' object' && props .to .path )
59+ ? props .to .path
60+ : ' /'
61+
4462 if (isServer) {
45- // 在服务器端,我们使用普通的a标签
63+ // 在服务器端使用正常的a标签
4664 return {
4765 class: ' router-link-fallback' ,
48- href: typeof props .to === ' string' ? props .to : ' ' ,
66+ href: toPath,
67+ // 添加 onclick 防止默认行为
68+ onclick: ' return false;' ,
69+ ... props .$attrs
70+ }
71+ } else if (linkComponent .value === ' a' ) {
72+ // 在客户端但RouterLink还未加载完成时
73+ // 使用 a 标签并自己处理导航逻辑
74+ return {
75+ class: ' router-link-fallback' ,
76+ 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+ },
4996 ... props .$attrs
5097 }
5198 } else {
52- // 在客户端,我们使用RouterLink的属性
99+ // 在客户端且RouterLink已加载,使用RouterLink的属性
53100 return {
54101 to: props .to ,
55102 custom: props .custom ,
@@ -60,24 +107,42 @@ const componentProps = computed(() => {
60107 }
61108})
62109
63- // 只在客户端环境下动态导入和使用RouterLink
64- if (! isServer) {
65- // 时间函数延迟运行,确保到了客户端才运行
66- setTimeout (() => {
67- try {
68- // 动态导入RouterLink
69- // 先尝试从 vuepress/client 中导入,这样在不同包管理器下都能正常工作
70- import (' vuepress/client' ).then (vuepress => {
71- // 检查是否存在RouterLink
110+ // 在组件创建前就开始加载 RouterLink
111+ onBeforeMount (() => {
112+ if (! isServer) {
113+ // 使用缓存避免重复导入RouterLink
114+ if (window .__ROUTER_LINK_LOADED__ ) {
115+ linkComponent .value = window .__ROUTER_LINK_COMPONENT__
116+ return
117+ }
118+
119+ // 使用立即执行的异步函数
120+ (async () => {
121+ try {
122+ // 使用 await 等待导入完成
123+ const vuepress = await import (' vuepress/client' )
72124 if (vuepress .RouterLink ) {
125+ // 缓存RouterLink组件引用
126+ window .__ROUTER_LINK_COMPONENT__ = vuepress .RouterLink
127+ window .__ROUTER_LINK_LOADED__ = true
73128 linkComponent .value = vuepress .RouterLink
74129 }
75- }). catch ( e => {
130+ } catch (e) {
76131 console .warn (' SafeRouterLink: Failed to load RouterLink, using fallback link' , e)
77- })
78- } catch (e) {
79- console .warn (' SafeRouterLink: Error importing RouterLink' , e)
80- }
81- }, 0 )
82- }
132+ }
133+ })();
134+ }
135+ })
136+
137+ // 也保留 onMounted 钩子,确保 RouterLink 被正确加载
138+ 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 )
146+ }
147+ })
83148 </script >
0 commit comments