Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .agents/skills/mpx2rn/references/rn-script-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,7 @@ Mpx.config.rnConfig = {
| `openTypeHandler.onShareAppMessage` | 对应模板中 `open-type="share"`:框架会先取当前页 `onShareAppMessage` 的返回(含与默认 `title` / `path` 的合并及可选 `promise` 异步结果),再调用本回调,入参为 `{ title, path, imageUrl? }`,由宿主调起系统分享等能力。 |
| `openTypeHandler.onUserInfo` | 对应模板中 `open-type="getUserInfo"`:由宿主实现获取用户信息的逻辑,结果需满足按钮侧对 `bindgetuserinfo` 的约定(以 `@mpxjs/webpack-plugin` 中 `mpx-button` 运行时为准)。 |
| `getBottomVirtualHeight` | Android 底部虚拟区域高度修正。 |
| `setSwipeBackEnabled` | `(enabled) => void`,DRN 等混合容器用于设置宿主页面侧滑返回状态;`page-container` 展示和关闭时会分别传入 `false` 和 `true`。 |
| `loadChunkAsync` | 异步分包加载实现。 |
| `downloadChunkAsync` | 分包下载实现,用于实现 preloadRule。 |
| `supportSubpackage` | 是否启用分包相关异步加载能力,与页面 `json` 中 `async` 等配合。 |
Expand Down
10 changes: 10 additions & 0 deletions .agents/skills/mpx2rn/references/rn-template-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,16 @@ movable-view 的可移动区域。
- wait-for 为 RN 环境特有属性,具体含义可参考[react-native-gesture-handler](https://docs.swmansion.com/react-native-gesture-handler/docs/fundamentals/gesture-composition/#requireexternalgesturetofail)
- RN 环境 movable 相关组件暂不支持缩放能力

### page-container

页面容器,可在页面内创建覆盖当前页面的弹层或抽屉。

RN 支持 `show`、`duration`、`z-index`、`overlay`、`position`、`round`、`close-on-slide-down`、`overlay-style`、`custom-style` 以及进入、离开、遮罩点击事件。

`bindclose` 是 RN 环境特有的可选事件。点击遮罩、系统返回或滑动关闭时,可通过该事件将父组件中受控的 `show` 同步为 `false`;未绑定时不会抛出异常,但业务状态也不会自动更新。

容器显示期间会临时禁用 iOS 页面侧滑返回,关闭后恢复页面原有的 React Navigation 配置。DRN 等混合容器可通过 `Mpx.config.rnConfig.setSwipeBackEnabled` 对接宿主手势控制。

### image

图片组件
Expand Down
22 changes: 22 additions & 0 deletions docs-vitepress/guide/rn/application-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,28 @@ Mpx 框架默认会使用 `ReactNative.AppState.addEventListener('change', callb
在需要将 RN 应用嵌入到现有的 NA 应用中时,可能会出现AppState触发时机异常的情况(例如从 RN 页面跳转到 NA 页面时),此时可以将 disableAppStateListener 设置为 true 来禁用框架内部对 AppState 的监听。但需要在合适的时机手动调用 setAppShow() 与 setAppHide() 方法来进行驱动以确保对应的钩子能正常触发。


### page-container {#page-container}

#### mpx.config.rnConfig.setSwipeBackEnabled

```ts
(enabled: boolean) => void
```

设置是否启用 iOS 页面侧滑返回,主要用于 DRN(混合容器)等场景。

当页面内使用 `page-container` 组件时,框架会在容器显示时自动调用此方法禁用手势返回,以防止用户左滑时触发页面返回而非关闭容器;容器关闭或组件销毁时会再次调用以恢复。

在纯 RN 环境下,框架通过 React Navigation 的 `gestureEnabled` 选项自动处理手势返回的禁用与恢复,无需配置此项。

```javascript
// 示例(DRN 场景)
mpx.config.rnConfig.setSwipeBackEnabled = (enabled) => {
// 调用 NA 提供的方法控制手势返回
NativeModules.NavigationModule.setSwipeBackEnabled(enabled)
}
```

### 自定义设置底部虚拟按键区高度 {#custom-bottom-bar-height}

#### mpx.config.rnConfig.getBottomVirtualHeight
Expand Down
76 changes: 75 additions & 1 deletion docs-vitepress/guide/rn/component.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
### 目录概览 {#directory-overview}

- #### 基础组件
**容器组件**:[view](#view) · [scroll-view](#scroll-view) · [swiper](#swiper) · [swiper-item](#swiper-item) · [movable-area](#movable-area) · [movable-view](#movable-view) · [root-portal](#root-portal) · [sticky-section](#sticky-section) · [sticky-header](#sticky-header) · [cover-view](#cover-view)
**容器组件**:[view](#view) · [scroll-view](#scroll-view) · [swiper](#swiper) · [swiper-item](#swiper-item) · [movable-area](#movable-area) · [movable-view](#movable-view) · [page-container](#page-container) · [root-portal](#root-portal) · [sticky-section](#sticky-section) · [sticky-header](#sticky-header) · [cover-view](#cover-view)

**媒体组件**:[image](#image) · [video](#video) · [canvas](#canvas)

Expand Down Expand Up @@ -774,6 +774,80 @@ API
视图容器。
功能同 [image 组件](#image)

### page-container

页面容器。可在页面内创建一个覆盖于页面之上的子页面容器,常用于实现弹出层、抽屉等交互效果。

属性

| 属性名 | 类型 | 默认值 | 说明 |
| ----- | ---- | ----- | ---- |
| show | boolean | `false` | 是否显示容器 |
| duration | number | `300` | 动画时长,单位毫秒 |
| z-index | number | `100` | z-index 层级 |
| overlay | boolean | `true` | 是否显示遮罩层 |
| position | string | `bottom` | 弹出位置,可选值为 `top`、`bottom`、`right`、`center` |
| round | boolean | `false` | 是否显示圆角,仅 `position` 为 `top` 或 `bottom` 时生效 |
| close-on-slide-down | boolean | `false` | 是否在下滑时关闭容器,仅 `position` 为 `bottom` 时生效 |
| overlay-style | string | | 自定义遮罩层样式 |
| custom-style | string | | 自定义容器样式 |

事件

| 事件名 | 说明 |
| ----- | ---- |
| bindbeforeenter | 进入前触发 |
| bindenter | 进入时触发 |
| bindafterenter | 进入后触发 |
| bindbeforeleave | 离开前触发 |
| bindleave | 离开时触发 |
| bindafterleave | 离开后触发 |
| bindclickoverlay | 点击遮罩层时触发 |
| bindclose | RN 环境特有可选事件,容器关闭时触发,可用于同步 `show` 状态到父组件,`event.detail = { value: false }` |

> [!tip] 注意
>
> - 在 RN 环境下,当容器显示时会禁用页面手势返回(iOS 左滑返回),并拦截系统返回事件。若需要响应点击遮罩、系统返回或滑动关闭并同步受控的 `show` 状态,应监听 `bindclose` 并将 `show` 设置为 `false`。
> - 为什么需要 `bindclose`?特殊场景:在微信小程序中 `show={{a}}` 在关闭`page-container`后,a会变为false(类似wx:model的效果),所以需要bindclose来模拟此效果

示例

```html
<template>
<view>
<button bindtap="openContainer">打开容器</button>
<page-container
show="{{show}}"
position="bottom"
round="{{true}}"
bindclose="onClose"
>
<view style="height: 300px; padding: 20px;">
<text>容器内容</text>
</view>
</page-container>
</view>
</template>

<script lang="ts" setup>
import { createPage } from '@mpxjs/core'

createPage({
data: {
show: false
},
methods: {
openContainer() {
this.show = true
},
onClose() {
this.show = false
}
}
})
</script>
```


## 自定义组件 {#custom-component}

Expand Down
13 changes: 13 additions & 0 deletions packages/core/@types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,19 @@ export interface RnConfig {
* @returns Promise<boolean> Resolves 为 true 表示权限获取成功,false 表示失败。
*/
cameraPermission?: () => Promise<boolean>

/**
* 设置是否启用 iOS 页面侧滑返回。
*
* 当 `page-container` 组件显示时,框架会调用此方法禁用手势返回,以防止与容器交互冲突;
* 容器关闭或销毁时会再次调用以恢复。
*
* 主要用于 DRN(混合容器)等场景,在纯 RN 环境下框架会通过 React Navigation 的
* `gestureEnabled` 选项自动处理,无需配置此项。
*
* @param enabled true 表示启用侧滑返回,false 表示禁用
*/
setSwipeBackEnabled?: (enabled: boolean) => void
}

interface MpxConfig {
Expand Down
22 changes: 15 additions & 7 deletions packages/core/src/platform/createApp.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as ReactNative from 'react-native'
import { initAppProvides } from './export/inject'
import { NavigationContainer, createNativeStackNavigator, SafeAreaProvider, GestureHandlerRootView } from './env/navigationHelper'
import MpxNav from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-nav'
import { NavigationContainerContext } from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/context'
import { wrapAppLifecycleHooks } from '../core/perf'

const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
Expand Down Expand Up @@ -160,6 +161,7 @@ export default function createApp (options) {
global.__mpxAppLaunched = false
global.__mpxOptionsMap[currentInject.moduleId] = memo((props) => {
const firstRef = useRef(true)
const navigationContainerRef = useRef(null)
const initialRouteRef = useRef({
initialRouteName: firstPage,
initialParams: {}
Expand Down Expand Up @@ -222,17 +224,23 @@ export default function createApp (options) {

return createElement(SafeAreaProvider,
null,
createElement(NavigationContainer,
createElement(NavigationContainerContext.Provider,
{
onStateChange,
onUnhandledAction
value: navigationContainerRef
},
createElement(Stack.Navigator,
createElement(NavigationContainer,
{
initialRouteName,
screenOptions: navScreenOpts
ref: navigationContainerRef,
onStateChange,
onUnhandledAction
},
...getPageScreens(initialRouteName, initialParams)
createElement(Stack.Navigator,
{
initialRouteName,
screenOptions: navScreenOpts
},
...getPageScreens(initialRouteName, initialParams)
)
)
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,26 @@ const TAG_NAME = 'page-container'
module.exports = function () {
return {
test: TAG_NAME,
// 支付宝保留事件名转换,RN 平台继续将组件映射为内建实现。
event: [
{
test: 'beforeleave',
ali () {
return 'beforeLeave'
}
}
]
],
ios (tag, { el }) {
el.isBuiltIn = true
return 'mpx-page-container'
},
android (tag, { el }) {
el.isBuiltIn = true
return 'mpx-page-container'
},
harmony (tag, { el }) {
el.isBuiltIn = true
return 'mpx-page-container'
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const JD_UNSUPPORTED_TAG_NAME_ARR = ['functional-page-navigator', 'live-pusher',
// 快应用不支持的标签集合
const QA_UNSUPPORTED_TAG_NAME_ARR = ['movable-view', 'movable-area', 'open-data', 'official-account', 'editor', 'functional-page-navigator', 'live-player', 'live-pusher', 'ad', 'cover-image']
// RN不支持的标签集合
const RN_UNSUPPORTED_TAG_NAME_ARR = ['open-data', 'official-account', 'editor', 'functional-page-navigator', 'live-player', 'live-pusher', 'ad', 'audio', 'match-media', 'page-container', 'keyboard-accessory', 'map']
const RN_UNSUPPORTED_TAG_NAME_ARR = ['open-data', 'official-account', 'editor', 'functional-page-navigator', 'live-player', 'live-pusher', 'ad', 'audio', 'match-media', 'keyboard-accessory', 'map']

/**
* @param {function(object): function} print
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createContext, Dispatch, MutableRefObject, SetStateAction } from 'react'
import { createContext, Dispatch, MutableRefObject, RefObject, SetStateAction } from 'react'
import type { NativeSyntheticEvent, Animated, ScaledSize, TextStyle } from 'react-native'
import { noop } from '@mpxjs/utils'

Expand Down Expand Up @@ -95,6 +95,8 @@ export const IntersectionObserverContext = createContext<IntersectionObserver |

export const RouteContext = createContext<RouteContextValue | null>(null)

export const NavigationContainerContext = createContext<RefObject<any> | null>(null)

export const SwiperContext = createContext({})

export const KeyboardAvoidContext = createContext<KeyboardAvoidContextValue | null>(null)
Expand Down
Loading
Loading