React Native鸿蒙跨平台实现待办事项列表组件作为移动端高频交互的核心场景,其“增删改查+状态管理+优先级可视化”的复合能力
本文介绍了一个跨平台待办事项列表组件的设计与实现,重点分析了其在React Native和HarmonyOS上的技术适配方案。组件采用模块化设计,包含列表展示、表单交互和状态管理三大核心功能。通过TypeScript强类型定义确保数据一致性,使用useState实现响应式状态管理,并优化列表渲染性能。在UI层面,组件实现了优先级可视化、完成状态反馈等交互细节,采用浮动操作按钮提升移动端操作体验。文
该待办事项列表组件采用了典型的功能组件设计,结合状态驱动的 UI 渲染模式。组件核心由待办事项列表、浮动操作按钮(FAB)和新增表单三部分组成,通过状态管理实现各模块间的协同工作。这种模块化设计在 React Native 鸿蒙跨端开发中具有良好的适应性,能够清晰地映射到不同平台的组件架构。
组件使用 useState Hook 管理待办事项数据、表单可见性及表单字段状态,这是 React 生态中最基础且广泛使用的状态管理方式。在 HarmonyOS ArkUI 中,useState 可以映射到 @State 装饰器,两者都能实现状态的响应式更新,确保 UI 与数据的一致性。
数据模型
应用采用 TypeScript 定义了 TodoItem 类型,包含 id、title、description、completed、priority、dueDate 和 createdAt 等属性。强类型设计在跨端开发中具有显著优势:
- 编译阶段捕获类型错误,减少运行时异常
- 提供清晰的接口定义,便于团队协作
- 支持 IDE 智能提示,提高开发效率
- 确保数据结构在不同平台上的一致性
priority 字段采用联合类型 'low' | 'medium' | 'high',限制了可选值范围,增强了数据的可靠性。这种类型约束在 HarmonyOS ArkUI 中同样受到支持,能够直接复用。
UI 组件
组件使用了 React Native 核心组件库构建用户界面,主要包括:
-
核心布局组件:
SafeAreaView确保内容在安全区域内显示,适配不同设备的刘海屏和底部手势区域;ScrollView或FlatList(从renderTodoItem函数可推断)用于高效渲染待办事项列表。 -
交互组件:
TouchableOpacity实现可点击的待办事项卡片、复选框和浮动操作按钮,提供视觉反馈;TextInput用于表单输入,支持多行文本和不同键盘类型。 -
样式系统:
StyleSheet实现样式与逻辑分离,采用 Flexbox 布局构建响应式界面;Dimensions获取屏幕尺寸,确保在不同设备上的良好显示效果。 -
反馈组件:
Alert用于操作确认和提示信息,如删除待办事项时的确认对话框。
在 HarmonyOS ArkUI 中,这些组件可以映射到对应的 ArkUI 组件:
SafeAreaView对应 ArkUI 的SafeArea组件FlatList对应 ArkUI 的List组件,同样支持虚拟列表优化TouchableOpacity对应 ArkUI 的Button或Gesture组件TextInput对应 ArkUI 的TextInput组件Alert对应 ArkUI 的dialog.showAlertDialogAPI
状态管理
组件的状态管理集中在待办事项数据和表单状态两个方面:
-
待办事项管理:
addTodo函数实现新增待办事项逻辑,包括表单验证、数据创建和状态更新toggleComplete函数切换待办事项的完成状态,采用不可变数据更新方式deleteTodo函数实现待办事项删除,包含确认对话框
-
表单状态管理:
showAddForm控制新增表单的显示与隐藏- 表单字段(标题、描述、优先级、截止日期)各自对应独立的状态变量
resetForm函数重置表单状态
这些业务逻辑在跨端开发中可以直接复用,无需针对不同平台进行修改。需要注意的是,React Native 的状态更新是异步的,而 ArkUI 的状态更新可能是同步的,但这种差异对业务逻辑的影响较小,可以通过统一的状态管理模式来处理。
响应式布局
组件使用 StyleSheet 定义样式,采用了模块化的样式设计,将不同组件的样式分离,便于维护和扩展。样式系统基于 Flexbox 布局,能够自适应不同屏幕尺寸,这在 React Native 和 HarmonyOS ArkUI 中都有良好的支持。
组件中的浮动操作按钮(FAB)采用绝对定位实现,通过 bottom 和 right 属性固定在屏幕右下角,这种设计在移动应用中非常常见,能够快速访问核心功能。在 HarmonyOS ArkUI 中,可以使用 Position 属性实现类似的定位效果。
优先级标签的样式根据优先级动态变化,通过 getPriorityColor 函数返回不同的颜色值,这种动态样式在跨端开发中可以直接复用,无需针对不同平台进行修改。
用户体验
组件实现了丰富的交互功能,包括:
- 待办事项的添加、删除和状态切换
- 优先级的视觉区分
- 完成状态的直观反馈(勾选图标和删除线)
- 表单验证和操作确认
- 浮动操作按钮的快捷访问
这些交互设计在跨端开发中需要保持一致性,确保用户在不同平台上获得相似的体验。例如,删除操作的确认对话框、表单验证的提示信息、完成状态的视觉反馈等,都应该在 React Native 和 HarmonyOS 上保持一致。
该待办事项列表组件展示了 React Native 鸿蒙跨端开发的核心技术要点,包括组件设计、状态管理、UI 实现、交互设计和样式系统等。通过合理的架构设计和技术选型,可以实现高效、一致的跨端应用开发。
随着 HarmonyOS 生态的不断发展和 React Native 跨端工具链的优化,开发者将能够更便捷地构建跨平台的高质量应用。掌握 React Native 与 HarmonyOS 跨端开发技术,将为开发者带来更广阔的发展空间和更多的应用场景。
该待办事项组件的设计思路和实现方式为 React Native 鸿蒙跨端开发提供了良好的参考,展示了如何通过合理的架构设计和技术选型,实现高效、一致的跨端应用开发。
待办清单(Todo List)作为移动端高频交互的核心场景,其“增删改查+状态管理+优先级可视化”的复合能力,是检验跨端开发一致性的典型案例。本文以 React Native 开发的待办清单组件(含浮动操作按钮FAB、表单交互、状态可视化)为例,深度拆解其“数据模型设计、状态驱动交互、列表渲染优化、表单封装”的核心实现逻辑,并系统阐述向鸿蒙(HarmonyOS)ArkTS 跨端迁移的技术路径,聚焦“状态管理等价转换、列表渲染跨端一致、表单交互语义复用”三大核心维度,为移动端待办类组件的跨端开发提供可落地的技术参考。
状态管理
该待办清单组件构建了“多层级状态管理 + 强类型数据约束”的底层架构,完全贴合待办场景的业务特性,也是跨端复用的核心基础:
- 业务类型定义:
TodoItem类型精准覆盖待办项的全维度属性,包含id(唯一标识)、title(标题)、description(描述)、completed(完成状态)、priority(优先级)、dueDate(截止日期)、createdAt(创建时间),7 个字段完整支撑待办项的展示、状态、时效管理;priority采用联合类型(low/medium/high)、completed采用布尔类型,通过 TypeScript 强类型约束避免非法数据录入,为跨端数据一致性提供底层保障。 - 多层级状态设计:
- 核心数据状态:
todos管理待办项数组,初始值预置 5 个覆盖不同优先级、完成状态的待办项,模拟真实业务场景; - 表单交互状态:
showAddForm控制添加表单的显隐,newTodoTitle/newTodoDescription等管理表单输入值,newTodoPriority限定优先级选择范围,形成完整的表单状态闭环; - 状态更新策略:所有状态更新均遵循 React 不可变数据原则(如
setTodos([newTodo, ...todos])、map/filter操作原数组),避免直接修改数据导致的状态不一致,也为跨端复用提供无副作用的纯逻辑资产。
- 核心数据状态:
- 核心业务逻辑:封装
addTodo(添加待办)、toggleComplete(切换完成状态)、deleteTodo(删除待办)、resetForm(重置表单)等纯函数,每个函数职责单一——addTodo包含表单校验、数据构造、状态更新、反馈提示全流程,deleteTodo封装确认弹窗逻辑,toggleComplete仅修改目标项的completed状态,这种模块化的逻辑封装大幅提升跨端复用效率。
列表渲染优化与视觉状态可视化
React Native 端采用 FlatList 替代基础 ScrollView 实现待办列表渲染,结合“状态驱动样式”实现优先级、完成状态的可视化,兼顾性能与体验:
- 高性能列表渲染:
- 选用
FlatList而非map遍历View,利用其“懒加载、复用单元格、减少重绘”的特性,优化长列表渲染性能; - 显式指定
keyExtractor={item => item.id},保证列表项的唯一性标识,避免列表更新时的不必要重渲染; - 关闭垂直滚动指示器(
showsVerticalScrollIndicator={false}),提升视觉简洁度。
- 选用
- 状态可视化设计:
- 完成状态映射:通过
completed状态动态控制待办项背景色(完成:#f1f5f9、未完成:#ffffff)、文本删除线(textDecorationLine: item.completed ? 'line-through' : 'none')、复选框图标(完成:✓、未完成:○),形成多维度的完成状态视觉反馈; - 优先级可视化:封装
getPriorityColor纯函数,实现“优先级 → 颜色”的映射(高:红色 #ef4444、中:橙色 #f59e0b、低:绿色 #10b981),并通过priorityBadge徽章组件展示优先级文本,徽章背景色采用“主色 + 20% 透明度”(如${getPriorityColor(item.priority)}20),既突出优先级又保证视觉柔和度; - 时效提示:截止日期文本采用红色(
#ef4444)高亮,强化时效感知,创建时间采用浅灰色弱化展示,形成信息层级。
- 完成状态映射:通过
表单封装
React Native 端将添加待办的表单封装为独立模块,通过条件渲染控制显隐,结合浮动操作按钮(FAB)实现“快速添加”的移动端交互范式:
- 表单结构设计:表单包含标题输入、描述多行输入、优先级选择、截止日期输入、操作按钮五大模块,采用
flexDirection: 'row'实现优先级与日期的横向布局,兼顾空间利用率与操作便捷性; - 优先级选择交互:通过三个
TouchableOpacity封装优先级选项,利用newTodoPriority === 'low' && styles.priorityOptionSelected实现选中状态的样式高亮,形成清晰的选择反馈; - 浮动操作按钮(FAB):固定在页面右下角的圆形按钮,点击切换
showAddForm状态,图标同步切换(+ / ✕),符合移动端“快捷操作”的交互习惯; - 表单校验与反馈:
addTodo函数首先校验标题是否为空,为空则弹出提示;添加成功后重置表单、隐藏表单、弹出成功提示,形成完整的交互闭环。
样式分层
该组件的样式设计遵循“功能分层 + 视觉层级”原则,将样式分为容器层、列表项层、表单层、辅助层四大类,每层样式职责单一,便于跨端迁移时逐层级等价转换:
- 容器层样式:
statsCard(统计卡片)、todosContainer(列表容器)、addForm(表单容器)统一采用borderRadius: 12、elevation: 1阴影,保证视觉风格一致性; - 列表项层样式:
todoItem采用borderRadius: 8圆角、marginBottom: 12间距,内部文本通过不同的fontSize/color区分层级(标题:16px 中粗、描述:14px 灰色、时效文本:12px); - 表单层样式:输入框采用
borderWidth: 1边框、borderRadius: 8圆角,按钮区分“取消(浅灰)”和“保存(蓝色)”,强化操作意图; - 辅助层样式:统计卡片采用横向布局展示“总计/已完成/待完成”数据,底部导航的
activeNavItem通过顶部 2px 蓝色边框标识当前选中项,符合移动端导航设计规范。
核心技术体系的等价映射
待办清单组件跨端适配的核心是“数据模型 100% 复用、状态管理等价转换、列表渲染语义一致、表单交互复刻”,React Native 与鸿蒙 ArkTS 的核心能力可实现精准映射,以下是关键技术点的等价转换:
| React Native 核心能力 | 鸿蒙 ArkTS 等价实现 | 待办组件适配要点 |
|---|---|---|
| TypeScript 类型定义(TodoItem) | TypeScript 类型定义(TodoItem) | 完全复用类型定义,保证待办项数据结构一致性 |
useState 状态管理 |
@State 装饰器 |
多层级状态一一映射,更新逻辑语义等价 |
FlatList 列表渲染 |
List 组件 |
懒加载、key 标识、渲染函数等价复用 |
TouchableOpacity 点击交互 |
Gesture 手势/Button 组件 |
onPress → onTap/onClick,交互逻辑一致 |
| 条件渲染(表单显隐) | if 条件语句 |
复用 showAddForm 控制表单显隐逻辑 |
TextInput 输入框 |
TextInput 组件 |
单行/多行输入、占位符、值绑定等价映射 |
Alert.alert 弹窗反馈 |
AlertDialog.show |
确认弹窗、提示弹窗内容完全复用 |
StyleSheet.create 样式管理 |
内联样式/样式常量 | 样式属性等价映射(backgroundColor/borderRadius 等) |
| FAB 浮动按钮 | Position.Fixed + 圆形组件 |
固定定位、点击交互、图标切换逻辑一致 |
随着移动办公需求的提升,此类任务管理组件将成为生产力应用的核心模块。其技术实现的质量和跨端一致性,将直接影响产品的使用效率和用户满意度。
真实演示案例代码:
// app.tsx
import React, { useState } from 'react';
import { SafeAreaView, View, Text, StyleSheet, TouchableOpacity, ScrollView, Dimensions, Alert, FlatList, TextInput } from 'react-native';
// Base64 图标库
const ICONS_BASE64 = {
add: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
edit: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
delete: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
check: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
close: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
settings: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
filter: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
home: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
};
const { width, height } = Dimensions.get('window');
// 待办事项类型
type TodoItem = {
id: string;
title: string;
description: string;
completed: boolean;
priority: 'low' | 'medium' | 'high';
dueDate: string;
createdAt: string;
};
const TodoListWithFAB: React.FC = () => {
const [todos, setTodos] = useState<TodoItem[]>([
{
id: '1',
title: '完成项目设计稿',
description: '完成新项目的UI设计和交互原型',
completed: false,
priority: 'high',
dueDate: '2023-06-10',
createdAt: '2023-06-01'
},
{
id: '2',
title: '购买生活用品',
description: '去超市购买日用品和食物',
completed: true,
priority: 'medium',
dueDate: '2023-06-05',
createdAt: '2023-05-30'
},
{
id: '3',
title: '预约医生',
description: '预约年度体检',
completed: false,
priority: 'high',
dueDate: '2023-06-15',
createdAt: '2023-06-02'
},
{
id: '4',
title: '学习React Native',
description: '完成教程第三章的学习',
completed: false,
priority: 'medium',
dueDate: '2023-06-20',
createdAt: '2023-06-03'
},
{
id: '5',
title: '整理衣柜',
description: '整理春夏衣物,准备收纳',
completed: false,
priority: 'low',
dueDate: '2023-06-25',
createdAt: '2023-06-01'
},
]);
const [showAddForm, setShowAddForm] = useState<boolean>(false);
const [newTodoTitle, setNewTodoTitle] = useState<string>('');
const [newTodoDescription, setNewTodoDescription] = useState<string>('');
const [newTodoPriority, setNewTodoPriority] = useState<'low' | 'medium' | 'high'>('medium');
const [newTodoDueDate, setNewTodoDueDate] = useState<string>('2023-06-10');
// 添加新待办事项
const addTodo = () => {
if (!newTodoTitle.trim()) {
Alert.alert('提示', '请输入待办事项标题');
return;
}
const newTodo: TodoItem = {
id: `${todos.length + 1}`,
title: newTodoTitle,
description: newTodoDescription,
completed: false,
priority: newTodoPriority,
dueDate: newTodoDueDate,
createdAt: new Date().toISOString().split('T')[0]
};
setTodos([newTodo, ...todos]);
resetForm();
setShowAddForm(false);
Alert.alert('成功', '待办事项已添加');
};
// 重置表单
const resetForm = () => {
setNewTodoTitle('');
setNewTodoDescription('');
setNewTodoPriority('medium');
setNewTodoDueDate('2023-06-10');
};
// 切换完成状态
const toggleComplete = (id: string) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
// 删除待办事项
const deleteTodo = (id: string) => {
Alert.alert(
'确认删除',
'确定要删除这个待办事项吗?',
[
{ text: '取消', style: 'cancel' },
{
text: '删除',
style: 'destructive',
onPress: () => setTodos(todos.filter(todo => todo.id !== id))
}
]
);
};
// 获取优先级颜色
const getPriorityColor = (priority: string): string => {
switch (priority) {
case 'high': return '#ef4444'; // 红色
case 'medium': return '#f59e0b'; // 橙色
case 'low': return '#10b981'; // 绿色
default: return '#64748b'; // 灰色
}
};
// 渲染待办事项项
const renderTodoItem = ({ item }: { item: TodoItem }) => (
<View style={[
styles.todoItem,
{ backgroundColor: item.completed ? '#f1f5f9' : '#ffffff' }
]}>
<TouchableOpacity
style={styles.todoCheckbox}
onPress={() => toggleComplete(item.id)}
>
<Text style={[
styles.checkboxIcon,
{ color: item.completed ? '#10b981' : '#94a3b8' }
]}>
{item.completed ? '✓' : '○'}
</Text>
</TouchableOpacity>
<View style={styles.todoContent}>
<View style={styles.todoHeader}>
<Text style={[
styles.todoTitle,
{ textDecorationLine: item.completed ? 'line-through' : 'none' }
]}>
{item.title}
</Text>
<View style={[
styles.priorityBadge,
{ backgroundColor: `${getPriorityColor(item.priority)}20`, borderColor: getPriorityColor(item.priority) }
]}>
<Text style={[
styles.priorityText,
{ color: getPriorityColor(item.priority) }
]}>
{item.priority === 'high' ? '高' : item.priority === 'medium' ? '中' : '低'}
</Text>
</View>
</View>
<Text style={[
styles.todoDescription,
{ textDecorationLine: item.completed ? 'line-through' : 'none' }
]}>
{item.description}
</Text>
<View style={styles.todoMeta}>
<Text style={styles.dueDate}>截止: {item.dueDate}</Text>
<Text style={styles.createdAt}>{item.createdAt}</Text>
</View>
</View>
<TouchableOpacity
style={styles.deleteButton}
onPress={() => deleteTodo(item.id)}
>
<Text style={styles.deleteIcon}>✕</Text>
</TouchableOpacity>
</View>
);
return (
<SafeAreaView style={styles.container}>
{/* 头部 */}
<View style={styles.header}>
<Text style={styles.title}>我的待办清单</Text>
<Text style={styles.subtitle}>{todos.filter(t => !t.completed).length} 个待办</Text>
</View>
<ScrollView style={styles.content}>
{/* 统计卡片 */}
<View style={styles.statsCard}>
<View style={styles.statItem}>
<Text style={styles.statNumber}>{todos.length}</Text>
<Text style={styles.statLabel}>总计</Text>
</View>
<View style={styles.statItem}>
<Text style={styles.statNumber}>{todos.filter(t => t.completed).length}</Text>
<Text style={styles.statLabel}>已完成</Text>
</View>
<View style={styles.statItem}>
<Text style={styles.statNumber}>{todos.filter(t => !t.completed).length}</Text>
<Text style={styles.statLabel}>待完成</Text>
</View>
</View>
{/* 待办列表 */}
<View style={styles.todosContainer}>
<FlatList
data={todos}
renderItem={renderTodoItem}
keyExtractor={item => item.id}
showsVerticalScrollIndicator={false}
/>
</View>
{/* 添加表单 */}
{showAddForm && (
<View style={styles.addForm}>
<Text style={styles.addFormTitle}>添加新待办</Text>
<TextInput
style={styles.input}
placeholder="待办事项标题"
value={newTodoTitle}
onChangeText={setNewTodoTitle}
/>
<TextInput
style={[styles.input, styles.textArea]}
placeholder="描述(可选)"
value={newTodoDescription}
onChangeText={setNewTodoDescription}
multiline
/>
<View style={styles.formRow}>
<View style={styles.formGroup}>
<Text style={styles.label}>优先级</Text>
<View style={styles.priorityOptions}>
<TouchableOpacity
style={[
styles.priorityOption,
newTodoPriority === 'low' && styles.priorityOptionSelected
]}
onPress={() => setNewTodoPriority('low')}
>
<Text style={[
styles.priorityOptionText,
newTodoPriority === 'low' && styles.priorityOptionTextSelected
]}>低</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.priorityOption,
newTodoPriority === 'medium' && styles.priorityOptionSelected
]}
onPress={() => setNewTodoPriority('medium')}
>
<Text style={[
styles.priorityOptionText,
newTodoPriority === 'medium' && styles.priorityOptionTextSelected
]}>中</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.priorityOption,
newTodoPriority === 'high' && styles.priorityOptionSelected
]}
onPress={() => setNewTodoPriority('high')}
>
<Text style={[
styles.priorityOptionText,
newTodoPriority === 'high' && styles.priorityOptionTextSelected
]}>高</Text>
</TouchableOpacity>
</View>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>截止日期</Text>
<TextInput
style={styles.dateInput}
value={newTodoDueDate}
onChangeText={setNewTodoDueDate}
placeholder="YYYY-MM-DD"
/>
</View>
</View>
<View style={styles.formButtons}>
<TouchableOpacity
style={styles.cancelButton}
onPress={() => setShowAddForm(false)}
>
<Text style={styles.cancelButtonText}>取消</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.saveButton}
onPress={addTodo}
>
<Text style={styles.saveButtonText}>保存</Text>
</TouchableOpacity>
</View>
</View>
)}
{/* 使用说明 */}
<View style={styles.infoCard}>
<Text style={styles.infoTitle}>使用说明</Text>
<Text style={styles.infoText}>• 点击圆圈标记完成/未完成</Text>
<Text style={styles.infoText}>• 点击右上角×删除待办事项</Text>
<Text style={styles.infoText}>• 高优先级任务会用红色标识</Text>
<Text style={styles.infoText}>• 浮动按钮可快速添加新任务</Text>
</View>
</ScrollView>
{/* 浮动添加按钮 */}
<TouchableOpacity
style={styles.fab}
onPress={() => setShowAddForm(!showAddForm)}
>
<Text style={styles.fabIcon}>{showAddForm ? '✕' : '+'}</Text>
</TouchableOpacity>
{/* 底部导航 */}
<View style={styles.bottomNav}>
<TouchableOpacity
style={[styles.navItem, styles.activeNavItem]}
onPress={() => Alert.alert('首页')}
>
<Text style={styles.navIcon}>🏠</Text>
<Text style={styles.navText}>首页</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navItem}
onPress={() => Alert.alert('待办')}
>
<Text style={styles.navIcon}>📋</Text>
<Text style={styles.navText}>待办</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navItem}
onPress={() => Alert.alert('完成')}
>
<Text style={styles.navIcon}>✅</Text>
<Text style={styles.navText}>完成</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navItem}
onPress={() => Alert.alert('设置')}
>
<Text style={styles.navIcon}>⚙️</Text>
<Text style={styles.navText}>设置</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f8fafc',
},
header: {
padding: 20,
backgroundColor: '#ffffff',
borderBottomWidth: 1,
borderBottomColor: '#e2e8f0',
},
title: {
fontSize: 20,
fontWeight: 'bold',
color: '#1e293b',
marginBottom: 4,
},
subtitle: {
fontSize: 14,
color: '#64748b',
},
content: {
flex: 1,
padding: 16,
},
statsCard: {
backgroundColor: '#ffffff',
borderRadius: 12,
padding: 16,
flexDirection: 'row',
justifyContent: 'space-around',
marginBottom: 16,
elevation: 1,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.1,
shadowRadius: 2,
},
statItem: {
alignItems: 'center',
},
statNumber: {
fontSize: 18,
fontWeight: 'bold',
color: '#3b82f6',
},
statLabel: {
fontSize: 12,
color: '#64748b',
marginTop: 4,
},
todosContainer: {
marginBottom: 16,
},
todoItem: {
flexDirection: 'row',
alignItems: 'center',
padding: 16,
borderRadius: 8,
marginBottom: 12,
elevation: 1,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.1,
shadowRadius: 2,
},
todoCheckbox: {
marginRight: 12,
},
checkboxIcon: {
fontSize: 20,
fontWeight: 'bold',
},
todoContent: {
flex: 1,
},
todoHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 8,
},
todoTitle: {
fontSize: 16,
fontWeight: '500',
color: '#1e293b',
flex: 1,
},
priorityBadge: {
paddingHorizontal: 6,
paddingVertical: 2,
borderRadius: 4,
borderWidth: 1,
marginLeft: 8,
},
priorityText: {
fontSize: 10,
fontWeight: '500',
},
todoDescription: {
fontSize: 14,
color: '#64748b',
marginBottom: 8,
},
todoMeta: {
flexDirection: 'row',
justifyContent: 'space-between',
},
dueDate: {
fontSize: 12,
color: '#ef4444',
fontWeight: '500',
},
createdAt: {
fontSize: 12,
color: '#94a3b8',
},
deleteButton: {
padding: 4,
},
deleteIcon: {
fontSize: 18,
color: '#94a3b8',
},
addForm: {
backgroundColor: '#ffffff',
borderRadius: 12,
padding: 16,
marginBottom: 16,
elevation: 1,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.1,
shadowRadius: 2,
},
addFormTitle: {
fontSize: 18,
fontWeight: 'bold',
color: '#1e293b',
marginBottom: 16,
textAlign: 'center',
},
input: {
borderWidth: 1,
borderColor: '#cbd5e1',
borderRadius: 8,
padding: 12,
fontSize: 16,
color: '#1e293b',
marginBottom: 12,
},
textArea: {
height: 80,
textAlignVertical: 'top',
},
formRow: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 12,
},
formGroup: {
flex: 1,
marginRight: 8,
},
formGroup:lastChild: {
marginRight: 0,
},
label: {
fontSize: 14,
fontWeight: '500',
color: '#1e293b',
marginBottom: 6,
},
priorityOptions: {
flexDirection: 'row',
},
priorityOption: {
flex: 1,
padding: 8,
borderWidth: 1,
borderColor: '#cbd5e1',
alignItems: 'center',
backgroundColor: '#f8fafc',
},
priorityOption:firstChild: {
borderTopLeftRadius: 8,
borderBottomLeftRadius: 8,
},
priorityOption:lastChild: {
borderTopRightRadius: 8,
borderBottomRightRadius: 8,
},
priorityOptionSelected: {
backgroundColor: '#dbeafe',
borderColor: '#3b82f6',
},
priorityOptionText: {
fontSize: 12,
color: '#64748b',
textAlign: 'center',
},
priorityOptionTextSelected: {
color: '#1e40af',
fontWeight: '500',
},
dateInput: {
borderWidth: 1,
borderColor: '#cbd5e1',
borderRadius: 8,
padding: 12,
fontSize: 16,
color: '#1e293b',
},
formButtons: {
flexDirection: 'row',
justifyContent: 'space-between',
},
cancelButton: {
flex: 1,
padding: 12,
borderRadius: 8,
borderWidth: 1,
borderColor: '#cbd5e1',
alignItems: 'center',
marginRight: 8,
},
cancelButtonText: {
color: '#64748b',
fontWeight: '500',
},
saveButton: {
flex: 1,
padding: 12,
borderRadius: 8,
backgroundColor: '#3b82f6',
alignItems: 'center',
marginLeft: 8,
},
saveButtonText: {
color: '#ffffff',
fontWeight: '500',
},
infoCard: {
backgroundColor: '#ffffff',
borderRadius: 12,
padding: 16,
elevation: 1,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.1,
shadowRadius: 2,
},
infoTitle: {
fontSize: 16,
fontWeight: 'bold',
color: '#1e293b',
marginBottom: 12,
},
infoText: {
fontSize: 14,
color: '#64748b',
lineHeight: 22,
marginBottom: 8,
},
fab: {
position: 'absolute',
right: 20,
bottom: 80,
width: 56,
height: 56,
borderRadius: 28,
backgroundColor: '#3b82f6',
alignItems: 'center',
justifyContent: 'center',
elevation: 8,
shadowColor: '#000',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 6,
},
fabIcon: {
fontSize: 24,
color: '#ffffff',
fontWeight: 'bold',
},
bottomNav: {
flexDirection: 'row',
justifyContent: 'space-around',
backgroundColor: '#ffffff',
borderTopWidth: 1,
borderTopColor: '#e2e8f0',
paddingVertical: 12,
},
navItem: {
alignItems: 'center',
flex: 1,
},
activeNavItem: {
paddingTop: 4,
borderTopWidth: 2,
borderTopColor: '#3b82f6',
},
navIcon: {
fontSize: 20,
color: '#94a3b8',
marginBottom: 4,
},
activeNavIcon: {
color: '#3b82f6',
},
navText: {
fontSize: 12,
color: '#94a3b8',
},
activeNavText: {
color: '#3b82f6',
},
});
export default TodoListWithFAB;

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

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

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

本文介绍了一个跨平台待办事项列表组件的设计与实现,重点分析了其在React Native和HarmonyOS上的技术适配方案。组件采用模块化设计,包含列表展示、表单交互和状态管理三大核心功能。通过TypeScript强类型定义确保数据一致性,使用useState实现响应式状态管理,并优化列表渲染性能。在UI层面,组件实现了优先级可视化、完成状态反馈等交互细节,采用浮动操作按钮提升移动端操作体验。文章还详细阐述了React Native组件向HarmonyOS ArkUI迁移的技术路径,包括状态管理映射、组件等效替换等关键问题,为跨端开发提供了实践参考。
欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。
更多推荐

所有评论(0)