Skip to content

Commit 3a7ddc7

Browse files
committed
fix: pure模式下router.go和router.back 和router.forward 没效果 jd-opensource#1534
1 parent fa7c7db commit 3a7ddc7

File tree

3 files changed

+105
-18
lines changed

3 files changed

+105
-18
lines changed

src/create_app.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { extractSourceDom } from './source/index'
1212
import { execScripts } from './source/scripts'
1313
import WithSandBox from './sandbox/with'
1414
import IframeSandbox from './sandbox/iframe'
15-
import { router, isRouterModeSearch } from './sandbox/router'
15+
import { router, isRouterModeSearch, clearPureHistory } from './sandbox/router'
1616
import {
1717
appStates,
1818
lifeCycles,
@@ -566,7 +566,7 @@ export default class CreateApp implements AppInterface {
566566
this.name,
567567
lifeCycles.UNMOUNT,
568568
)
569-
569+
clearPureHistory(this.name)
570570
this.clearOptions(destroy)
571571

572572
unmountcb?.()

src/sandbox/router/history.ts

+102-16
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
} from './core'
3333
import {
3434
dispatchNativeEvent,
35+
dispatchPopStateEventToMicroApp,
3536
} from './event'
3637
import {
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

src/sandbox/router/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export {
4242
export {
4343
patchHistory,
4444
releasePatchHistory,
45+
clearPureHistory
4546
} from './history'
4647

4748
/**

0 commit comments

Comments
 (0)