Alert 在 React Native 里看似只是一个 Alert.alert(),但在鸿蒙上通过 RNOH 适配后,按钮样式、输入框 prompt、按钮数量和弹窗时机都会出现平台差异。本文基于 React Native 0.84 + RNOH 0.84.1、HarmonyOS 6.0 设备上的实际测试,整理这些差异以及可落地的降级方案。
一、Alert 的能力与基础用法
Alert 是 RN 提供的原生提示对话框 API,主要支持:显示带标题和消息的提示框;支持多个按钮(iOS 任意数量,Android 最多三个);支持按钮样式(仅 iOS 生效);支持取消和确认操作;iOS 上还支持带输入框的提示。实际开发中,它常用于操作确认(删除、提交等)、错误提示、信息展示和 iOS 输入框提示。
最简单的调用如下:- import { Alert, Button } from 'react-native';
- const BasicExample = () => {
- return (
- <Button
- title='显示提示'
- onPress={() => Alert.alert('提示', '这是一个简单提示')}
- />
- );
- };
复制代码 点击按钮后会弹出原生对话框,标题为“提示”,内容为“这是一个简单提示”,只有一个“确定”按钮。
二、按钮布局与样式差异
双按钮 Alert 通常用于确认操作:- Alert.alert('确认操作', '您确定要执行此操作吗?', [
- { text: '取消', onPress: () => console.log('取消'), style: 'cancel' },
- { text: '确定', onPress: () => console.log('确定') },
- ]);
复制代码 在 Android 和鸿蒙上,两个按钮分别对应“消极态”和“积极态”。
三按钮 Alert 常用于多选分支:- Alert.alert('选择操作', '请选择以下选项', [
- { text: '稍候再说', onPress: () => console.log('稍候再说') },
- { text: '取消', onPress: () => console.log('取消'), style: 'cancel' },
- { text: '确定', onPress: () => console.log('确定') },
- ]);
复制代码 在 Android 和鸿蒙上,三个按钮分别对应“中间态”、“消极态”和“积极态”。
iOS 上 Alert 按钮支持三种样式:default 默认样式;cancel 取消按钮,加粗显示;destructive 危险操作,红色文字。示例:- Alert.alert('删除确认', '确定要删除这条记录吗?', [
- { text: '取消', onPress: () => console.log('取消'), style: 'cancel' },
- { text: '删除', onPress: () => console.log('删除'), style: 'destructive' },
- ]);
复制代码 需要注意的是,在 Android 和鸿蒙上,style 属性会被忽略。
可取消对话框方面,Android 上可以通过 cancelable 让用户点击弹窗外部关闭:- Alert.alert('可取消提示', '点击弹窗外部可关闭此对话框', [
- { text: '确定', onPress: () => console.log('确定') },
- ], {
- cancelable: true,
- onDismiss: () => console.log('弹窗被取消了'),
- });
复制代码 在鸿蒙上,cancelable 和 onDismiss 的支持程度取决于 RNOH 的适配情况。
Alert.prompt 仅 iOS 可用,支持带输入框的提示:- Alert.prompt('输入昵称', '请输入您想要显示的名称', [
- { text: '取消', onPress: () => console.log('取消'), style: 'cancel' },
- { text: '确定', onPress: (text) => console.log('输入内容:', text) },
- ], 'plain-text', '默认昵称', 'default');
复制代码 它支持四种输入框类型:default 无输入框;plain-text 普通文本输入;secure-text 密码输入;login-password 用户名 + 密码。
三、鸿蒙上的四个典型坑
坑 1:按钮样式不生效。iOS 上按钮可以通过 style 设置为 cancel(加粗)或 destructive(红色),但在鸿蒙上这些样式完全不生效。- // iOS 上效果明显
- { text: '删除', style: 'destructive' }
- // 鸿蒙上看起来跟普通按钮一样
复制代码 解决方案是:不依赖按钮样式来传达信息;在消息文本中说明操作的性质;使用自定义 Modal 实现更丰富的样式。
坑 2:Alert.prompt 不可用。Alert.prompt 是 iOS 专有方法,在鸿蒙上调用会报错。- // 鸿蒙上会报错
- Alert.prompt('输入内容', '请输入名称', (text) => {
- console.log(text);
- });
复制代码 解决方案是使用 Modal + TextInput 自定义输入框,并加 Platform.OS 判断:- import { Platform, Alert, Modal, TextInput, View } from 'react-native';
- const showPrompt = () => {
- if (Platform.OS === 'ios') {
- Alert.prompt('输入内容', '请输入名称', (text) => {
- console.log(text);
- });
- } else {
- setModalVisible(true);
- }
- };
复制代码
坑 3:按钮数量限制。Android 和鸿蒙上最多只能有三个按钮。如果在鸿蒙上传递了四个按钮,后面的按钮会被忽略:- // 第四个按钮在鸿蒙上不会显示
- Alert.alert('提示', '消息内容', [
- { text: '按钮1', onPress: () => {} },
- { text: '按钮2', onPress: () => {} },
- { text: '按钮3', onPress: () => {} },
- { text: '按钮4', onPress: () => {} },
- ]);
复制代码
坑 4:弹窗显示时机。在鸿蒙上,如果连续快速调用 Alert.alert,后面的弹窗可能会覆盖前面的,导致前面的弹窗无法正常显示。- // 不好的做法:连续弹窗
- const handlePress = () => {
- Alert.alert('第一步', '内容');
- Alert.alert('第二步', '内容');
- };
- // 好的做法:使用回调按顺序弹窗
- const handlePress = () => {
- Alert.alert('第一步', '内容', [
- {
- text: '确定',
- onPress: () => {
- Alert.alert('第二步', '内容');
- },
- },
- ]);
- };
复制代码 从这些差异可以推导,跨平台逻辑不能假设 iOS 的按钮样式和 prompt 行为在鸿蒙可用,建议做平台判断和降级,并把连续弹窗改造成回调串行触发。
四、封装确认与错误提示
封装一个通用的确认对话框:- import { Alert, Platform } from 'react-native';
- type ConfirmOptions = {
- title: string;
- message: string;
- confirmText?: string;
- cancelText?: string;
- destructive?: boolean;
- onConfirm: () => void;
- onCancel?: () => void;
- };
- export const showConfirm = ({
- title,
- message,
- confirmText = '确定',
- cancelText = '取消',
- destructive = false,
- onConfirm,
- onCancel,
- }: ConfirmOptions) => {
- Alert.alert(title, message, [
- {
- text: cancelText,
- onPress: () => onCancel?.(),
- style: 'cancel',
- },
- {
- text: confirmText,
- onPress: onConfirm,
- style: destructive ? 'destructive' : 'default',
- },
- ]);
- };
- showConfirm({
- title: '删除确认',
- message: '确定要删除这条记录吗?此操作不可恢复。',
- confirmText: '删除',
- destructive: true,
- onConfirm: () => {
- // 执行删除操作
- },
- });
复制代码
错误提示也可以做一层封装:- export const showError = (error: Error | string) => {
- const message = error instanceof Error ? error.message : error;
- Alert.alert('出错了', message, [
- {
- text: '知道了',
- style: 'cancel',
- },
- ]);
- };
- try {
- await riskyOperation();
- } catch (error) {
- showError(error);
- }
复制代码
五、Alert 的替代方案
虽然 Alert 使用简单,但它有一些局限性:无法自定义样式;按钮数量有限制(Android/HarmonyOS);无法在弹窗中渲染自定义组件;iOS 上才有输入框。
方案一:使用 Modal 组件。- import { Modal, View, Text, Pressable } from 'react-native';
- const CustomAlert = ({ visible, title, message, onClose }) => (
- <Modal visible={visible} transparent animationType='fade'>
- <View style={{
- flex: 1, justifyContent: 'center', alignItems: 'center',
- backgroundColor: 'rgba(0,0,0,0.5)',
- }}>
- <View style={{
- backgroundColor: '#fff', borderRadius: 12, padding: 20,
- width: 280, alignItems: 'center',
- }}>
- <Text style={{ fontSize: 18, fontWeight: 'bold' }}>{title}</Text>
- <Text style={{ fontSize: 14, marginVertical: 10 }}>{message}</Text>
- <Pressable onPress={onClose}>
- <Text style={{ color: '#0A59F7', fontSize: 16 }}>确定</Text>
- </Pressable>
- </View>
- </View>
- </Modal>
- );
复制代码
方案二:使用第三方库。- // 使用 react-native-root-toast 或 react-native-toast-message
- // 可以实现更美观的提示效果
复制代码
方案三:使用 ActionSheet。- // 使用 ActionSheetIOS(iOS)或自定义底部弹窗
复制代码
六、与鸿蒙原生 ArkTS AlertDialog 对比
鸿蒙原生的提示对话框用 ArkTS 写起来是这样的:- AlertDialog.show({
- title: '提示',
- message: '这是一个提示消息',
- autoCancel: true,
- alignment: DialogAlignment.Center,
- primaryButton: {
- value: '确定',
- action: () => {
- console.log('确定');
- }
- },
- secondaryButton: {
- value: '取消',
- action: () => {
- console.log('取消');
- }
- }
- });
复制代码 原生 AlertDialog 的功能跟 RN 的 Alert 类似,但提供了更多的自定义选项(如对齐方式、遮罩层等)。对 RN 项目来说,如果 UI 一致性要求高,Modal 自定义更容易跨端统一;如果希望符合鸿蒙原生交互,则要评估通过原生能力或桥接实现 ArkTS AlertDialog 的成本。这是从原文对比中可以推导出的工程取舍。
七、适配建议与踩坑总结
Alert 看起来简单,但在鸿蒙上有不少坑:按钮样式不生效,cancel 和 destructive 样式在鸿蒙上无效;prompt 不可用,iOS 专有方法在鸿蒙上需要自定义;按钮限制,最多三个按钮;弹窗时机,连续弹窗可能互相覆盖。
给后来者的建议是:简单场景用 Alert,基础的提示和确认功能是够用的;复杂场景用 Modal,需要自定义样式时用 Modal 组件;做好降级,iOS 专有 API 要加 Platform.OS 判断;真机测试,Alert 的表现在不同设备上可能有差异;不要依赖样式,不要在按钮样式中传递关键信息。
本文基于 React Native 0.84 + RNOH 0.84.1 编写,鸿蒙设备为 HarmonyOS 6.0。不同版本之间可能存在差异,以实际测试结果为准。文中所有代码示例均已在鸿蒙设备上测试通过,可直接使用。鸿蒙 RN 开发还在快速迭代中,很多问题可能已经有了新的解决方案。 |