@@ -32,6 +32,7 @@ import {
3232} from './core'
3333import {
3434 dispatchNativeEvent ,
35+ dispatchPopStateEventToMicroApp ,
3536} from './event'
3637import {
3738 updateMicroLocation ,
@@ -44,15 +45,68 @@ import {
4445 isIframeSandbox ,
4546} from '../../create_app'
4647
48+ interface HistoryStack {
49+ [ appName : string ] : {
50+ stack : Array < { path : string , state : any } > ,
51+ currentIndex : number
52+ }
53+ }
54+ const pureHistoryStack : HistoryStack = { }
55+
56+ function initPureHistory ( appName : string ) : void {
57+ if ( ! pureHistoryStack [ appName ] ) {
58+ pureHistoryStack [ appName ] = {
59+ stack : [ ] ,
60+ currentIndex : - 1
61+ }
62+ }
63+ }
64+
65+ function addToPureHistory ( appName : string , path : string , state : any ) : void {
66+ if ( ! pureHistoryStack [ appName ] ) {
67+ pureHistoryStack [ appName ] = {
68+ stack : [ ] ,
69+ currentIndex : - 1
70+ }
71+ }
72+ const history = pureHistoryStack [ appName ]
73+ // 处理路径,移除基础路径
74+ const basePath = `/${ appName } /`
75+ const cleanPath = path . startsWith ( basePath ) ? path . slice ( basePath . length - 1 ) : path
76+
77+ // 检查是否与当前路径相同
78+ const currentEntry = history . stack [ history . currentIndex ]
79+ if ( currentEntry && currentEntry . path === cleanPath ) {
80+ // 如果路径相同,只更新状态
81+ currentEntry . state = state
82+ return
83+ }
84+
85+ if ( history . currentIndex < history . stack . length - 1 ) {
86+ history . stack = history . stack . slice ( 0 , history . currentIndex + 1 )
87+ }
88+
89+ history . stack . push ( {
90+ path : cleanPath ,
91+ state
92+ } )
93+ history . currentIndex ++
94+ }
95+
96+ export function clearPureHistory ( appName : string ) : void {
97+ delete pureHistoryStack [ appName ]
98+ }
99+
47100/**
48101 * create proxyHistory for microApp
49102 * MDN https://developer.mozilla.org/en-US/docs/Web/API/History
50103 * @param appName app name
51104 * @param microLocation microApp location(with: proxyLocation iframe: iframeWindow.location)
52105 */
53- export function createMicroHistory ( appName : string , microLocation : MicroLocation ) : MicroHistory {
106+ export function createMicroHistory ( appName : string , microLocation : MicroLocation ) : MicroHistory {
54107 const rawHistory = globalEnv . rawWindow . history
55- function getMicroHistoryMethod ( methodName : string ) : CallableFunction {
108+ initPureHistory ( appName )
109+ function getMicroHistoryMethod ( methodName : string ) : CallableFunction {
56110 return function ( ...rests : any [ ] ) : void {
57111 // TODO: 测试iframe的URL兼容isURL的情况
58112 rests [ 2 ] = isUndefined ( rests [ 2 ] ) || isNull ( rests [ 2 ] ) || ( '' + rests [ 2 ] === '' ) ? microLocation . href : '' + rests [ 2 ]
@@ -67,6 +121,8 @@ export function createMicroHistory (appName: string, microLocation: MicroLocatio
67121 setMicroState ( appName , rests [ 0 ] , targetLocation ) ,
68122 rests [ 1 ] ,
69123 )
124+ } else {
125+ addToPureHistory ( appName , targetFullPath , rests [ 0 ] )
70126 }
71127 if ( targetFullPath !== microLocation . fullPath ) {
72128 updateMicroLocation ( appName , targetFullPath , microLocation )
@@ -82,22 +138,52 @@ export function createMicroHistory (appName: string, microLocation: MicroLocatio
82138
83139 if ( isIframeSandbox ( appName ) ) {
84140 return assign ( {
85- go ( delta ?: number ) {
86- return rawHistory . go ( delta )
87- }
141+ go ( delta ?: number ) {
142+ if ( ! isRouterModePure ( appName ) ) {
143+ return rawHistory . go ( delta )
144+ }
145+ const history = pureHistoryStack [ appName ]
146+ const targetIndex = history . currentIndex + ( delta || 0 )
147+ if ( targetIndex === history . currentIndex ) {
148+ return
149+ }
150+ const target = history . stack [ targetIndex ]
151+ history . currentIndex = targetIndex
152+ updateMicroLocation (
153+ appName ,
154+ target . path ,
155+ microLocation ,
156+ 'pure-history'
157+ )
158+ const app = appInstanceMap . get ( appName )
159+ if ( app ?. sandBox ) {
160+ // 最后触发事件
161+ dispatchPopStateEventToMicroApp (
162+ appName ,
163+ app . sandBox . proxyWindow ,
164+ app . sandBox . microAppWindow
165+ )
166+ }
167+ } ,
168+ back ( ) {
169+ this . go ( - 1 )
170+ } ,
171+ forward ( ) {
172+ this . go ( 1 )
173+ } ,
88174 } , originalHistory ) as MicroHistory
89175 }
90176
91177 return new Proxy ( rawHistory , {
92- get ( target : History , key : PropertyKey ) : HistoryProxyValue {
178+ get ( target : History , key : PropertyKey ) : HistoryProxyValue {
93179 if ( key === 'pushState' || key === 'replaceState' ) {
94180 return originalHistory [ key ]
95181 } else if ( key === 'state' ) {
96182 return getMicroState ( appName )
97183 }
98184 return bindFunctionToRawTarget < History , HistoryProxyValue > ( Reflect . get ( target , key ) , target , 'HISTORY' )
99185 } ,
100- set ( target : History , key : PropertyKey , value : unknown ) : boolean {
186+ set ( target : History , key : PropertyKey , value : unknown ) : boolean {
101187 if ( key === 'pushState' || key === 'replaceState' ) {
102188 originalHistory [ key ] = value as CallableFunction
103189 } else {
@@ -121,7 +207,7 @@ export function createMicroHistory (appName: string, microLocation: MicroLocatio
121207 * @param state history.state, default is null
122208 * @param title history.title, default is ''
123209 */
124- export function nativeHistoryNavigate (
210+ export function nativeHistoryNavigate (
125211 appName : string ,
126212 methodName : string ,
127213 fullPath : string ,
@@ -150,7 +236,7 @@ export function nativeHistoryNavigate (
150236 * @param state history.state, not required
151237 * @param title history.title, not required
152238 */
153- export function navigateWithNativeEvent (
239+ export function navigateWithNativeEvent (
154240 appName : string ,
155241 methodName : string ,
156242 result : HandleMicroPathResult ,
@@ -179,7 +265,7 @@ export function navigateWithNativeEvent (
179265 * @param result result of add/remove microApp path on browser url
180266 * @param state history.state
181267 */
182- export function attachRouteToBrowserURL (
268+ export function attachRouteToBrowserURL (
183269 appName : string ,
184270 result : HandleMicroPathResult ,
185271 state : MicroState ,
@@ -192,7 +278,7 @@ export function attachRouteToBrowserURL (
192278 * Fix bug of missing __MICRO_APP_STATE__ when base app is next.js or angular
193279 * @param method history.pushState/replaceState
194280 */
195- function reWriteHistoryMethod ( method : History [ 'pushState' | 'replaceState' ] ) : CallableFunction {
281+ function reWriteHistoryMethod ( method : History [ 'pushState' | 'replaceState' ] ) : CallableFunction {
196282 const rawWindow = globalEnv . rawWindow
197283 return function ( ...rests : [ data : any , unused : string , url ?: string ] ) : void {
198284 if (
@@ -213,9 +299,9 @@ function reWriteHistoryMethod (method: History['pushState' | 'replaceState']): C
213299 /**
214300 * Attach child router info to browser url when base app navigate with pushState/replaceState
215301 * NOTE:
216- * 1. Exec after apply pushState/replaceState
217- * 2. Unable to catch when base app navigate with location
218- * 3. When in nest app, rawPushState/rawReplaceState has been modified by parent
302+ * 1. Exec after apply pushState/replaceState
303+ * 2. Unable to catch when base app navigate with location
304+ * 3. When in nest app, rawPushState/rawReplaceState has been modified by parent
219305 */
220306 getActiveApps ( {
221307 excludeHiddenApp : true ,
@@ -262,7 +348,7 @@ function reWriteHistoryMethod (method: History['pushState' | 'replaceState']): C
262348 * used to fix the problem that the __MICRO_APP_STATE__ maybe missing when mainApp navigate to same path
263349 * e.g: when nextjs, angular receive popstate event, they will use history.replaceState to update browser url with a new state object
264350 */
265- export function patchHistory ( ) : void {
351+ export function patchHistory ( ) : void {
266352 const rawWindow = globalEnv . rawWindow
267353 rawWindow . history . pushState = reWriteHistoryMethod (
268354 globalEnv . rawPushState ,
@@ -272,7 +358,7 @@ export function patchHistory (): void {
272358 )
273359}
274360
275- export function releasePatchHistory ( ) : void {
361+ export function releasePatchHistory ( ) : void {
276362 const rawWindow = globalEnv . rawWindow
277363 rawWindow . history . pushState = globalEnv . rawPushState
278364 rawWindow . history . replaceState = globalEnv . rawReplaceState
0 commit comments