基于React Native鸿蒙跨平台Modal组件的属性animationType/transparent/visible/onRequestClose在鸿蒙端转换为 ArkUI 的Dialog属性
本文介绍了一个基于React Native开发的在线处方应用的技术实现细节。该应用采用TypeScript提供类型安全保障,使用函数式组件和Hooks进行状态管理,通过Flexbox布局实现响应式设计。核心功能包括处方开具与管理、药品购买、取药码生成等,均采用React Native跨平台组件实现。文章重点分析了该应用在鸿蒙系统上的适配策略,包括组件兼容性、性能优化和资源加载等方面的考虑,展示了R
欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。
在医疗健康领域,在线处方系统正成为连接医患与药房的重要桥梁。今天我们将深入分析一个基于 React Native 开发的在线处方应用,探讨其技术实现细节以及在鸿蒙系统上的跨端适配策略。
TypeScript 提供类型
该应用采用了 React Native 作为核心框架,结合 TypeScript 提供类型安全保障。从代码结构来看,项目遵循了 React 函数式组件的设计范式,充分利用了 Hooks 进行状态管理。
const OnlinePrescriptionApp: React.FC = () => {
const [prescriptions, setPrescriptions] = useState<Prescription[]>([...]);
const [medicines] = useState<Medicine[]>([...]);
const [selectedPrescription, setSelectedPrescription] = useState<string | null>(null);
const [isModalVisible, setIsModalVisible] = useState(false);
const [modalContent, setModalContent] = useState('');
// ...
};
这种函数式组件的写法不仅代码更简洁,而且在性能上也有优势。通过多个 useState 钩子,开发者可以独立管理不同的状态,如处方列表、药品列表、选中的处方以及模态框状态等。这种状态管理方式对于在线处方应用来说非常合适,因为各个状态之间存在明确的业务逻辑关系,通过局部状态管理即可满足需求。
业务逻辑关系
项目使用 TypeScript 定义了清晰的数据结构,例如 Prescription 和 Medicine 类型:
type Prescription = {
id: string;
doctorName: string;
patientName: string;
medication: string;
dosage: string;
duration: string;
issuedDate: string;
};
type Medicine = {
id: string;
name: string;
price: number;
stock: number;
};
这种类型定义为代码提供了良好的可维护性和类型检查,避免了运行时错误。在跨端开发中,类型系统的重要性更加凸显,因为不同平台的类型处理可能存在差异,TypeScript 可以帮助开发者在编译时就发现潜在问题。
布局
应用采用了 Flexbox 布局系统,结合 Dimensions API 实现响应式设计:
const { width, height } = Dimensions.get('window');
这种方式确保了应用在不同屏幕尺寸的设备上都能良好显示。特别值得注意的是,代码中使用了 ScrollView 组件来处理内容滚动,对于处方列表和药品列表等可能超出屏幕高度的内容,这种处理方式非常合适。同时,应用使用了卡片式布局来展示处方和药品信息,提升了界面的美观度和可读性。
从代码中可以看出,开发者采用了一套通用的组件和 API,这些都是 React Native 提供的跨平台解决方案:
- 使用
SafeAreaView确保内容不会被设备刘海或底部安全区域遮挡 - 使用
TouchableOpacity实现跨平台的点击效果 - 使用
Alert实现跨平台的弹窗提示 - 使用
Modal实现跨平台的模态框 - 使用
TextInput实现跨平台的文本输入
这些组件在 iOS、Android 和鸿蒙系统上都能正常工作,体现了 React Native 的 “Write Once, Run Anywhere” 理念。
处方管理
应用实现了处方的开具和查看功能:
const handleIssuePrescription = () => {
Alert.alert('开具处方', '处方已成功开具,请患者查看');
};
const handleViewPrescription = (prescriptionId: string) => {
const prescription = prescriptions.find(p => p.id === prescriptionId);
if (prescription) {
setModalContent(`医生: ${prescription.doctorName}\n患者: ${prescription.patientName}\n药品: ${prescription.medication}\n剂量: ${prescription.dosage}\n疗程: ${prescription.duration}\n开具日期: ${prescription.issuedDate}`);
setIsModalVisible(true);
}
};
通过这种方式,医生可以方便地开具处方,患者可以查看处方详情,提升了用户体验。处方开具操作通过 Alert 弹窗提供反馈,确保医生了解操作结果。处方详情通过模态框展示,避免了页面跳转,保持了操作的连续性。
药品购买
应用实现了药品的购买功能:
const handleBuyMedicine = (medicineId: string) => {
const medicine = medicines.find(m => m.id === medicineId);
if (medicine) {
Alert.alert('购买药品', `您已成功购买 ${medicine.name},价格为 ¥${medicine.price}`);
}
};
这种设计使得患者可以方便地购买处方药品,提升了用户体验。购买操作通过 Alert 弹窗提供反馈,确保患者了解操作结果。
取药码生成
应用实现了取药码的生成功能:
const handleGetPickupCode = (prescriptionId: string) => {
const prescription = prescriptions.find(p => p.id === prescriptionId);
if (prescription) {
const pickupCode = Math.floor(100000 + Math.random() * 900000).toString();
setModalContent(`取药码: ${pickupCode}\n请凭此码到药店取药`);
setIsModalVisible(true);
}
};
这种设计使得患者可以方便地获取取药码,凭码到药店取药,提升了用户体验。取药码通过模态框展示,避免了页面跳转,保持了操作的连续性。
模态框功能
应用使用 Modal 组件实现了模态框功能:
const openModal = (content: string) => {
setModalContent(content);
setIsModalVisible(true);
};
const closeModal = () => {
setIsModalVisible(false);
};
这种方式可以在不离开当前页面的情况下展示额外信息,提升了用户体验。
视觉反馈设计
应用通过样式和图标为用户提供了清晰的视觉反馈:
- 使用不同的图标来区分处方和药品
- 使用卡片式布局来展示信息
- 使用 Alert 弹窗来确认用户的操作
- 使用模态框来展示详细信息
这种设计使得用户可以直观地了解应用的状态和操作结果,提升了用户体验。
组件
在鸿蒙系统上,React Native 应用需要考虑组件的兼容性。从代码来看,开发者使用的都是 React Native 核心组件,这些组件在鸿蒙系统上都有对应的实现。例如:
View对应鸿蒙的ComponentText对应鸿蒙的TextScrollView对应鸿蒙的ListContainerModal对应鸿蒙的DialogTouchableOpacity对应鸿蒙的ButtonTextInput对应鸿蒙的TextInput
鸿蒙系统对应用性能有较高要求,特别是在内存使用和启动速度方面。该应用的实现方式有利于在鸿蒙系统上获得良好的性能:
- 使用函数式组件减少了内存占用
- 使用多个
useState钩子进行细粒度的状态管理 - 避免了复杂的计算和不必要的渲染
- 使用
TouchableOpacity替代Button,减少了视图层级
虽然代码中没有直接调用原生能力,但在实际的鸿蒙适配中,可能需要通过 React Native 的 Native Modules 机制来调用鸿蒙的特有 API。例如,当需要实现处方的电子签名或与药房系统的集成时,可能需要调用鸿蒙的安全 API 或网络 API。
资源加载
代码中使用了 Base64 编码的图标:
const ICONS_BASE64 = {
prescription: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
pharmacy: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
cart: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
code: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
};
这种方式的优点是减少了网络请求,提高了应用的加载速度。对于小型图标来说,Base64 编码是一种非常有效的优化策略,特别是在跨端开发中,可以避免不同平台对图片资源的处理差异。
模块化
应用采用了清晰的模块化设计:
- 状态管理与 UI 渲染分离
- 数据结构与业务逻辑分离
- 样式与组件分离
这种设计使得代码结构清晰,易于维护和扩展。例如,当需要添加新的处方类型或药品类型时,只需要修改对应的数据结构和 UI 渲染逻辑即可,不需要修改整体架构。
TypeScript 的使用为代码提供了类型安全保障,减少了运行时错误的可能性。特别是在跨端开发中,类型系统可以帮助开发者发现不同平台之间的潜在差异。
应用使用了 StyleSheet.create 来管理样式,这种方式的优点是:
- 提高了样式的复用性
- 减少了运行时的样式计算
- 使代码更加清晰易读
应用的代码组织合理,逻辑清晰:
- 首先定义了必要的类型和数据
- 然后实现了组件的状态管理
- 接着实现了事件处理函数
- 最后实现了 UI 渲染
通过对这个在线处方应用的技术分析,我们可以看到 React Native 在跨端开发中的优势:
- 开发效率高:使用 JavaScript/TypeScript 开发,代码量少,开发周期短
- 跨平台兼容性好:一套代码可以在 iOS、Android 和鸿蒙系统上运行
- 性能表现优秀:通过原生组件渲染,性能接近原生应用
- 生态系统成熟:拥有丰富的第三方库和工具
- 用户体验良好:可以构建出与原生应用相媲美的界面和交互
- 功能强大:通过 Hooks 等特性,可以实现复杂的业务逻辑
在鸿蒙系统逐渐普及的背景下,React Native 作为一种跨端解决方案,具有广阔的应用前景。开发者可以通过学习和掌握 React Native,快速构建支持多平台的医疗应用,提高开发效率和代码复用率。
同时,我们也可以看到,React Native 在构建具有业务逻辑的应用时表现出色,例如这个在线处方应用。通过简单的状态管理和组件组合,开发者可以实现完整的处方管理和药品购买流程,为用户提供便捷的在线医疗服务。
在线处方是智慧医疗体系中“诊后用药”环节的核心载体,聚焦“处方开具-处方查看-药品购买-取药码生成”的全流程处方管理逻辑,既要保证处方信息展示的准确性与药品购买交互的流畅性,又需兼顾多端处方管理体验的一致性与医疗信息展示的规范性。本文基于这套 React Native 在线处方应用代码,从架构设计、核心业务逻辑、鸿蒙跨端适配三个维度,系统解读在线处方场景的跨端开发逻辑与技术要点,重点剖析 React Native 与鸿蒙系统的适配底层逻辑和落地实践方案,尤其针对处方列表展示、取药码生成、药品购买等核心交互的跨端实现进行深度拆解。
一、处方列表展示、取药码生成、药品购买
该在线处方应用基于 React Native 函数式组件 + TypeScript 强类型架构构建,核心依赖 React Native 原生基础组件(SafeAreaView、ScrollView、TouchableOpacity、Modal 等)与 useState 状态管理,未引入第三方 UI 框架或复杂状态管理库。这种极简架构是在线处方这类“强信息展示、轻实时计算”场景实现鸿蒙跨端的核心优势——轻量意味着适配成本更低,且能最大程度保证多端处方管理流程逻辑的一致性,尤其适合处方列表展示、取药码生成、药品购买等核心逻辑的跨端复用。
从跨端技术底层逻辑来看,React Native 以“JS 桥接层(JS Bridge)”为核心实现跨端能力:前端编写的 JSX 组件与在线处方逻辑,通过桥接层映射为不同平台的原生组件,iOS 端映射为 UIKit 体系、Android 端映射为 View 体系,而鸿蒙(HarmonyOS)端则通过 React Native for HarmonyOS 适配层,完成 React Native 组件/API 与鸿蒙 ArkUI 组件/API 的双向映射。该应用的代码结构完全遵循跨端开发规范:无平台专属硬编码、状态管理基于 React 原生 Hooks、样式采用跨端通用的 Flex 布局,从根源上消除了鸿蒙适配的技术壁垒,同时保证处方开具、处方查看、药品购买等核心在线处方流程逻辑在多端的一致性。
值得注意的是,应用核心的取药码生成逻辑(handleGetPickupCode)为纯 JS 数值运算实现,无任何平台相关依赖,这是跨端复用的关键——鸿蒙端可通过 JS 引擎直接执行该逻辑,无需适配任何原生能力,保证取药码生成规则在多端的完全一致,避免因平台差异导致的取药码生成错误。
1. 在线处方
应用通过 TypeScript 接口定义了 Prescription(处方)、Medicine(药品)两类核心数据类型,字段设计精准匹配在线处方全流程数据需求:
Prescription涵盖处方ID、医生姓名、患者姓名、药品名称、剂量、疗程、开具日期,完整覆盖临床处方的基础信息维度,字段均采用通用字符串格式,在鸿蒙端适配层可直接映射为 ArkTS 的string类型,避免多端数据类型解析差异导致的处方信息展示错误;Medicine包含药品ID、名称、价格、库存,完整覆盖药品购买的核心信息维度,价格字段采用number类型,在鸿蒙端适配层可直接映射为 ArkTS 的number类型,保证药品价格计算、库存展示的跨端准确性,尤其在“阿莫西林 ¥25.0”这类核心药品价格信息的传递上,保证了跨端的数据准确性。
这种强类型+场景化的数据模型设计,在跨端场景下保证了数据结构的一致性——鸿蒙端适配层可直接解析 TypeScript 类型定义,与 ArkTS 中的数据模型形成精准映射,避免多端数据格式不一致导致的处方信息展示异常、药品价格计算错误等核心问题,是在线处方场景跨端落地的基础保障。
2. Hooks 状态管理
应用采用 useState 实现多维度状态管理,核心状态均具备跨端复用的特性:
- 核心业务状态(
prescriptions/medicines)中,prescriptions支持动态更新(setPrescriptions),该更新方法在鸿蒙端会被适配层转换为 ArkTS 的@State状态更新逻辑,新增处方后列表可实时渲染,保证多端处方列表展示的一致性;medicines为只读设计,适配层自动映射为鸿蒙的@State响应式状态,药品列表的展示逻辑跨端统一; - 交互状态(
selectedPrescription/isModalVisible/modalContent)维护处方选择、弹窗显隐与内容,其更新逻辑为基础状态操作,鸿蒙端适配层会将Modal的显示状态映射为 ArkUI 弹窗的显隐状态,弹窗展示处方详情、取药码的逻辑跨端统一; - 取药码生成逻辑中,随机数生成(
Math.floor(100000 + Math.random() * 900000))为纯 JS 数值运算,鸿蒙端直接执行,生成的6位数字取药码格式跨端一致,保证患者凭码取药的核心流程不受平台影响。
1. 处方卡片、药品卡片、开具处方按钮专属样式
应用在基础样式之上新增处方卡片、药品卡片、开具处方按钮专属样式,核心样式设计仍遵循跨端兼容原则,适配鸿蒙系统无明显改造成本,且针对在线处方场景的样式特性做了深度优化:
- Flex 布局的跨端统一:从处方卡片的“图标+处方信息+取药码按钮”、药品卡片的“图标+药品信息+购买按钮”,到开具处方按钮的居中布局,全量采用 Flex 横向布局(
flexDirection: 'row' + alignItems: 'center')。Flex 作为 W3C 标准布局方案,在鸿蒙端可被适配层直接解析为 ArkUI 的 Flex 布局,无需重构任何布局逻辑,仅需保证样式属性命名与 React Native 规范一致,尤其在处方列表、药品列表等核心信息展示区域的布局上,Flex 布局的跨端一致性表现突出; - 在线处方专属样式的跨端适配:
- 处方卡片与药品卡片采用统一的基础样式(
backgroundColor: '#f0f9ff' + borderRadius: 12 + padding: 16),为通用样式属性,鸿蒙端适配层会将尺寸单位转换为vp,卡片的大小、内边距、圆角跨端一致,保证处方/药品信息展示的视觉统一性; - 取药码按钮(
actionButton)与购买按钮(buyButton)采用差异化背景色(#0284c7/#10b981),为通用颜色属性,鸿蒙端适配层转换为 ArkUI 的Color类型,按钮的视觉区分度跨端统一,符合用户对“取药”“购买”不同操作的视觉认知; - 开具处方按钮(
issueButton)采用更大的内边距(padding: 16)与圆角(borderRadius: 12),为通用样式属性,鸿蒙端直接解析,按钮的点击区域与视觉效果跨端一致,突出“开具处方”核心操作的交互优先级;
- 处方卡片与药品卡片采用统一的基础样式(
- 屏幕适配与层级兼容:
Dimensions.get('window')获取设备宽高的 API 在鸿蒙端已完成原生映射,为不同尺寸鸿蒙设备(手机、平板)的自适应布局预留基础;shadow+elevation的双层阴影设计,鸿蒙系统对elevation属性的支持与 Android 端完全兼容,保证处方卡片、药品卡片等组件的视觉层级跨端统一; - 安全区域适配:
SafeAreaView组件在鸿蒙端已适配为 ArkUI 的SafeArea组件,保证头部在线处方标题区域在不同鸿蒙设备上的展示完整性,避免标题被刘海屏、全面屏遮挡。
(1)处方列表
处方列表展示组件是在线处方的核心信息展示环节,核心适配逻辑如下:
- 处方列表的渲染采用
map方法遍历prescriptions数组,该逻辑为纯 JS 数组操作,鸿蒙端通过 JS 引擎直接执行,列表渲染的顺序与数据展示的完整性跨端一致,保证开具的处方信息按添加顺序展示的核心逻辑不被破坏; - 处方卡片的点击逻辑(
handleViewPrescription)包含处方查找、弹窗内容拼接、弹窗显隐状态更新,处方查找(prescriptions.find(p => p.id === prescriptionId))为 JS 原生数组方法,弹窗内容拼接包含医生、患者、药品、剂量等核心处方信息,该逻辑在鸿蒙端直接执行,处方详情的展示格式跨端统一; - 取药码按钮的点击逻辑(
handleGetPickupCode)包含处方查找、随机取药码生成、弹窗内容拼接,随机数生成(Math.floor(100000 + Math.random() * 900000))为纯 JS 数值运算,鸿蒙端直接执行,生成的6位取药码格式跨端一致,弹窗展示取药码的逻辑跨端统一。
(2)药品列表
药品列表管理组件是在线处方的核心购药环节,核心适配逻辑如下:
- 药品列表的渲染采用
map方法遍历medicines数组,该逻辑为纯 JS 数组操作,鸿蒙端直接执行,列表渲染的顺序与药品信息(名称、价格、库存)展示的完整性跨端一致,保证药品信息展示的准确性; - 购买按钮的点击逻辑(
handleBuyMedicine)包含药品查找、购买反馈提示,药品查找(medicines.find(m => m.id === medicineId))为 JS 原生数组方法,购买反馈提示(Alert.alert)会被适配层转换为鸿蒙的AlertDialog组件,提示内容(“您已成功购买 XX 药品,价格为 ¥XX”)的拼接逻辑为纯 JS 字符串操作,跨端一致,保证购药反馈的准确性与交互体验的统一性。
(3)开具处方组件
开具处方组件是在线处方的核心操作环节,核心适配逻辑如下:
- 开具处方按钮的点击逻辑(
handleIssuePrescription)仅包含弹窗反馈提示(Alert.alert),该 API 在鸿蒙端会被适配层转换为AlertDialog组件,提示内容(“处方已成功开具,请患者查看”)为固定字符串,跨端展示与交互逻辑完全一致; - 生产环境中扩展开具处方的表单录入逻辑时,新增的表单输入(
TextInput)、表单校验等逻辑均为纯 JS 实现,鸿蒙端可直接复用,仅需保证表单字段与Prescription数据模型的一致性,核心开具逻辑无需适配。
(4)弹窗组件
弹窗组件是在线处方的核心详情展示环节,核心适配逻辑如下:
Modal组件的核心属性(animationType/transparent/visible/onRequestClose)在鸿蒙端会被适配层转换为 ArkUI 的Dialog组件对应属性,滑动动画(slide)、透明背景(transparent: true)、显隐状态(visible)的逻辑跨端一致,保证处方详情、取药码的展示体验统一;- 弹窗内的文本展示(
modalText)采用通用样式属性(fontSize/color/lineHeight),鸿蒙端直接解析,文本的排版格式跨端一致,保证处方详情、取药码的可读性。
1. 处方查看
handleViewPrescription + handleGetPickupCode 是在线处方的核心信息交互能力,实现了“处方详情展示-取药码生成-弹窗提示”的全流程交互,核心适配逻辑如下:
- 处方查找逻辑(
prescriptions.find(p => p.id === prescriptionId))为纯 JS 数组方法调用,鸿蒙端直接执行,基于 ID 精准查找处方的规则跨端一致,保证能定位到用户点击的具体处方信息; - 处方详情拼接逻辑(
setModalContent)采用字符串换行拼接,该逻辑为通用 JS 字符串操作,鸿蒙端直接执行,拼接后的处方详情格式(医生、患者、药品、剂量、疗程、开具日期)跨端统一,保证用户可清晰查看完整的处方信息; - 取药码生成逻辑(
Math.floor(100000 + Math.random() * 900000).toString())为纯 JS 数值运算 + 类型转换,鸿蒙端直接执行,生成的6位数字取药码格式跨端一致,保证患者凭码取药的核心流程不受平台影响; - 弹窗显隐状态更新(
setIsModalVisible(true))为基础状态操作,鸿蒙端适配层会将Modal组件的visible属性映射为 ArkUI 弹窗的显隐状态,弹窗的触发时机与展示逻辑跨端统一。
2. 药品购买
handleBuyMedicine 函数是在线处方的核心购药交互逻辑,核心适配逻辑如下:
- 药品查找逻辑(
medicines.find(m => m.id === medicineId))为纯 JS 数组方法调用,鸿蒙端直接执行,基于 ID 精准查找药品的规则跨端一致,保证能定位到用户点击的具体药品信息; - 购买反馈提示逻辑(
Alert.alert)使用跨端兼容的弹窗 API,鸿蒙端适配层转换为AlertDialog组件,提示内容的拼接逻辑(您已成功购买 ${medicine.name},价格为 ¥${medicine.price})为纯 JS 字符串操作,跨端一致,保证购药反馈的准确性与交互体验的统一性; - 生产环境中扩展库存扣减逻辑时,新增的库存更新(
setMedicines)为纯 JS 数组操作,鸿蒙端直接执行,库存扣减规则跨端一致,保证药品库存展示的实时性。
3. 开具处方
handleIssuePrescription 函数是在线处方的核心操作逻辑,核心适配逻辑如下:
- 开具处方反馈提示逻辑(
Alert.alert)使用跨端兼容的弹窗 API,鸿蒙端转换为AlertDialog组件,提示内容为固定字符串,跨端展示与交互逻辑完全一致; - 生产环境中扩展处方开具的表单录入与保存逻辑时,新增的表单校验、处方对象生成、列表更新等逻辑均为纯 JS 实现,鸿蒙端可直接复用,仅需保证新处方对象与
Prescription数据模型的一致性,核心开具逻辑无需适配。
应用使用的核心 API 均为 React Native 跨端兼容 API,在鸿蒙端可无缝适配:
- 数组 API:
map/find等数组方法为 JS 原生 API,鸿蒙端通过 JS 引擎直接执行,无需适配,保证处方列表、药品列表的渲染、查找等核心逻辑的跨端一致性; - 数值 API:
Math.floor/Math.random等数值运算 API 为 JS 原生 API,鸿蒙端直接执行,保证取药码生成的跨端一致性; - 字符串 API:字符串拼接/换行符(
\n)等操作为 JS 原生 API,鸿蒙端直接执行,保证弹窗内容拼接等核心逻辑的跨端一致性; - 弹窗 API:
Alert.alert/Modal已被适配层封装为鸿蒙的AlertDialog/Dialog组件,交互逻辑完全复用,在处方开具反馈、购药反馈、处方详情/取药码展示等核心场景中,弹窗的展示与操作逻辑多端统一; - 样式 API:
StyleSheet.create封装的样式规则,适配层转换为 ArkUI 的样式对象,新增的处方卡片、药品卡片、开具处方按钮样式属性(backgroundColor/borderRadius/padding)均为通用属性,无需修改即可适配鸿蒙。
该在线处方应用作为智慧医疗诊后用药核心模块,适配鸿蒙系统的成本极低,核心适配思路与技术要点如下:
1. 纯 JS 业务逻辑
应用核心的取药码生成、处方查找、药品查找等逻辑均为纯 JS 实现,无任何平台相关依赖,这是跨端复用的最大优势——鸿蒙端可通过 JS 引擎直接执行该逻辑,无需适配任何原生能力。在生产环境中扩展处方开具、库存扣减、处方审核等逻辑时,新增规则仍为纯 JS 逻辑,鸿蒙端可直接复用,仅需保证规则逻辑的通用性,无需考虑平台差异,这也是在线处方场景跨端开发的核心优势。
该应用当前的列表渲染采用基础 map 方法,在生产环境中若处方/药品数据量较大(如超过50条处方记录、超过30条药品信息),可替换为 React Native 的 FlatList 高性能列表组件——FlatList 在鸿蒙端已完成深度适配,支持虚拟化列表渲染,其核心属性(data/renderItem/keyExtractor)与 React Native 端完全一致,仅需少量调整即可适配鸿蒙端的性能优化策略,保证列表的滚动性能,尤其适合长期处方管理产生的海量处方数据与药品信息展示场景。
3. 在线处方样式
鸿蒙系统有自身的设计规范,在适配时可通过条件编译实现差异化样式,既保证遵循鸿蒙设计规范,又能最大程度复用现有代码:
// 鸿蒙端在线处方样式差异化适配示例
import { Platform } from 'react-native';
const isHarmonyOS = Platform.OS === 'harmony';
const adaptiveStyles = {
prescriptionCard: {
...styles.prescriptionCard,
backgroundColor: isHarmonyOS ? '#e0f7fa' : '#f0f9ff',
borderRadius: isHarmonyOS ? 14 : 12,
},
buyButton: {
...styles.buyButton,
backgroundColor: isHarmonyOS ? '#059669' : '#10b981',
borderRadius: isHarmonyOS ? 10 : 8,
},
issueButton: {
...styles.issueButton,
backgroundColor: isHarmonyOS ? '#0369a1' : '#0284c7',
borderRadius: isHarmonyOS ? 14 : 12,
}
};
这种轻量级的差异化适配,既能保证符合鸿蒙的设计规范,又能保留现有代码的完整性,尤其在处方卡片、购买按钮、开具处方按钮等核心在线处方交互组件的样式适配中,效果显著。
该 React Native 在线处方应用实现了处方列表展示、处方详情查看、取药码生成、药品购买、处方开具等核心智慧医疗诊后用药功能,代码结构符合跨端开发规范,可低成本适配鸿蒙系统。针对生产环境落地,可做以下优化:
- 处方开具逻辑扩展:新增处方开具的表单录入组件(
TextInput),实现医生、患者、药品、剂量等信息的手动录入,表单校验逻辑为纯 JS 实现,鸿蒙端可直接执行,提升处方开具的实用性; - 库存扣减逻辑完善:在
handleBuyMedicine函数中新增库存扣减逻辑(setMedicines),扣减规则为纯 JS 数组操作,鸿蒙端直接执行,保证药品库存的实时更新,避免超售问题; - 取药码有效性管理:为
Prescription模型新增取药码有效期字段,在handleGetPickupCode函数中添加有效期判断逻辑,该逻辑为纯 JS 日期运算,鸿蒙端直接执行,提升取药码的安全性; - 数据持久化与同步:引入 AsyncStorage(或鸿蒙原生 Preferences)实现处方信息与药品数据的本地加密存储,同时对接医疗云平台接口实现数据云端同步,鸿蒙端兼容主流存储方案,可直接复用数据处理逻辑,保证处方信息的跨设备同步;
- 鸿蒙原生能力融合:通过 React Native 原生模块封装鸿蒙的扫码能力,实现取药码扫码核销功能,核心处方管理逻辑可完全复用现有代码,仅需对接鸿蒙的扫码 API,提升取药流程的便捷性。
真实演示案例代码:
// App.tsx
import React, { useState } from 'react';
import { SafeAreaView, View, Text, StyleSheet, TouchableOpacity, ScrollView, Dimensions, Alert, TextInput, Modal } from 'react-native';
// Base64 图标库
const ICONS_BASE64 = {
prescription: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
pharmacy: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
cart: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
code: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
};
const { width, height } = Dimensions.get('window');
// 处方类型
type Prescription = {
id: string;
doctorName: string;
patientName: string;
medication: string;
dosage: string;
duration: string;
issuedDate: string;
};
// 药品类型
type Medicine = {
id: string;
name: string;
price: number;
stock: number;
};
// 在线处方应用组件
const OnlinePrescriptionApp: React.FC = () => {
const [prescriptions, setPrescriptions] = useState<Prescription[]>([
{
id: '1',
doctorName: '张医生',
patientName: '李先生',
medication: '阿莫西林',
dosage: '500mg',
duration: '7天',
issuedDate: '2023-12-01'
}
]);
const [medicines] = useState<Medicine[]>([
{
id: '1',
name: '阿莫西林',
price: 25.0,
stock: 100
},
{
id: '2',
name: '布洛芬',
price: 15.0,
stock: 50
}
]);
const [selectedPrescription, setSelectedPrescription] = useState<string | null>(null);
const [isModalVisible, setIsModalVisible] = useState(false);
const [modalContent, setModalContent] = useState('');
const handleIssuePrescription = () => {
Alert.alert('开具处方', '处方已成功开具,请患者查看');
};
const handleBuyMedicine = (medicineId: string) => {
const medicine = medicines.find(m => m.id === medicineId);
if (medicine) {
Alert.alert('购买药品', `您已成功购买 ${medicine.name},价格为 ¥${medicine.price}`);
}
};
const handleGetPickupCode = (prescriptionId: string) => {
const prescription = prescriptions.find(p => p.id === prescriptionId);
if (prescription) {
const pickupCode = Math.floor(100000 + Math.random() * 900000).toString();
setModalContent(`取药码: ${pickupCode}\n请凭此码到药店取药`);
setIsModalVisible(true);
}
};
const handleViewPrescription = (prescriptionId: string) => {
const prescription = prescriptions.find(p => p.id === prescriptionId);
if (prescription) {
setModalContent(`医生: ${prescription.doctorName}\n患者: ${prescription.patientName}\n药品: ${prescription.medication}\n剂量: ${prescription.dosage}\n疗程: ${prescription.duration}\n开具日期: ${prescription.issuedDate}`);
setIsModalVisible(true);
}
};
const openModal = (content: string) => {
setModalContent(content);
setIsModalVisible(true);
};
const closeModal = () => {
setIsModalVisible(false);
};
return (
<SafeAreaView style={styles.container}>
{/* 头部 */}
<View style={styles.header}>
<Text style={styles.title}>在线处方</Text>
<Text style={styles.subtitle}>医生在线开具处方,患者可直接购药或凭码取药</Text>
</View>
<ScrollView style={styles.content}>
{/* 处方列表 */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>处方列表</Text>
{prescriptions.map(prescription => (
<TouchableOpacity
key={prescription.id}
style={styles.prescriptionCard}
onPress={() => handleViewPrescription(prescription.id)}
>
<Text style={styles.icon}>📝</Text>
<View style={styles.cardInfo}>
<Text style={styles.cardTitle}>{prescription.medication}</Text>
<Text style={styles.cardDescription}>医生: {prescription.doctorName}</Text>
<Text style={styles.cardDescription}>患者: {prescription.patientName}</Text>
<Text style={styles.cardDescription}>开具日期: {prescription.issuedDate}</Text>
</View>
<TouchableOpacity
style={styles.actionButton}
onPress={() => handleGetPickupCode(prescription.id)}
>
<Text style={styles.actionText}>取药码</Text>
</TouchableOpacity>
</TouchableOpacity>
))}
</View>
{/* 药品列表 */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>药品列表</Text>
{medicines.map(medicine => (
<View key={medicine.id} style={styles.medicineCard}>
<Text style={styles.icon}>💊</Text>
<View style={styles.cardInfo}>
<Text style={styles.cardTitle}>{medicine.name}</Text>
<Text style={styles.cardDescription}>价格: ¥{medicine.price}</Text>
<Text style={styles.cardDescription}>库存: {medicine.stock}</Text>
</View>
<TouchableOpacity
style={styles.buyButton}
onPress={() => handleBuyMedicine(medicine.id)}
>
<Text style={styles.buyText}>购买</Text>
</TouchableOpacity>
</View>
))}
</View>
{/* 开具处方 */}
<View style={styles.issueSection}>
<TouchableOpacity
style={styles.issueButton}
onPress={handleIssuePrescription}
>
<Text style={styles.issueText}>开具处方</Text>
</TouchableOpacity>
</View>
{/* 使用说明 */}
<View style={styles.infoCard}>
<Text style={styles.sectionTitle}>📘 使用说明</Text>
<Text style={styles.infoText}>• 医生可在线开具处方</Text>
<Text style={styles.infoText}>• 患者可查看处方详情</Text>
<Text style={styles.infoText}>• 支持直接购买药品或凭码取药</Text>
<Text style={styles.infoText}>• 请遵医嘱合理用药</Text>
</View>
{/* 弹框内容 */}
<Modal
animationType="slide"
transparent={true}
visible={isModalVisible}
onRequestClose={closeModal}
>
<View style={styles.modalContainer}>
<View style={styles.modalContent}>
<Text style={styles.modalTitle}>详细信息</Text>
<Text style={styles.modalText}>{modalContent}</Text>
<TouchableOpacity
style={styles.closeButton}
onPress={closeModal}
>
<Text style={styles.closeButtonText}>关闭</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f0f9ff',
},
header: {
flexDirection: 'column',
padding: 16,
backgroundColor: '#ffffff',
borderBottomWidth: 1,
borderBottomColor: '#bae6fd',
},
title: {
fontSize: 20,
fontWeight: 'bold',
color: '#0c4a6e',
marginBottom: 4,
},
subtitle: {
fontSize: 14,
color: '#0284c7',
},
content: {
flex: 1,
marginTop: 12,
},
section: {
backgroundColor: '#ffffff',
marginHorizontal: 16,
marginBottom: 12,
borderRadius: 12,
padding: 16,
elevation: 2,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
},
sectionTitle: {
fontSize: 16,
fontWeight: '600',
color: '#0c4a6e',
marginBottom: 12,
},
prescriptionCard: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#f0f9ff',
borderRadius: 12,
padding: 16,
marginBottom: 12,
},
medicineCard: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#f0f9ff',
borderRadius: 12,
padding: 16,
marginBottom: 12,
},
icon: {
fontSize: 28,
marginRight: 12,
},
cardInfo: {
flex: 1,
},
cardTitle: {
fontSize: 16,
fontWeight: '500',
color: '#0c4a6e',
marginBottom: 4,
},
cardDescription: {
fontSize: 14,
color: '#0284c7',
marginBottom: 2,
},
actionButton: {
backgroundColor: '#0284c7',
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 8,
},
actionText: {
color: '#ffffff',
fontSize: 12,
fontWeight: '500',
},
buyButton: {
backgroundColor: '#10b981',
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 8,
},
buyText: {
color: '#ffffff',
fontSize: 12,
fontWeight: '500',
},
issueSection: {
backgroundColor: '#ffffff',
marginHorizontal: 16,
marginBottom: 12,
borderRadius: 12,
padding: 16,
elevation: 2,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
},
issueButton: {
backgroundColor: '#0284c7',
padding: 16,
borderRadius: 12,
alignItems: 'center',
},
issueText: {
color: '#ffffff',
fontSize: 16,
fontWeight: '500',
},
infoCard: {
backgroundColor: '#ffffff',
marginHorizontal: 16,
marginBottom: 80,
borderRadius: 12,
padding: 16,
elevation: 2,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
},
infoText: {
fontSize: 14,
color: '#64748b',
lineHeight: 20,
marginBottom: 4,
},
modalContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
},
modalContent: {
width: '80%',
backgroundColor: '#ffffff',
borderRadius: 12,
padding: 20,
elevation: 5,
},
modalTitle: {
fontSize: 18,
fontWeight: 'bold',
color: '#0c4a6e',
marginBottom: 12,
textAlign: 'center',
},
modalText: {
fontSize: 14,
color: '#0c4a6e',
lineHeight: 20,
marginBottom: 20,
},
closeButton: {
backgroundColor: '#0284c7',
padding: 10,
borderRadius: 8,
alignItems: 'center',
},
closeButtonText: {
color: '#ffffff',
fontSize: 14,
fontWeight: '500',
},
});
export default OnlinePrescriptionApp;

打包
接下来通过打包命令npn run harmony将reactNative的代码打包成为bundle,这样可以进行在开源鸿蒙OpenHarmony中进行使用。

打包之后再将打包后的鸿蒙OpenHarmony文件拷贝到鸿蒙的DevEco-Studio工程目录去:

最后运行效果图如下显示:

本文介绍了一个基于React Native开发的在线处方应用的技术实现细节。该应用采用TypeScript提供类型安全保障,使用函数式组件和Hooks进行状态管理,通过Flexbox布局实现响应式设计。核心功能包括处方开具与管理、药品购买、取药码生成等,均采用React Native跨平台组件实现。文章重点分析了该应用在鸿蒙系统上的适配策略,包括组件兼容性、性能优化和资源加载等方面的考虑,展示了React Native"一次编写,多端运行"的开发优势。
欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。
更多推荐
所有评论(0)