@mpxjs/core 2.10.4-beta.2 → 2.10.4-beta.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.10.4-beta.2",
3
+ "version": "2.10.4-beta.20",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "peerDependencies": {
27
27
  "@d11/react-native-fast-image": "*",
28
- "@mpxjs/api-proxy": "^2.9.0",
28
+ "@mpxjs/api-proxy": "^2.10.4-beta.0",
29
29
  "@mpxjs/store": "^2.9.0",
30
30
  "@react-navigation/native": "*",
31
31
  "@react-navigation/native-stack": "*",
@@ -2,12 +2,14 @@ import { isObject, isArray, dash2hump, cached, isEmptyObject } from '@mpxjs/util
2
2
  import { Dimensions, StyleSheet } from 'react-native'
3
3
 
4
4
  let { width, height } = Dimensions.get('screen')
5
+ // TODO 临时适配折叠屏场景适配
6
+ const isLargeFoldableLike = (__mpx_mode__ === 'android') && (height / width < 1.5) && (width > 600)
7
+ if (isLargeFoldableLike) width = width / 2
5
8
 
6
9
  Dimensions.addEventListener('change', ({ screen }) => {
7
10
  width = screen.width
8
11
  height = screen.height
9
12
  })
10
-
11
13
  function rpx (value) {
12
14
  // rn 单位 dp = 1(css)px = 1 物理像素 * pixelRatio(像素比)
13
15
  // px = rpx * (750 / 屏幕宽度)
@@ -4,10 +4,12 @@ import { makeMap, spreadProp, getFocusedNavigation, hasOwn } from '@mpxjs/utils'
4
4
  import { mergeLifecycle } from '../convertor/mergeLifecycle'
5
5
  import { LIFECYCLE } from '../platform/patch/lifecycle/index'
6
6
  import Mpx from '../index'
7
+ import { reactive } from '../observer/reactive'
8
+ import { watch } from '../observer/watch'
7
9
  import { createElement, memo, useRef, useEffect } from 'react'
8
10
  import * as ReactNative from 'react-native'
9
11
  import { initAppProvides } from './export/inject'
10
- import { NavigationContainer, createStackNavigator, SafeAreaProvider } from './env/navigationHelper'
12
+ import { NavigationContainer, createNativeStackNavigator, SafeAreaProvider } from './env/navigationHelper'
11
13
 
12
14
  const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
13
15
 
@@ -52,25 +54,25 @@ export default function createApp (options) {
52
54
 
53
55
  const pages = currentInject.getPages() || {}
54
56
  const firstPage = currentInject.firstPage
55
- const Stack = createStackNavigator()
57
+ const Stack = createNativeStackNavigator()
56
58
  const getPageScreens = (initialRouteName, initialParams) => {
57
59
  return Object.entries(pages).map(([key, item]) => {
58
- const options = {
59
- // __mpxPageStatusMap 为编译注入的全局变量
60
- headerShown: !(Object.assign({}, global.__mpxPageConfig, global.__mpxPageConfigsMap[key]).navigationStyle === 'custom')
61
- }
60
+ // const options = {
61
+ // // __mpxPageStatusMap 为编译注入的全局变量
62
+ // headerShown: !(Object.assign({}, global.__mpxPageConfig, global.__mpxPageConfigsMap[key]).navigationStyle === 'custom')
63
+ // }
62
64
  if (key === initialRouteName) {
63
65
  return createElement(Stack.Screen, {
64
66
  name: key,
65
67
  component: item,
66
- initialParams,
67
- options
68
+ initialParams
69
+ // options
68
70
  })
69
71
  }
70
72
  return createElement(Stack.Screen, {
71
73
  name: key,
72
- component: item,
73
- options
74
+ component: item
75
+ // options
74
76
  })
75
77
  })
76
78
  }
@@ -90,6 +92,57 @@ export default function createApp (options) {
90
92
  global.__navigationHelper.lastFailCallback = null
91
93
  }
92
94
  }
95
+ const appState = reactive({ state: '' })
96
+ // TODO hideReason 暂未完全模拟
97
+ // 0用户退出小程序
98
+ // 1进入其他小程序
99
+ // 2打开原生功能页
100
+ // 3其他
101
+ watch(() => appState.state, (value) => {
102
+ if (value === 'show') {
103
+ let options = appState.showOptions
104
+ delete appState.showOptions
105
+ if (!options) {
106
+ const navigation = getFocusedNavigation()
107
+ if (navigation) {
108
+ const state = navigation.getState()
109
+ const current = state.routes[state.index]
110
+ options = {
111
+ path: current.name,
112
+ query: current.params,
113
+ scene: 0,
114
+ shareTicket: '',
115
+ referrerInfo: {}
116
+ }
117
+ }
118
+ }
119
+ global.__mpxAppCbs.show.forEach((cb) => {
120
+ cb(options || {})
121
+ })
122
+ } else if (value === 'hide') {
123
+ global.__mpxAppCbs.hide.forEach((cb) => {
124
+ cb({
125
+ reason: appState.hideReason ?? 3
126
+ })
127
+ delete appState.hideReason
128
+ })
129
+ }
130
+ }, { sync: true })
131
+ const onAppStateChange = (currentState) => {
132
+ const navigation = getFocusedNavigation()
133
+ if (currentState === 'active') {
134
+ appState.state = 'show'
135
+ if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
136
+ global.__mpxPageStatusMap[navigation.pageId] = 'show'
137
+ }
138
+ } else if (currentState === 'inactive' || currentState === 'background') {
139
+ appState.hideReason = 3
140
+ appState.state = 'hide'
141
+ if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
142
+ global.__mpxPageStatusMap[navigation.pageId] = 'hide'
143
+ }
144
+ }
145
+ }
93
146
 
94
147
  global.__mpxAppLaunched = false
95
148
  global.__mpxOptionsMap[currentInject.moduleId] = memo((props) => {
@@ -127,47 +180,18 @@ export default function createApp (options) {
127
180
  global.__mpxLaunchOptions = options
128
181
  defaultOptions.onLaunch && defaultOptions.onLaunch.call(appInstance, options)
129
182
  }
130
- global.__mpxAppCbs.show.forEach((cb) => {
131
- cb(options)
132
- })
183
+ appState.showOptions = options
184
+ appState.state = 'show'
133
185
  global.__mpxAppLaunched = true
134
186
  global.__mpxAppHotLaunched = true
135
187
  }
136
188
  }
137
189
 
138
190
  useEffect(() => {
139
- const changeSubscription = ReactNative.AppState.addEventListener('change', (currentState) => {
140
- if (currentState === 'active') {
141
- let options = global.__mpxEnterOptions
142
- const navigation = getFocusedNavigation()
143
- if (navigation) {
144
- const state = navigation.getState()
145
- const current = state.routes[state.index]
146
- options = {
147
- path: current.name,
148
- query: current.params,
149
- scene: 0,
150
- shareTicket: '',
151
- referrerInfo: {}
152
- }
153
- }
154
- global.__mpxAppCbs.show.forEach((cb) => {
155
- cb(options)
156
- })
157
- if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
158
- global.__mpxPageStatusMap[navigation.pageId] = 'show'
159
- }
160
- } else if (currentState === 'inactive' || currentState === 'background') {
161
- global.__mpxAppCbs.hide.forEach((cb) => {
162
- cb({
163
- reason: 3
164
- })
165
- })
166
- const navigation = getFocusedNavigation()
167
- if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
168
- global.__mpxPageStatusMap[navigation.pageId] = 'hide'
169
- }
170
- }
191
+ const changeSubscription = ReactNative.AppState.addEventListener('change', (state) => {
192
+ // 外层可能会异常设置此配置,因此加载监听函数内部
193
+ if (Mpx.config.rnConfig.disableAppStateListener) return
194
+ onAppStateChange(state)
171
195
  })
172
196
 
173
197
  let count = 0
@@ -182,12 +206,8 @@ export default function createApp (options) {
182
206
  }
183
207
  })
184
208
  return () => {
185
- // todo 跳到原生页面或者其他rn bundle可以考虑使用reason 1/2进行模拟抹平
186
- global.__mpxAppCbs.hide.forEach((cb) => {
187
- cb({
188
- reason: 0
189
- })
190
- })
209
+ appState.hideReason = 0
210
+ appState.state = 'hide'
191
211
  changeSubscription && changeSubscription.remove()
192
212
  resizeSubScription && resizeSubScription.remove()
193
213
  }
@@ -195,32 +215,10 @@ export default function createApp (options) {
195
215
 
196
216
  const { initialRouteName, initialParams } = initialRouteRef.current
197
217
  const navScreenOpts = {
198
- // 7.x替换headerBackTitleVisible
199
- // headerBackButtonDisplayMode: 'minimal',
200
- headerBackTitleVisible: false,
201
- headerShadowVisible: false
202
- // 整体切换native-stack时进行修改如下
203
- // statusBarTranslucent: true,
204
- // statusBarBackgroundColor: 'transparent'
205
- }
206
- if (__mpx_mode__ === 'ios') {
207
- // ios使用native-stack
208
- const headerBackImageSource = Mpx.config.rnConfig.headerBackImageSource || null
209
- if (headerBackImageSource) {
210
- navScreenOpts.headerBackImageSource = headerBackImageSource
211
- }
212
- } else {
213
- // 安卓上会出现导航条闪现的问题所以默认加headerShown false(stack版本, native-stack版本可以干掉)
214
- // iOS加上默认headerShown false的话会因为iOS根高度是screenHeight - useHeaderHeight()会导致出现渲染两次情况,因此iOS不加此默认值
215
- navScreenOpts.headerShown = false
216
- // 安卓和鸿蒙先用stack
217
- const headerBackImageProps = Mpx.config.rnConfig.headerBackImageProps || null
218
- if (headerBackImageProps) {
219
- navScreenOpts.headerBackImage = () => {
220
- return createElement(ReactNative.Image, headerBackImageProps)
221
- }
222
- }
223
- }
218
+ headerShown: false,
219
+ statusBarTranslucent: true,
220
+ statusBarBackgroundColor: 'transparent'
221
+ }
224
222
 
225
223
  return createElement(SafeAreaProvider,
226
224
  null,
@@ -256,4 +254,12 @@ export default function createApp (options) {
256
254
  global.__mpxPageStatusMap[navigation.pageId] = status
257
255
  }
258
256
  }
257
+
258
+ // 用于外层业务用来设置App的展示情况
259
+ global.setAppShow = function () {
260
+ onAppStateChange('active')
261
+ }
262
+ global.setAppHide = function () {
263
+ onAppStateChange('inactive')
264
+ }
259
265
  }
@@ -0,0 +1,130 @@
1
+ import { createElement, useState, useMemo } from 'react'
2
+ import { useSafeAreaInsets } from 'react-native-safe-area-context'
3
+ import * as ReactNative from 'react-native'
4
+ import Mpx from '../../index'
5
+
6
+ function convertToHex (color) {
7
+ try {
8
+ const intColor = ReactNative.processColor(color)
9
+ if (intColor === null || intColor === undefined) {
10
+ return null
11
+ }
12
+ // 将32位整数颜色值转换为RGBA
13
+ const r = (intColor >> 16) & 255
14
+ const g = (intColor >> 8) & 255
15
+ const b = intColor & 255
16
+ // 转换为十六进制
17
+ const hexR = r.toString(16).padStart(2, '0')
18
+ const hexG = g.toString(16).padStart(2, '0')
19
+ const hexB = b.toString(16).padStart(2, '0')
20
+ return `#${hexR}${hexG}${hexB}`
21
+ } catch (error) {
22
+ return null
23
+ }
24
+ }
25
+
26
+ const titleHeight = 44
27
+ export function useInnerHeaderHeight (pageconfig) {
28
+ if (pageconfig.navigationStyle === 'custom') {
29
+ return 0
30
+ } else {
31
+ const safeAreaTop = useSafeAreaInsets()?.top || 0
32
+ const headerHeight = safeAreaTop + titleHeight
33
+ return headerHeight
34
+ }
35
+ }
36
+
37
+ const styles = ReactNative.StyleSheet.create({
38
+ header: {
39
+ elevation: 3
40
+ },
41
+ headerContent: {
42
+ flexDirection: 'row',
43
+ alignItems: 'center',
44
+ justifyContent: 'center'
45
+ },
46
+ backButton: {
47
+ position: 'absolute',
48
+ height: '100%',
49
+ width: 40,
50
+ left: 0,
51
+ top: 0,
52
+ alignItems: 'center',
53
+ justifyContent: 'center'
54
+ },
55
+ backButtonImage: {
56
+ width: 22,
57
+ height: 22
58
+ },
59
+ title: {
60
+ fontSize: 17,
61
+ fontWeight: 600,
62
+ width: '60%',
63
+ textAlign: 'center'
64
+ }
65
+ })
66
+ const NavColor = {
67
+ White: '#ffffff',
68
+ Black: '#000000'
69
+ }
70
+ // navigationBarTextStyle只支持黑白'white'/'black
71
+ const validBarTextStyle = (textStyle) => {
72
+ const textStyleColor = convertToHex(textStyle)
73
+ if (textStyle && [NavColor.White, NavColor.Black].includes(textStyleColor)) {
74
+ return textStyleColor
75
+ } else {
76
+ return NavColor.White
77
+ }
78
+ }
79
+ export function innerNav ({ props, navigation }) {
80
+ const { pageConfig } = props
81
+ const [innerPageConfig, setPageConfig] = useState(pageConfig || {})
82
+ navigation.setPageConfig = (config) => {
83
+ const newConfig = Object.assign({}, innerPageConfig, config)
84
+ setPageConfig(newConfig)
85
+ }
86
+ const isCustom = innerPageConfig.navigationStyle === 'custom'
87
+ const navigationBarTextStyle = useMemo(() => validBarTextStyle(innerPageConfig.navigationBarTextStyle), [innerPageConfig.navigationBarTextStyle])
88
+ // 状态栏的颜色
89
+ const statusBarElement = createElement(ReactNative.StatusBar, {
90
+ translucent: true,
91
+ backgroundColor: 'transparent',
92
+ barStyle: (navigationBarTextStyle === NavColor.White) ? 'light-content' : 'dark-content' // 'default'/'light-content'/'dark-content'
93
+ })
94
+
95
+ if (isCustom) return statusBarElement
96
+ const safeAreaTop = useSafeAreaInsets()?.top || 0
97
+ // 假设是栈导航,获取栈的长度
98
+ const stackLength = navigation.getState()?.routes?.length
99
+ // 用于外部注册打开RN容器之前的栈长度
100
+ const beforeStackLength = Mpx.config?.rnConfig?.beforeStackLength || 0
101
+
102
+ // 回退按钮与图标
103
+ const backElement = stackLength + beforeStackLength > 1
104
+ ? createElement(ReactNative.TouchableOpacity, {
105
+ style: [styles.backButton],
106
+ onPress: () => { navigation.goBack() }
107
+ }, createElement(ReactNative.Image, {
108
+ source: { uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAABICAYAAACqT5alAAAA2UlEQVR4nO3bMQrCUBRE0Yla6AYEN2nnBrTL+izcitW3MRDkEUWSvPzJvfCqgMwhZbAppWhNbbIHzB1g9wATERFRVyvpkj1irlpJ5X326D7WHh1hbdFD2CLpLmmftm7kfsEe09aNHFiBrT+wAlt/YAW2/sAKbP2BFdj6Ayuwy+ufz6XPL893krZ//O6iu2n4LT8kndLWTRTo4EC7BDo40C6BDg60S6CDA+0S6OBAuwQ6uNWiD2nrJmoIfU7cNWkR2hbb1UfbY7uuWhGWiIg+a/iHuHmA3QPs3gu4JW9Gan+OJAAAAABJRU5ErkJggg==' },
109
+ // 回退按钮的颜色与设置的title文案颜色一致
110
+ style: [styles.backButtonImage, { tintColor: navigationBarTextStyle }]
111
+ }))
112
+ : null
113
+
114
+ return createElement(ReactNative.View, {
115
+ style: [styles.header, {
116
+ paddingTop: safeAreaTop,
117
+ backgroundColor: innerPageConfig.navigationBarBackgroundColor || '#000000'
118
+ }]
119
+ },
120
+ statusBarElement,
121
+ createElement(ReactNative.View, {
122
+ style: styles.headerContent,
123
+ height: titleHeight
124
+ }, backElement,
125
+ createElement(ReactNative.Text, {
126
+ style: [styles.title, { color: navigationBarTextStyle }],
127
+ numberOfLines: 1
128
+ }, innerPageConfig.navigationBarTitleText?.trim() || ''))
129
+ )
130
+ }
@@ -1,4 +1,4 @@
1
- import { createStackNavigator } from '@react-navigation/stack'
1
+ import { createNativeStackNavigator } from '@react-navigation/native-stack'
2
2
  import { NavigationContainer, StackActions } from '@react-navigation/native'
3
3
  import PortalHost from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal/portal-host'
4
4
  import { useHeaderHeight } from '@react-navigation/elements'
@@ -6,7 +6,7 @@ import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-cont
6
6
  import { GestureHandlerRootView } from 'react-native-gesture-handler'
7
7
 
8
8
  export {
9
- createStackNavigator,
9
+ createNativeStackNavigator,
10
10
  NavigationContainer,
11
11
  useHeaderHeight,
12
12
  StackActions,
@@ -1,4 +1,4 @@
1
- import { createNativeStackNavigator as createStackNavigator } from '@react-navigation/native-stack'
1
+ import { createNativeStackNavigator } from '@react-navigation/native-stack'
2
2
  import { NavigationContainer, StackActions } from '@react-navigation/native'
3
3
  import PortalHost from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal/portal-host'
4
4
  import { useHeaderHeight } from '@react-navigation/elements'
@@ -6,7 +6,7 @@ import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-cont
6
6
  import { GestureHandlerRootView } from 'react-native-gesture-handler'
7
7
 
8
8
  export {
9
- createStackNavigator,
9
+ createNativeStackNavigator,
10
10
  NavigationContainer,
11
11
  useHeaderHeight,
12
12
  StackActions,
@@ -1,4 +1,4 @@
1
- import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, createElement, memo, forwardRef, useImperativeHandle, useContext, Fragment, cloneElement, createContext } from 'react'
1
+ import { useEffect, useSyncExternalStore, useRef, useMemo, createElement, memo, forwardRef, useImperativeHandle, useContext, Fragment, cloneElement, createContext } from 'react'
2
2
  import * as ReactNative from 'react-native'
3
3
  import { ReactiveEffect } from '../../observer/effect'
4
4
  import { watch } from '../../observer/watch'
@@ -15,7 +15,8 @@ import {
15
15
  KeyboardAvoidContext,
16
16
  RouteContext
17
17
  } from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/context'
18
- import { PortalHost, useSafeAreaInsets, GestureHandlerRootView, useHeaderHeight } from '../env/navigationHelper'
18
+ import { PortalHost, useSafeAreaInsets, GestureHandlerRootView } from '../env/navigationHelper'
19
+ import { innerNav, useInnerHeaderHeight } from '../env/nav'
19
20
 
20
21
  const ProviderContext = createContext(null)
21
22
  function getSystemInfo () {
@@ -392,7 +393,7 @@ function usePageEffect (mpxProxy, pageId) {
392
393
  } else if (/^resize/.test(newVal)) {
393
394
  triggerResizeEvent(mpxProxy)
394
395
  }
395
- })
396
+ }, { sync: true })
396
397
  }
397
398
  }
398
399
  return () => {
@@ -445,11 +446,30 @@ const checkRelation = (options) => {
445
446
  hasAncestorRelation
446
447
  }
447
448
  }
449
+ function getLayoutData (headerHeight) {
450
+ const screenDimensions = ReactNative.Dimensions.get('screen')
451
+ const windowDimensions = ReactNative.Dimensions.get('window')
452
+ // 在横屏状态下 screen.height = window.height + bottomVirtualHeight
453
+ // 在正常状态 screen.height = window.height + bottomVirtualHeight + statusBarHeight
454
+ const isLandscape = screenDimensions.height < screenDimensions.width
455
+ const bottomVirtualHeight = isLandscape ? screenDimensions.height - windowDimensions.height : ((screenDimensions.height - windowDimensions.height - ReactNative.StatusBar.currentHeight) || 0)
456
+ return {
457
+ x: 0,
458
+ y: headerHeight,
459
+ left: 0,
460
+ top: headerHeight,
461
+ // 此处必须为windowDimensions.width,在横屏状态下windowDimensions.width才符合预期
462
+ width: windowDimensions.width,
463
+ height: screenDimensions.height - headerHeight - bottomVirtualHeight,
464
+ // ios为0 android为实际statusbar高度
465
+ statusBarHeight: ReactNative.StatusBar.currentHeight || 0,
466
+ bottomVirtualHeight: bottomVirtualHeight,
467
+ isLandscape: isLandscape
468
+ }
469
+ }
448
470
 
449
- // 临时用来存储安卓底部(iOS没有这个)的高度(虚拟按键等高度)根据第一次进入推算
450
- let bottomVirtualHeight = null
451
- export function PageWrapperHOC (WrappedComponent) {
452
- return function PageWrapperCom ({ navigation, route, pageConfig = {}, ...props }) {
471
+ export function PageWrapperHOC (WrappedComponent, pageConfig = {}) {
472
+ return function PageWrapperCom ({ navigation, route, ...props }) {
453
473
  const rootRef = useRef(null)
454
474
  const keyboardAvoidRef = useRef(null)
455
475
  const intersectionObservers = useRef({})
@@ -464,59 +484,15 @@ export function PageWrapperHOC (WrappedComponent) {
464
484
  error('Using pageWrapper requires passing navigation and route')
465
485
  return null
466
486
  }
467
- usePageStatus(navigation, currentPageId)
468
- useLayoutEffect(() => {
469
- navigation.setOptions({
470
- title: currentPageConfig.navigationBarTitleText?.trim() || '',
471
- headerStyle: {
472
- backgroundColor: currentPageConfig.navigationBarBackgroundColor || '#000000'
473
- },
474
- headerTintColor: currentPageConfig.navigationBarTextStyle || 'white'
475
- })
476
-
477
- // TODO 此部分内容在native-stack可删除,用setOptions设置
478
- if (__mpx_mode__ !== 'ios') {
479
- ReactNative.StatusBar.setBarStyle(currentPageConfig.barStyle || 'dark-content')
480
- ReactNative.StatusBar.setTranslucent(true) // 控制statusbar是否占位
481
- ReactNative.StatusBar.setBackgroundColor('transparent')
482
- }
483
- }, [])
484
-
485
- const headerHeight = useHeaderHeight()
487
+ const headerHeight = useInnerHeaderHeight(currentPageConfig)
488
+ navigation.layout = getLayoutData(headerHeight)
486
489
  const onLayout = () => {
487
- const screenDimensions = ReactNative.Dimensions.get('screen')
488
- if (__mpx_mode__ === 'ios') {
489
- navigation.layout = {
490
- x: 0,
491
- y: headerHeight,
492
- width: screenDimensions.width,
493
- height: screenDimensions.height - headerHeight
494
- }
495
- } else {
496
- if (bottomVirtualHeight === null) {
497
- rootRef.current?.measureInWindow((x, y, width, height) => {
498
- // 沉浸模式的计算方式
499
- bottomVirtualHeight = screenDimensions.height - height - headerHeight
500
- // 非沉浸模式(translucent=true)计算方式, 现在默认是全用沉浸模式,所以先不算这个
501
- // bottomVirtualHeight = windowDimensions.height - height - headerHeight
502
- navigation.layout = {
503
- x: 0,
504
- y: headerHeight,
505
- width: screenDimensions.width,
506
- height: height
507
- }
508
- })
509
- } else {
510
- navigation.layout = {
511
- x: 0,
512
- y: headerHeight, // 这个y值
513
- width: screenDimensions.width,
514
- // 后续页面的layout是通过第一次路由进入时候推算出来的底部区域来推算出来的
515
- height: screenDimensions.height - bottomVirtualHeight - headerHeight
516
- }
517
- }
518
- }
490
+ // 当用户处于横屏或者竖屏状态的时候,需要进行layout修正
491
+ navigation.layout = getLayoutData(headerHeight)
519
492
  }
493
+
494
+ usePageStatus(navigation, currentPageId)
495
+
520
496
  const withKeyboardAvoidingView = (element) => {
521
497
  return createElement(KeyboardAvoidContext.Provider,
522
498
  {
@@ -535,26 +511,26 @@ export function PageWrapperHOC (WrappedComponent) {
535
511
  )
536
512
  )
537
513
  }
538
-
514
+ // android存在第一次打开insets都返回为0情况,后续会触发第二次渲染后正确
539
515
  navigation.insets = useSafeAreaInsets()
540
-
541
516
  return createElement(GestureHandlerRootView,
542
517
  {
543
- // https://github.com/software-mansion/react-native-reanimated/issues/6639 因存在此问题,iOS在页面上进行定宽来暂时规避
544
- style: __mpx_mode__ === 'ios' && currentPageConfig?.navigationStyle !== 'custom'
545
- ? {
546
- height: ReactNative.Dimensions.get('screen').height - useHeaderHeight()
547
- }
548
- : {
549
- flex: 1
550
- }
518
+ style: {
519
+ flex: 1
520
+ }
551
521
  },
522
+ createElement(innerNav, {
523
+ props: { pageConfig: currentPageConfig },
524
+ navigation
525
+ }),
552
526
  withKeyboardAvoidingView(
553
527
  createElement(ReactNative.View,
554
528
  {
555
529
  style: {
556
530
  flex: 1,
557
- backgroundColor: currentPageConfig?.backgroundColor || '#fff'
531
+ backgroundColor: currentPageConfig?.backgroundColor || '#fff',
532
+ // 解决页面内有元素定位relative left为负值的时候,回退的时候还能看到对应元素问题
533
+ overflow: 'hidden'
558
534
  },
559
535
  ref: rootRef,
560
536
  onLayout
@@ -582,7 +558,6 @@ export function PageWrapperHOC (WrappedComponent) {
582
558
  ))
583
559
  }
584
560
  }
585
-
586
561
  export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
587
562
  rawOptions = mergeOptions(rawOptions, type, false)
588
563
  const components = Object.assign({}, rawOptions.components, currentInject.getComponents())
@@ -656,8 +631,13 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
656
631
  return () => {
657
632
  proxy.unmounted()
658
633
  proxy.target.__resetInstance()
634
+ // 热更新下会销毁旧页面并创建新页面组件,且旧页面组件销毁时机晚于新页面组件创建,此时__mpxPagesMap中存储的为新页面组件,不应该删除
635
+ // 所以需要判断路由表中存储的页面实例是否为当前页面实例
659
636
  if (type === 'page') {
660
- delete global.__mpxPagesMap[props.route.key]
637
+ const routeKey = props.route.key
638
+ if (global.__mpxPagesMap[routeKey] && global.__mpxPagesMap[routeKey][0] === instance) {
639
+ delete global.__mpxPagesMap[routeKey]
640
+ }
661
641
  }
662
642
  }
663
643
  }, [])
@@ -718,11 +698,7 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
718
698
  }
719
699
 
720
700
  if (type === 'page') {
721
- return (props) =>
722
- createElement(PageWrapperHOC(defaultOptions), {
723
- pageConfig: currentInject.pageConfig,
724
- ...props
725
- })
701
+ return PageWrapperHOC(defaultOptions, currentInject.pageConfig)
726
702
  }
727
703
  return defaultOptions
728
704
  }