@@ -45,6 +45,10 @@ export interface IRouterOptions extends IBaseRouterOptions {
4545 * default initial route
4646 */
4747 defaultRoute ?: string ;
48+ /**
49+ * The maximum number of historical records stored in the browser, the default is 10.
50+ */
51+ maxHistoryLength ?: number ;
4852}
4953
5054@injectable ( {
@@ -53,6 +57,10 @@ export interface IRouterOptions extends IBaseRouterOptions {
5357class ReactantRouter extends BaseReactantRouter {
5458 private passiveRoute = false ;
5559
60+ private cachedHistory : RouterState [ ] = [ ] ;
61+
62+ private forwardHistory : RouterState [ ] = [ ] ;
63+
5664 constructor (
5765 protected portDetector : PortDetector ,
5866 @inject ( SharedAppOptions ) protected sharedAppOptions : ISharedAppOptions ,
@@ -139,6 +147,19 @@ class ReactantRouter extends BaseReactantRouter {
139147
140148 // #region sync init router from clients in Worker mode
141149 this . portDetector . onServer ( ( transport ) => {
150+ watch (
151+ this ,
152+ ( ) => this . router ,
153+ ( router ) => {
154+ if (
155+ router ?. location . pathname !==
156+ this . cachedHistory [ 0 ] ?. location ?. pathname
157+ ) {
158+ this . cachedHistory . unshift ( router ! ) ;
159+ this . cachedHistory . length = this . maxHistoryLength ; // Limit the length of the historical stack
160+ }
161+ }
162+ ) ;
142163 if ( this . portDetector . isWorkerMode && ! this . enableCacheRouting ) {
143164 transport
144165 . emit ( syncWorkerRouterName , this . portDetector . name )
@@ -251,6 +272,10 @@ class ReactantRouter extends BaseReactantRouter {
251272 // #endregion
252273 }
253274
275+ get maxHistoryLength ( ) {
276+ return this . options . maxHistoryLength ?? 10 ;
277+ }
278+
254279 watchRehydratedRouting ( ) {
255280 // The first rendering and the hydration of the persistent router may emit actions in a different order due to the module order.
256281 let firstTrigger = false ;
@@ -511,63 +536,148 @@ class ReactantRouter extends BaseReactantRouter {
511536 }
512537 }
513538
514- async go ( n : number ) {
515- if ( this . portDetector . isServerWorker ) {
516- const router : RouterState = await fork (
517- this as any ,
518- '_makeRoutingOnClient' ,
519- [
520- {
521- args : [ n ] ,
522- action : 'go' ,
523- name : this . portDetector . name ,
524- } ,
525- ]
526- ) ;
527- this . dispatchChanged ( router ) ;
528- } else {
539+ async go ( n : number ) : Promise < void > {
540+ if ( ! this . portDetector . shared ) {
529541 this . lastRoutedTimestamp = Date . now ( ) ;
530542 super . go ( n ) ;
543+ return ;
531544 }
532- }
545+ if ( this . portDetector . isClient ) {
546+ return delegate ( this as ReactantRouter , 'go' , [ n ] ) ;
547+ }
548+ if ( n < 0 ) {
549+ // Navigate backward (like goBack)
550+ const stepsBack = Math . abs ( n ) ;
551+ if ( this . cachedHistory . length > stepsBack ) {
552+ // Pop the current route to the forward history stack
553+ const currentRouter = this . cachedHistory . shift ( ) ;
554+ this . forwardHistory . unshift ( currentRouter ! ) ; // Add to forward history
533555
534- async goBack ( ) {
535- if ( this . portDetector . isServerWorker ) {
536- const router : RouterState = await fork (
537- this as any ,
538- '_makeRoutingOnClient' ,
539- [
540- {
541- args : [ ] ,
542- action : 'goBack' ,
543- name : this . portDetector . name ,
544- } ,
545- ]
546- ) ;
547- this . dispatchChanged ( router ) ;
556+ // Get the target router (stepsBack-th item)
557+ const targetRouter = this . cachedHistory [ stepsBack - 1 ] ;
558+
559+ if ( targetRouter ) {
560+ const router : RouterState = await fork (
561+ this as any ,
562+ '_makeRoutingOnClient' ,
563+ [
564+ {
565+ args : [
566+ targetRouter . location . pathname ,
567+ targetRouter . location . state ,
568+ ] ,
569+ action : 'replace' ,
570+ name : this . portDetector . name ,
571+ } ,
572+ ]
573+ ) ;
574+ this . dispatchChanged ( router ) ;
575+ } else {
576+ console . warn ( 'No more history to go back.' ) ;
577+ }
578+ } else {
579+ console . warn ( 'No more history to go back.' ) ;
580+ }
581+ } else if ( n > 0 ) {
582+ // Navigate forward (like goForward)
583+ const stepsForward = n ;
584+ if ( this . forwardHistory . length >= stepsForward ) {
585+ const targetRouter = this . forwardHistory [ stepsForward - 1 ] ;
586+ if ( targetRouter ) {
587+ const router : RouterState = await fork (
588+ this as any ,
589+ '_makeRoutingOnClient' ,
590+ [
591+ {
592+ args : [
593+ targetRouter . location . pathname ,
594+ targetRouter . location . state ,
595+ ] ,
596+ action : 'replace' ,
597+ name : this . portDetector . name ,
598+ } ,
599+ ]
600+ ) ;
601+ this . dispatchChanged ( router ) ;
602+ } else {
603+ console . warn ( 'No more history to go forward.' ) ;
604+ }
605+ // Remove the used entry from the forward stack
606+ this . forwardHistory . splice ( 0 , stepsForward ) ;
607+ } else {
608+ console . warn ( 'No more history to go forward.' ) ;
609+ }
548610 } else {
611+ // Go to the current route (refresh the page)
612+ console . warn ( 'Going to the current route (n = 0) does nothing.' ) ;
613+ }
614+ }
615+
616+ async goBack ( ) : Promise < void > {
617+ if ( ! this . portDetector . shared ) {
549618 this . lastRoutedTimestamp = Date . now ( ) ;
550619 super . goBack ( ) ;
620+ return ;
621+ }
622+ if ( this . portDetector . isClient ) {
623+ return delegate ( this as ReactantRouter , 'goBack' , [ ] ) ;
624+ }
625+ if ( this . cachedHistory . length > 1 ) {
626+ const currentRouter = this . cachedHistory . shift ( ) ; // Pop the current route
627+ this . forwardHistory . unshift ( currentRouter ! ) ; // Push to forward stack
628+ this . forwardHistory . length = this . maxHistoryLength ; // Limit the length of the forward stack
629+ const previousRouter = this . cachedHistory [ 0 ] ; // Get the previous route
630+ if ( previousRouter ) {
631+ const router : RouterState = await fork (
632+ this as any ,
633+ '_makeRoutingOnClient' ,
634+ [
635+ {
636+ args : [
637+ previousRouter . location . pathname ,
638+ previousRouter . location . state ,
639+ ] ,
640+ action : 'replace' ,
641+ name : this . portDetector . name ,
642+ } ,
643+ ]
644+ ) ;
645+ this . dispatchChanged ( router ) ;
646+ } else {
647+ console . warn ( 'No forward route available.' ) ;
648+ }
649+ } else {
650+ console . warn ( 'No previous route available.' ) ;
551651 }
552652 }
553653
554- async goForward ( ) {
555- if ( this . portDetector . isServerWorker ) {
556- const router : RouterState = await fork (
557- this as any ,
558- '_makeRoutingOnClient' ,
559- [
560- {
561- args : [ ] ,
562- action : 'goForward' ,
563- name : this . portDetector . name ,
564- } ,
565- ]
566- ) ;
567- this . dispatchChanged ( router ) ;
568- } else {
654+ async goForward ( ) : Promise < void > {
655+ if ( ! this . portDetector . shared ) {
569656 this . lastRoutedTimestamp = Date . now ( ) ;
570657 super . goForward ( ) ;
658+ return ;
659+ }
660+ if ( this . portDetector . isClient ) {
661+ return delegate ( this as ReactantRouter , 'goForward' , [ ] ) ;
662+ }
663+ if ( this . forwardHistory . length > 0 ) {
664+ const nextRouter = this . forwardHistory . shift ( ) ; // Pop from forward stack
665+ if ( nextRouter ) {
666+ const router : RouterState = await fork (
667+ this as any ,
668+ '_makeRoutingOnClient' ,
669+ [
670+ {
671+ args : [ nextRouter . location . pathname , nextRouter . location . state ] ,
672+ action : 'replace' ,
673+ name : this . portDetector . name ,
674+ } ,
675+ ]
676+ ) ;
677+ this . dispatchChanged ( router ) ;
678+ }
679+ } else {
680+ console . warn ( 'No forward route available.' ) ;
571681 }
572682 }
573683}
0 commit comments