基于React Native鸿蒙跨平台应用中使用扩展运算符(`...`)创建新状态,避免直接修改原状态
欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。
在即时物流与快递行业数字化升级的背景下,面向一线快递员的移动工作台需要兼顾多端适配能力与轻量化操作体验。React Native 凭借其“跨端一致性”与“原生体验”的双重优势,成为连接 iOS、Android 与鸿蒙(HarmonyOS)系统的核心技术选型。本文以快递员工作台应用为例,从数据模型设计、鸿蒙风格 UI 实现、业务逻辑跨端兼容等维度,深度解析 React Native 对接鸿蒙系统的技术内核与最佳实践。
本快递员工作台聚焦派件全流程管理——待取件、运输中、待签收、已完成四大核心状态的流转,整体架构遵循 React Native 组件化开发范式,同时深度契合鸿蒙系统的设计语言与交互逻辑。从技术底层来看,应用基于 React 函数式组件 + TypeScript 构建,这种组合既保证了代码的类型安全,又能最大化跨端复用率,是 React Native 适配鸿蒙系统的理想技术选型。
1. 强类型数据模型:
在跨端应用开发中,统一且严谨的数据模型是避免多端行为不一致的关键。代码中通过 TypeScript 精准定义了派件任务的核心数据结构,覆盖快递派件全场景的业务属性:
// 派件任务核心模型
type DeliveryTask = {
id: string;
orderNumber: string;
recipientName: string;
recipientPhone: string;
deliveryAddress: string;
packageWeight: number;
packageSize: string;
status: '待取件' | '运输中' | '待签收' | '已完成';
assignedTime: string;
estimatedArrival: string;
};
这种强类型定义不仅在开发阶段提供语法校验和智能提示,更关键的是在鸿蒙系统适配时,能够与 ArkTS 的类型系统形成天然映射。相较于纯 JavaScript 开发,TypeScript 能有效规避因数据类型模糊导致的跨端兼容性问题——尤其是在鸿蒙这类面向全场景智慧终端的操作系统中,类型安全可大幅降低多设备适配的调试成本。
2. 轻量级状态管理:
应用采用 React 内置的 useState Hook 管理核心业务状态,结合不可变数据模式实现派件任务状态的跨端更新:
const [tasks, setTasks] = useState<DeliveryTask[]>([...]);
// 状态更新示例 - 取件操作
setTasks(tasks.map(t =>
t.id === taskId
? { ...t, status: '运输中' }
: t
));
这种轻量级状态管理方案完全适配跨端开发场景,相较于 Redux 等重型状态库,useState 无需额外的中间件和适配层,能够直接在 React Native 支持的所有平台(包括鸿蒙)上稳定运行。从鸿蒙系统的视角来看,useState 的状态更新逻辑与 ArkUI 的 @State 装饰器在设计理念上高度契合,开发者无需切换思维模式即可完成跨端开发,大幅降低了鸿蒙适配的学习成本。
React Native 的核心价值在于通过统一的组件抽象层,屏蔽不同平台的 UI 实现差异。本应用在 UI 层的设计深度复刻了鸿蒙系统的视觉风格与交互规范,同时保证多端体验的一致性。
1. 布局系统:
应用基于 React Native 的 Flex 布局系统构建整体界面,通过 Dimensions.get('window') 获取设备宽高,实现对不同尺寸鸿蒙设备(手机、平板、车载终端)的自适应:
const { width, height } = Dimensions.get('window');
相较于鸿蒙系统的 DirectionalLayout 和 StackLayout,React Native 的 Flex 布局具备更强的跨端兼容性,通过 flexDirection、justifyContent、flexWrap 等属性,能够精准还原鸿蒙系统的布局逻辑。例如任务操作按钮区域的自适应布局:
<View style={styles.taskActions}>
{task.status === '待取件' && (
<TouchableOpacity style={styles.scanButton}>
<Text style={styles.scanButtonText}>扫描取件</Text>
</TouchableOpacity>
)}
{/* 其他状态按钮 */}
</View>
这段代码通过 flexDirection: 'row' 和 flexWrap: 'wrap' 实现了鸿蒙系统特有的流式布局效果,在不同尺寸的鸿蒙设备上都能保持按钮的合理排列,无需针对鸿蒙系统做额外的布局适配。
2. 视觉
应用通过 StyleSheet.create 定义样式表,深度适配鸿蒙系统的设计规范,核心体现在以下几个维度:
- 色彩体系:采用鸿蒙系统的青蓝色系主色调(
#06b6d4、#083344),搭配功能性色彩区分派件状态(待取件-橙色、运输中-蓝色、待签收-紫色、已完成-绿色) - 圆角与阴影:使用
borderRadius: 12实现鸿蒙风格的大圆角设计,通过elevation(Android)和shadow(iOS)属性适配鸿蒙系统的阴影效果,兼顾视觉层次感与跨端一致性 - 状态徽章:通过动态样式绑定实现鸿蒙风格的状态标签,根据派件状态动态渲染对应颜色:
<View style={[
styles.statusBadge,
{ backgroundColor: getStatusColor(task.status) }
]}>
<Text style={styles.statusText}>{task.status}</Text>
</View>
这种样式设计方案完全基于 React Native 的标准 API 实现,在鸿蒙系统中能够通过 React Native 的渲染层自动转换为原生样式——backgroundColor 对应鸿蒙的 background-color,borderRadius 对应鸿蒙的 border-radius,无需编写平台特定代码。
3. 交互组件:
应用中所有交互组件均基于 React Native 基础组件封装,同时适配鸿蒙系统的交互规范:
- SafeAreaView:对应鸿蒙系统的
SafeArea组件,适配刘海屏、挖孔屏等异形屏,保证界面在鸿蒙不同终端设备上的完整性 - TouchableOpacity:替代鸿蒙的
Button组件,实现点击反馈效果,符合鸿蒙的交互规范,同时支持长按、点击等基础交互 - Alert:对应鸿蒙的
TextDialog组件,实现取件确认、交付签收等弹窗交互,保持与鸿蒙原生应用一致的交互体验 - ScrollView:与鸿蒙的
List组件逻辑一致,实现长列表的滚动加载,适配鸿蒙系统的滑动交互逻辑
以扫描取件的交互流程为例,代码通过 Alert.alert 实现鸿蒙风格的分步确认弹窗:
Alert.alert(
'扫描包裹',
`订单号: ${task.orderNumber}\n` +
`收件人: ${task.recipientName}\n` +
`地址: ${task.deliveryAddress}\n\n` +
`请确认包裹信息无误`,
[
{ text: '取消', style: 'cancel' },
{
text: '确认取件',
onPress: () => {
// 状态更新逻辑
Alert.alert('成功', '包裹已取件,开始运输');
}
}
]
);
这种交互逻辑完全基于 React Native 的跨端 API 实现,在鸿蒙系统中能够保持与原生应用一致的交互体验,无需针对鸿蒙系统做特殊处理。
除了 UI 层的适配,业务逻辑的跨端兼容性是 React Native 开发的核心。本应用的核心业务逻辑包括派件状态流转、任务筛选、操作交互等,这些逻辑完全基于 JavaScript/TypeScript 实现,天然具备跨端运行能力。
1. 派件状态流转
应用实现了完整的派件状态管理逻辑(待取件 → 运输中 → 待签收 → 已完成),通过纯函数实现状态的不可变更新:
const handleScanPackage = (taskId: string) => {
const task = tasks.find(t => t.id === taskId);
if (task) {
// 确认取件后更新状态
setTasks(tasks.map(t =>
t.id === taskId
? { ...t, status: '运输中' }
: t
));
}
};
这种业务逻辑完全基于纯函数实现,不依赖任何平台特定 API,在 React Native 支持的所有平台(包括鸿蒙)上都能稳定运行。值得注意的是,代码中使用 Array.find、Array.map 等标准 JavaScript 数组方法处理数据,这些方法在鸿蒙系统的 JS 引擎中能够无缝执行,体现了 React Native 跨端开发“一次编写,多端复用”的核心价值。
2. 任务筛选
应用中的任务统计逻辑(如待取件、运输中、待签收任务数)采用纯数据计算实现:
// 待取件任务数统计
tasks.filter(t => t.status === '待取件').length
// 运输中任务数统计
tasks.filter(t => t.status === '运输中').length
这种无副作用的纯函数计算方式,不仅符合 React 的设计理念,更重要的是在跨端场景下,能够避免因不同平台的运行时差异导致的计算错误。对于鸿蒙系统而言,这类纯逻辑代码无需任何适配即可直接运行,是跨端开发的最优实践。
3. 场景化
应用针对不同派件状态提供差异化的操作按钮,实现场景化的交互逻辑:
{task.status === '待取件' && (
<TouchableOpacity
style={styles.scanButton}
onPress={() => handleScanPackage(task.id)}
>
<Text style={styles.scanButtonText}>扫描取件</Text>
</TouchableOpacity>
)}
{task.status === '运输中' && (
<>
<TouchableOpacity style={styles.navigateButton}>
<Text style={styles.navigateButtonText}>导航</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.deliverButton}>
<Text style={styles.deliverButtonText}>交付</Text>
</TouchableOpacity>
</>
)}
该逻辑基于条件渲染实现,完全兼容 React Native 的跨端渲染机制,在鸿蒙系统中能够保持与其他平台一致的交互逻辑,避免因平台差异导致的功能缺失。
从本应用的实现来看,React Native 对接鸿蒙系统的核心在于“抽象层适配”,而非“重写适配”,具体体现在以下几个维度:
-
JS 引擎层兼容:鸿蒙系统内置了符合 ECMAScript 标准的 JavaScript 引擎,能够直接执行 React Native 的 JS 代码,这是跨端运行的底层基础。本应用中所有的业务逻辑代码(状态管理、数据计算、交互处理)均运行在 JS 引擎层,无需任何修改即可在鸿蒙系统中执行,保证了业务逻辑的跨端一致性。
-
组件映射层适配:React Native 通过自定义渲染器,将 React 组件(View、Text、TouchableOpacity 等)映射为鸿蒙系统的原生组件。例如
View组件会被转换为鸿蒙的Div组件,Text组件会被转换为鸿蒙的Text组件,这种映射关系由 React Native 的鸿蒙适配层自动完成,开发者无需关注底层实现细节,只需专注于业务逻辑开发。 -
样式转换层适配:React Native 的 StyleSheet 样式会被自动转换为鸿蒙系统的原生样式,本应用中定义的所有鸿蒙风格样式(圆角、阴影、色彩体系)都能通过这一层完成自动转换,保证了 UI 风格在鸿蒙系统中的一致性。
-
API 适配层兼容:React Native 提供的基础 API(如 Alert、Dimensions)都有对应的鸿蒙实现,本应用中使用的
Alert.alert、Dimensions.get等 API,在鸿蒙系统中会被替换为对应的原生 API 调用,保证了交互行为的跨端一致性。
本快递员工作台应用的实现完整展现了 React Native 在鸿蒙跨端开发领域的技术优势,核心要点可总结为:
- 强类型设计保障跨端一致性:TypeScript 类型定义不仅提升代码质量,更能与鸿蒙 ArkTS 形成类型映射,降低跨端适配成本,是物流类应用跨端开发的基础保障
- 纯逻辑开发最大化复用率:业务逻辑与 UI 层解耦,采用纯 JavaScript/TypeScript 实现核心逻辑,无需针对鸿蒙系统做特殊修改,大幅提升开发效率
- 标准 API 适配鸿蒙生态:基于 React Native 标准组件和 API 开发,通过底层适配层自动对接鸿蒙原生能力,兼顾开发效率与原生体验
本项目采用React Native函数式组件架构,以CourierApp为核心组件,实现了快递员工作台的完整功能流程。架构设计遵循模块化原则,将数据结构、状态管理和业务逻辑清晰分离,便于维护和扩展。
核心技术栈
- React Native:跨平台移动应用开发框架,支持iOS、Android和鸿蒙系统
- TypeScript:提供类型安全,增强代码可维护性和开发体验
- Hooks API:使用useState进行状态管理,简化组件逻辑
- Flexbox:实现响应式布局,适配不同屏幕尺寸
- Base64图标:内置图标资源,减少网络请求,提升加载速度
- Dimensions API:获取屏幕尺寸,实现精细化布局控制
派件任务类型(DeliveryTask)
type DeliveryTask = {
id: string;
orderNumber: string;
recipientName: string;
recipientPhone: string;
deliveryAddress: string;
packageWeight: number;
packageSize: string;
status: '待取件' | '运输中' | '待签收' | '已完成';
assignedTime: string;
estimatedArrival: string;
};
该类型设计全面,包含了派件任务的核心信息:
id:唯一标识符,确保数据唯一性orderNumber:订单号,便于任务追踪recipientName、recipientPhone:收件人信息,便于联系deliveryAddress:配送地址,确保准确送达packageWeight、packageSize:包裹信息,影响配送难度status:任务状态,使用联合类型确保类型安全,清晰定义业务流程assignedTime、estimatedArrival:时间信息,用于任务规划
核心状态设计
应用使用useState钩子管理一个核心状态:
tasks:派件任务列表,支持动态更新
状态更新机制
- 包裹扫描:通过handleScanPackage函数,更新任务状态为"运输中"
- 包裹交付:通过handleDeliverPackage函数,更新任务状态为"已完成"
- 状态更新:通过setTasks函数,批量更新任务状态
- 用户交互:通过Alert组件提供操作确认和信息提示
状态管理优化
- 不可变数据模式:使用扩展运算符(
...)创建新状态,避免直接修改原状态 - 批量更新:在状态更新时使用map方法批量处理,确保数据一致性
- 状态验证:在进行操作前,通过find方法验证任务是否存在
- 用户反馈:操作完成后,通过Alert组件提供明确的成功提示
核心业务流程
- 任务管理:展示派件任务列表,包含完整的任务信息
- 包裹扫描:扫描包裹并确认取件,更新任务状态
- 包裹交付:交付包裹并确认签收,完成任务
- 收件人联系:提供与收件人的沟通渠道,方便配送协调
- 导航功能:支持导航到配送地址,提高配送效率
核心业务逻辑
const handleScanPackage = (taskId: string) => {
const task = tasks.find(t => t.id === taskId);
if (task) {
Alert.alert(
'扫描包裹',
`订单号: ${task.orderNumber}\n` +
`收件人: ${task.recipientName}\n` +
`地址: ${task.deliveryAddress}\n\n` +
`请确认包裹信息无误`,
[
{ text: '取消', style: 'cancel' },
{
text: '确认取件',
onPress: () => {
setTasks(tasks.map(t =>
t.id === taskId
? { ...t, status: '运输中' }
: t
));
Alert.alert('成功', '包裹已取件,开始运输');
}
}
]
);
}
};
数据流设计
- 单向数据流:状态 → 视图 → 用户操作 → 状态更新
- 数据验证:在进行操作前,验证任务是否存在
- 业务逻辑封装:将复杂操作逻辑封装在专用函数中,提高代码可读性
- 用户交互反馈:使用Alert组件提供操作确认和信息提示,提升用户体验
组件
- 核心组件:SafeAreaView、View、Text、ScrollView、TouchableOpacity等在鸿蒙系统上有对应实现
- API兼容性:Dimensions API在鸿蒙系统中可正常使用,确保布局适配
- Alert组件:鸿蒙系统支持Alert组件的基本功能,但样式可能有所差异
- 导航功能:需要注意鸿蒙系统对地图导航API的支持情况,可能需要自定义实现
资源
- Base64图标:在鸿蒙系统中同样支持,可减少网络请求,提升性能
- 内存管理:鸿蒙系统对内存使用更为严格,需注意资源释放
- 计算性能:对于任务状态管理等操作,鸿蒙系统的处理性能与其他平台相当
性能优化
-
渲染性能:
- 避免不必要的重渲染,合理使用React.memo
- 对于长任务列表,建议使用FlatList替代ScrollView
- 优化组件结构,减少嵌套层级
-
数据处理:
- 缓存计算结果,避免重复计算
- 优化任务过滤和查找算法,特别是任务状态统计
- 考虑使用useMemo缓存计算结果,提高性能
-
内存管理:
- 及时释放不再使用的资源
- 避免内存泄漏,特别是在处理多个任务时
- 合理使用缓存策略,平衡性能和内存占用
- 条件渲染:使用Platform API检测平台,针对不同平台使用不同实现
- 样式适配:考虑鸿蒙系统的设计规范,调整UI样式以符合平台特性
- 权限处理:鸿蒙系统的权限管理与Android有所不同,需单独处理
- 鸿蒙特性:充分利用鸿蒙系统的分布式能力,实现多设备协同
- 定位服务:针对鸿蒙系统的定位服务,调整导航功能实现
随着React Native和鸿蒙系统的不断发展,跨端开发将会变得更加成熟和高效。未来可以考虑:
- 使用React Native 0.70+版本:利用新的架构特性,如Fabric渲染器和Turbo Modules,提升应用性能
- 探索鸿蒙原生能力:充分利用鸿蒙系统的分布式能力,实现多设备协同和更丰富的功能
- 引入现代化状态管理:使用Redux Toolkit或Zustand等现代状态管理库,简化状态管理
- 实现PWA支持:扩展应用的使用场景,支持Web平台
- 集成AI能力:引入AI技术,如智能路径规划、包裹识别等,提升应用智能化水平
- 实时定位系统:集成实时定位系统,实现对快递员位置的实时监控
- 多语言支持:添加多语言支持,提升应用的全球适配能力
通过持续的技术迭代和优化,可以构建更加稳定、高效、智能的快递员工作台应用,为快递行业的数字化转型提供技术支持。
真实演示案例代码:
// App.tsx
import React, { useState } from 'react';
import { SafeAreaView, View, Text, StyleSheet, TouchableOpacity, ScrollView, Dimensions, Alert } from 'react-native';
// Base64 图标库
const ICONS_BASE64 = {
package: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
scan: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
signature: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
location: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
phone: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
check: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
alert: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
info: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
};
const { width, height } = Dimensions.get('window');
// 派件任务类型
type DeliveryTask = {
id: string;
orderNumber: string;
recipientName: string;
recipientPhone: string;
deliveryAddress: string;
packageWeight: number;
packageSize: string;
status: '待取件' | '运输中' | '待签收' | '已完成';
assignedTime: string;
estimatedArrival: string;
};
// 快递员应用组件
const CourierApp: React.FC = () => {
const [tasks, setTasks] = useState<DeliveryTask[]>([
{
id: '1',
orderNumber: 'KD20231201001',
recipientName: '李先生',
recipientPhone: '138****1234',
deliveryAddress: '北京市朝阳区某某小区12号楼',
packageWeight: 1.2,
packageSize: '中等',
status: '待取件',
assignedTime: '2023-12-01 08:30',
estimatedArrival: '2023-12-01 10:30'
},
{
id: '2',
orderNumber: 'KD20231201002',
recipientName: '王女士',
recipientPhone: '139****5678',
deliveryAddress: '上海市浦东新区某写字楼',
packageWeight: 0.8,
packageSize: '小件',
status: '运输中',
assignedTime: '2023-12-01 09:15',
estimatedArrival: '2023-12-01 11:00'
},
{
id: '3',
orderNumber: 'KD20231201003',
recipientName: '张先生',
recipientPhone: '137****9012',
deliveryAddress: '广州市天河区某住宅区',
packageWeight: 2.5,
packageSize: '大件',
status: '待签收',
assignedTime: '2023-12-01 07:45',
estimatedArrival: '2023-12-01 09:30'
}
]);
const getStatusColor = (status: string) => {
switch (status) {
case '待取件': return '#f59e0b';
case '运输中': return '#3b82f6';
case '待签收': return '#8b5cf6';
case '已完成': return '#10b981';
default: return '#6b7280';
}
};
const handleScanPackage = (taskId: string) => {
const task = tasks.find(t => t.id === taskId);
if (task) {
Alert.alert(
'扫描包裹',
`订单号: ${task.orderNumber}\n` +
`收件人: ${task.recipientName}\n` +
`地址: ${task.deliveryAddress}\n\n` +
`请确认包裹信息无误`,
[
{ text: '取消', style: 'cancel' },
{
text: '确认取件',
onPress: () => {
setTasks(tasks.map(t =>
t.id === taskId
? { ...t, status: '运输中' }
: t
));
Alert.alert('成功', '包裹已取件,开始运输');
}
}
]
);
}
};
const handleDeliverPackage = (taskId: string) => {
const task = tasks.find(t => t.id === taskId);
if (task) {
Alert.alert(
'交付确认',
`订单号: ${task.orderNumber}\n` +
`收件人: ${task.recipientName}\n` +
`请让收件人签字确认`,
[
{ text: '取消', style: 'cancel' },
{
text: '扫描签收',
onPress: () => {
setTasks(tasks.map(t =>
t.id === taskId
? { ...t, status: '已完成' }
: t
));
Alert.alert('成功', '包裹已成功交付');
}
}
]
);
}
};
const handleContactRecipient = (taskId: string) => {
const task = tasks.find(t => t.id === taskId);
if (task) {
Alert.alert('联系收件人', `拨打 ${task.recipientPhone}`, [
{ text: '取消', style: 'cancel' },
{ text: '拨打', onPress: () => Alert.alert('提示', '正在拨打电话...') }
]);
}
};
const handleNavigate = (taskId: string) => {
const task = tasks.find(t => t.id === taskId);
if (task) {
Alert.alert(
'导航',
`前往: ${task.deliveryAddress}\n` +
`预计到达时间: ${task.estimatedArrival}`,
[
{ text: '取消', style: 'cancel' },
{ text: '开始导航', onPress: () => Alert.alert('提示', '启动地图导航') }
]
);
}
};
return (
<SafeAreaView style={styles.container}>
{/* 头部 */}
<View style={styles.header}>
<Text style={styles.title}>快递员工作台</Text>
<Text style={styles.subtitle}>今日任务: {tasks.length} 件</Text>
</View>
<ScrollView style={styles.content}>
{/* 任务统计 */}
<View style={styles.statsCard}>
<View style={styles.statItem}>
<Text style={styles.statNumber}>
{tasks.filter(t => t.status === '待取件').length}
</Text>
<Text style={styles.statLabel}>待取件</Text>
</View>
<View style={styles.statItem}>
<Text style={styles.statNumber}>
{tasks.filter(t => t.status === '运输中').length}
</Text>
<Text style={styles.statLabel}>运输中</Text>
</View>
<View style={styles.statItem}>
<Text style={styles.statNumber}>
{tasks.filter(t => t.status === '待签收').length}
</Text>
<Text style={styles.statLabel}>待签收</Text>
</View>
</View>
{/* 任务列表 */}
<View style={styles.tasksCard}>
<Text style={styles.sectionTitle}>派件任务</Text>
{tasks.map(task => (
<View key={task.id} style={styles.taskItem}>
<View style={styles.taskHeader}>
<Text style={styles.orderNumber}>{task.orderNumber}</Text>
<View style={[
styles.statusBadge,
{ backgroundColor: getStatusColor(task.status) }
]}>
<Text style={styles.statusText}>{task.status}</Text>
</View>
</View>
<View style={styles.taskDetails}>
<View style={styles.detailRow}>
<Text style={styles.detailLabel}>收件人:</Text>
<Text style={styles.detailValue}>{task.recipientName}</Text>
</View>
<View style={styles.detailRow}>
<Text style={styles.detailLabel}>地址:</Text>
<Text style={styles.detailValue}>{task.deliveryAddress}</Text>
</View>
<View style={styles.detailRow}>
<Text style={styles.detailLabel}>重量:</Text>
<Text style={styles.detailValue}>{task.packageWeight}kg</Text>
</View>
<View style={styles.detailRow}>
<Text style={styles.detailLabel}>预计:</Text>
<Text style={styles.detailValue}>{task.estimatedArrival}</Text>
</View>
</View>
<View style={styles.taskActions}>
{task.status === '待取件' && (
<TouchableOpacity
style={styles.scanButton}
onPress={() => handleScanPackage(task.id)}
>
<Text style={styles.scanButtonText}>扫描取件</Text>
</TouchableOpacity>
)}
{task.status === '运输中' && (
<>
<TouchableOpacity
style={styles.navigateButton}
onPress={() => handleNavigate(task.id)}
>
<Text style={styles.navigateButtonText}>导航</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.deliverButton}
onPress={() => handleDeliverPackage(task.id)}
>
<Text style={styles.deliverButtonText}>交付</Text>
</TouchableOpacity>
</>
)}
{task.status === '待签收' && (
<TouchableOpacity
style={styles.signButton}
onPress={() => handleDeliverPackage(task.id)}
>
<Text style={styles.signButtonText}>签收</Text>
</TouchableOpacity>
)}
<TouchableOpacity
style={styles.contactButton}
onPress={() => handleContactRecipient(task.id)}
>
<Text style={styles.contactButtonText}>联系</Text>
</TouchableOpacity>
</View>
</View>
))}
</View>
{/* 工作提醒 */}
<View style={styles.remindersCard}>
<Text style={styles.sectionTitle}>工作提醒</Text>
{tasks.filter(t => t.status === '待取件').map(task => (
<View key={task.id} style={styles.reminderItem}>
<Text style={styles.reminderIcon}>⏰</Text>
<View style={styles.reminderContent}>
<Text style={styles.reminderTitle}>取件提醒</Text>
<Text style={styles.reminderText}>
订单 {task.orderNumber} 需在 {task.estimatedArrival} 前取件
</Text>
</View>
</View>
))}
{tasks.filter(t => t.status === '运输中').length > 0 && (
<View style={styles.reminderItem}>
<Text style={styles.reminderIcon}>🚛</Text>
<View style={styles.reminderContent}>
<Text style={styles.reminderTitle}>运输中</Text>
<Text style={styles.reminderText}>
共 {tasks.filter(t => t.status === '运输中').length} 个包裹正在运输
</Text>
</View>
</View>
)}
</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>
</ScrollView>
{/* 底部导航 */}
<View style={styles.bottomNav}>
<TouchableOpacity style={styles.navItem}>
<Text style={styles.navIcon}>📦</Text>
<Text style={styles.navText}>任务</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.navItem}>
<Text style={styles.navIcon}>🗺️</Text>
<Text style={styles.navText}>地图</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.navItem}>
<Text style={styles.navIcon}>📊</Text>
<Text style={styles.navText}>统计</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.navItem, styles.activeNavItem]}>
<Text style={styles.navIcon}>👤</Text>
<Text style={styles.navText}>我的</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ecfeff',
},
header: {
flexDirection: 'column',
padding: 16,
backgroundColor: '#ffffff',
borderBottomWidth: 1,
borderBottomColor: '#a5f3fc',
},
title: {
fontSize: 20,
fontWeight: 'bold',
color: '#083344',
marginBottom: 4,
},
subtitle: {
fontSize: 14,
color: '#06b6d4',
},
content: {
flex: 1,
marginTop: 12,
},
statsCard: {
backgroundColor: '#ffffff',
marginHorizontal: 16,
marginBottom: 12,
borderRadius: 12,
padding: 16,
elevation: 2,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
flexDirection: 'row',
justifyContent: 'space-around',
},
statItem: {
alignItems: 'center',
},
statNumber: {
fontSize: 18,
fontWeight: 'bold',
color: '#06b6d4',
},
statLabel: {
fontSize: 12,
color: '#64748b',
marginTop: 4,
},
tasksCard: {
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: '#083344',
marginBottom: 12,
},
taskItem: {
padding: 12,
borderBottomWidth: 1,
borderBottomColor: '#a5f3fc',
},
taskHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 8,
},
orderNumber: {
fontSize: 16,
fontWeight: '600',
color: '#083344',
},
statusBadge: {
paddingHorizontal: 8,
paddingVertical: 4,
borderRadius: 12,
},
statusText: {
fontSize: 12,
color: '#ffffff',
fontWeight: '500',
},
taskDetails: {
marginBottom: 12,
},
detailRow: {
flexDirection: 'row',
marginBottom: 4,
},
detailLabel: {
fontSize: 12,
color: '#64748b',
width: 50,
},
detailValue: {
fontSize: 12,
color: '#083344',
flex: 1,
},
taskActions: {
flexDirection: 'row',
justifyContent: 'flex-end',
flexWrap: 'wrap',
},
scanButton: {
backgroundColor: '#06b6d4',
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 16,
marginRight: 8,
marginBottom: 4,
},
scanButtonText: {
color: '#ffffff',
fontSize: 12,
},
navigateButton: {
backgroundColor: '#8b5cf6',
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 16,
marginRight: 8,
marginBottom: 4,
},
navigateButtonText: {
color: '#ffffff',
fontSize: 12,
},
deliverButton: {
backgroundColor: '#10b981',
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 16,
marginRight: 8,
marginBottom: 4,
},
deliverButtonText: {
color: '#ffffff',
fontSize: 12,
},
signButton: {
backgroundColor: '#f59e0b',
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 16,
marginRight: 8,
marginBottom: 4,
},
signButtonText: {
color: '#ffffff',
fontSize: 12,
},
contactButton: {
backgroundColor: '#cffafe',
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 16,
marginBottom: 4,
},
contactButtonText: {
color: '#06b6d4',
fontSize: 12,
},
remindersCard: {
backgroundColor: '#ffffff',
marginHorizontal: 16,
marginBottom: 12,
borderRadius: 12,
padding: 16,
elevation: 2,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
},
reminderItem: {
flexDirection: 'row',
alignItems: 'center',
padding: 12,
backgroundColor: '#f0fdfa',
borderRadius: 8,
marginBottom: 8,
},
reminderIcon: {
fontSize: 16,
marginRight: 8,
},
reminderContent: {
flex: 1,
},
reminderTitle: {
fontSize: 14,
fontWeight: '500',
color: '#083344',
marginBottom: 2,
},
reminderText: {
fontSize: 12,
color: '#64748b',
},
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,
},
bottomNav: {
flexDirection: 'row',
justifyContent: 'space-around',
backgroundColor: '#ffffff',
borderTopWidth: 1,
borderTopColor: '#a5f3fc',
paddingVertical: 12,
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
},
navItem: {
alignItems: 'center',
flex: 1,
},
activeNavItem: {
paddingTop: 4,
borderTopWidth: 2,
borderTopColor: '#06b6d4',
},
navIcon: {
fontSize: 20,
color: '#94a3b8',
marginBottom: 4,
},
activeNavIcon: {
color: '#06b6d4',
},
navText: {
fontSize: 12,
color: '#94a3b8',
},
activeNavText: {
color: '#06b6d4',
fontWeight: '500',
},
});
export default CourierApp;

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

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

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

React Native在跨平台开发中的优势与实践:以鸿蒙快递员工作台为例
本文探讨了React Native在构建跨平台快递员工作台应用中的技术优势,重点分析了其在鸿蒙系统上的适配方案。通过TypeScript强类型数据模型确保多端一致性,采用轻量级状态管理和Flex布局实现跨端UI适配。案例展示了如何基于React Native组件化开发范式,构建同时兼容iOS、Android和鸿蒙系统的快递派件管理应用,涵盖数据模型设计、鸿蒙风格UI实现及业务逻辑跨端兼容等核心环节。实践表明,React Native能有效降低鸿蒙生态开发门槛,实现"一次编写,多端运行"的高效开发模式。
欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。
更多推荐

所有评论(0)