React Native鸿蒙跨平台通过 TouchableOpacity 包裹实现点击交互,适合作为模块化功能中心的容器
技术栈深度解析
这段代码展示了一个基于React Native的净水机管理应用,其技术栈涵盖了前端开发的多个关键领域。从框架选择到组件设计,再到状态管理和样式处理,每一个环节都体现了现代移动端开发的典型实践。
核心框架与开发语言
项目采用了React Native作为基础框架,这是一个广泛用于构建跨平台移动应用的工具链。React Native的优势在于能够通过JavaScript和React的语法直接调用原生组件,从而实现接近原生应用的性能表现。代码中大量使用了React Native提供的核心组件,如SafeAreaView、ScrollView和TouchableOpacity,这些组件不仅保证了UI的流畅性,还提供了良好的用户体验。
TypeScript作为开发语言为项目带来了静态类型检查的能力。通过定义FilterElement和DeviceStatus等接口类型,代码的可读性和可维护性得到了显著提升。TypeScript的类型系统帮助开发者在编码阶段就能发现潜在的错误,减少了运行时的问题。
组件化设计与状态管理
整个应用采用了典型的组件化设计模式。例如:
FilterElementCard组件专门用于展示滤芯的状态信息DeviceStatusCard则负责显示设备的实时数据
这种模块化的设计使得每个组件的职责单一,便于复用和测试。
状态管理方面,项目使用了React的useState钩子来管理局部状态。虽然这是一个相对简单的状态管理方案,但对于当前应用的规模来说已经足够。设备状态和滤芯数据通过useState进行初始化,并在组件之间通过props传递。这种设计在小型应用中非常高效,避免了引入复杂状态管理库(如Redux)带来的额外开销。
样式与布局处理
样式处理采用了React Native的StyleSheet模块,这是一种类似于CSS但针对移动端优化的样式方案。代码中通过StyleSheet.create集中定义所有样式规则,这种做法不仅提高了样式的复用性,还能通过静态分析工具进行优化。
动态样式的实现尤为巧妙:
const getProgressColor = () => {
if (element.remainingDays <= 0) return '#ef4444'; // 红色
if (element.remainingDays <= 30) return '#f59e0b'; // 黄色
return '#10b981'; // 绿色
};
布局方面,Flexbox是主要的布局模型。通过flexDirection、justifyContent和alignItems等属性,实现了复杂的响应式布局。例如功能卡片采用了flexWrap: 'wrap'来实现流式布局,确保在不同屏幕尺寸下都能合理排列。
交互与用户提示
用户交互部分主要通过TouchableOpacity和Alert实现:
TouchableOpacity为按钮和可点击区域提供了标准的触摸反馈效果Alert则用于显示重要的操作确认提示
例如更换滤芯时的确认对话框:
Alert.alert(
'滤芯更换',
`确定要更换${filterElements.find(f => f.id === id)?.name}吗?`,
[
{ text: '取消', style: 'cancel' },
{
text: '确定',
onPress: () => Alert.alert('提示', '请按照说明书进行滤芯更换操作')
}
]
);
图标与视觉设计
图标系统采用了Unicode符号作为解决方案,这是一种轻量级的实现方式。所有图标被集中定义在ICONS常量中:
const ICONS = {
water: '💧',
filter: '🔧',
power: '⚡',
timer: '⏱️',
settings: '⚙️',
warning: '⚠️',
info: 'ℹ️',
check: '✅',
};
视觉设计上,卡片式布局和阴影效果的应用增强了界面的层次感。通过elevation和shadow属性实现的卡片阴影,在鸿蒙上都能呈现一致的视觉效果。
总结
整体来看,这个项目展示了如何用React Native构建一个结构清晰、性能良好的移动应用。技术栈的选择恰到好处,既没有过度设计引入不必要的复杂性,又保证了代码的可扩展性和可维护性。
导言
这段 React Native + TypeScript 的代码实现了一个“净水机管理”页面,整体采用函数式组件与本地状态的轻量组合方案。它的架构思路是将领域模型用类型显式建模,再通过若干卡片化 UI 组件组合出页面,交互以 Alert 作为占位,适用于展示与原型阶段。下面按代码结构逐段解读,兼顾实现细节与可扩展性考量。
模块与依赖
import React, { useState } from 'react';
import { SafeAreaView, View, Text, StyleSheet, TouchableOpacity, ScrollView, Dimensions, Alert } from 'react-native';
使用 React 的函数式组件能力与 useState 管理本地状态;UI 构建依赖 React Native 核心组件。SafeAreaView 负责在异形屏上保证内容安全区域,ScrollView 处理纵向滚动,Alert 承担轻量对话框交互。当前没有引入第三方库,保证跨平台一致性与依赖最小化。
图标与屏幕尺寸
const ICONS = {
water: '💧',
filter: '🔧',
power: '⚡',
timer: '⏱️',
settings: '⚙️',
warning: '⚠️',
info: 'ℹ️',
check: '✅',
};
const { width } = Dimensions.get('window');
图标用 emoji 直出,避免额外图标库,但需注意部分设备或字体环境可能导致表现差异。通过 Dimensions 读取设备宽度,用于后续网格卡片宽度计算,实现简易响应式布局。若考虑横竖屏切换,建议订阅维度变化并触发重渲染。
领域类型建模
type FilterElement = {
id: number;
name: string;
installedDate: string;
lifeSpan: number; // 天数
remainingDays: number;
status: 'normal' | 'warning' | 'replace';
};
type DeviceStatus = {
waterQuality: number; // 0-100
temperature: number; // 摄氏度
pressure: number; // bar
flowRate: number; // L/min
};
显式的 TypeScript 类型定义清晰界定领域模型:滤芯关注寿命与剩余天数,设备状态涵盖水质、温度、压力、流量。类型约束使得组件间数据契约清晰,也为接入后端接口与校验提供了稳固基础。值得注意的是 UI 展示逻辑主要由 remainingDays 驱动,status 字段目前未参与显示,后续可通过派生函数统一两者。
组件:FilterElementCard
const FilterElementCard = ({
element,
onReplace
}: {
element: FilterElement;
onReplace: (id: number) => void
}) => {
const getProgressColor = () => {
if (element.remainingDays <= 0) return '#ef4444'; // 红色
if (element.remainingDays <= 30) return '#f59e0b'; // 黄色
return '#10b981'; // 绿色
};
const getProgressPercentage = () => {
const usedDays = element.lifeSpan - element.remainingDays;
return Math.min(100, Math.max(0, (usedDays / element.lifeSpan) * 100));
};
return (
<View style={styles.filterCard}>
<View style={styles.filterHeader}>
<Text style={styles.filterIcon}>{ICONS.filter}</Text>
<Text style={styles.filterName}>{element.name}</Text>
<Text style={[
styles.filterStatus,
element.remainingDays <= 0 && styles.statusReplace,
element.remainingDays > 0 && element.remainingDays <= 30 && styles.statusWarning
]}>
{element.remainingDays <= 0 ? '需更换' : element.remainingDays <= 30 ? '警告' : '正常'}
</Text>
</View>
<View style={styles.filterProgressContainer}>
<View style={styles.filterProgressBackground}>
<View
style={[
styles.filterProgressFill,
{ backgroundColor: getProgressColor(), width: `${getProgressPercentage()}%` }
]}
/>
</View>
<Text style={styles.filterProgressText}>
{element.remainingDays > 0 ? `${element.remainingDays}天后更换` : '立即更换'}
</Text>
</View>
<View style={styles.filterDetails}>
<Text style={styles.filterDetailText}>安装日期: {element.installedDate}</Text>
<Text style={styles.filterDetailText}>使用寿命: {element.lifeSpan}天</Text>
</View>
<TouchableOpacity
style={[
styles.replaceButton,
element.remainingDays <= 0 && styles.replaceButtonUrgent
]}
onPress={() => onReplace(element.id)}
>
<Text style={styles.replaceButtonText}>
{element.remainingDays <= 0 ? `${ICONS.warning} 立即更换` : '更换滤芯'}
</Text>
</TouchableOpacity>
</View>
);
};
卡片以“数据驱动 UI”的方式呈现滤芯状态。进度条颜色与宽度分别由剩余天数与使用比例推导,逻辑上通过最小/最大值确保百分比边界。状态徽标与按钮颜色在临界条件下切换,形成明确的语义色提示(绿/黄/红)。这段实现让用户无需阅读说明即可直观理解寿命阶段。若后续优化性能,可将 getProgressColor 和 getProgressPercentage 用 useMemo 包裹,减少重复计算。
组件:DeviceStatusCard
const DeviceStatusCard = ({ status }: { status: DeviceStatus }) => {
return (
<View style={styles.deviceStatusCard}>
<Text style={styles.deviceStatusTitle}>设备状态</Text>
<View style={styles.statusRow}>
<View style={styles.statusItem}>
<Text style={styles.statusIcon}>{ICONS.water}</Text>
<Text style={styles.statusLabel}>水质</Text>
<Text style={styles.statusValue}>{status.waterQuality}%</Text>
</View>
<View style={styles.statusItem}>
<Text style={styles.statusIcon}>{ICONS.power}</Text>
<Text style={styles.statusLabel}>温度</Text>
<Text style={styles.statusValue}>{status.temperature}°C</Text>
</View>
</View>
<View style={styles.statusRow}>
<View style={styles.statusItem}>
<Text style={styles.statusIcon}>{ICONS.timer}</Text>
<Text style={styles.statusLabel}>压力</Text>
<Text style={styles.statusValue}>{status.pressure} bar</Text>
</View>
<View style={styles.statusItem}>
<Text style={styles.statusIcon}>{ICONS.filter}</Text>
<Text style={styles.statusLabel}>流量</Text>
<Text style={styles.statusValue}>{status.flowRate} L/min</Text>
</View>
</View>
</View>
);
};
设备状态以两行两列网格呈现四项关键指标,搭配轻量 emoji 图标与语义标签,形成信息密度适中且易读的监控视图。布局通过 flex 属性保证自适应伸缩,适合不同尺寸屏幕。异常态提示可在此基础上延伸,例如当水质低于阈值时增加醒目色或图形标记。
组件:FeatureCard
const FeatureCard = ({
title,
icon,
description,
onPress
}: {
title: string;
icon: string;
description: string;
onPress: () => void
}) => {
return (
<TouchableOpacity style={styles.featureCard} onPress={onPress}>
<Text style={styles.featureIcon}>{icon}</Text>
<Text style={styles.featureTitle}>{title}</Text>
<Text style={styles.featureDescription}>{description}</Text>
</TouchableOpacity>
);
};
功能入口的复用卡片,包含图标、标题、描述三要素。通过 TouchableOpacity 包裹实现点击交互,适合作为模块化功能中心的容器。与 Dimensions 结合的 width 计算让卡片在网格中保持均匀分布,保障视觉秩序。
页面:WaterPurifierApp
const WaterPurifierApp: React.FC = () => {
const [deviceStatus] = useState<DeviceStatus>({
waterQuality: 98,
temperature: 22,
pressure: 3.2,
flowRate: 1.5,
});
const [filterElements] = useState<FilterElement[]>([
{ id: 1, name: 'PP棉滤芯', installedDate: '2023-01-15', lifeSpan: 180, remainingDays: 45, status: 'normal' },
{ id: 2, name: '活性炭滤芯', installedDate: '2023-01-15', lifeSpan: 365, remainingDays: 120, status: 'normal' },
{ id: 3, name: 'RO反渗透膜', installedDate: '2023-01-15', lifeSpan: 730, remainingDays: 15, status: 'warning' },
{ id: 4, name: '后置活性炭', installedDate: '2023-01-15', lifeSpan: 365, remainingDays: 0, status: 'replace' },
]);
const handleReplaceFilter = (id: number) => {
Alert.alert(
'滤芯更换',
`确定要更换${filterElements.find(f => f.id === id)?.name}吗?`,
[
{ text: '取消', style: 'cancel' },
{
text: '确定',
onPress: () => Alert.alert('提示', '请按照说明书进行滤芯更换操作')
}
]
);
};
const handleFeaturePress = (feature: string) => {
Alert.alert('功能', `您点击了${feature}功能`);
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.header}>
<Text style={styles.title}>净水机管理</Text>
<TouchableOpacity style={styles.settingsButton}>
<Text style={styles.settingsIcon}>{ICONS.settings}</Text>
</TouchableOpacity>
</View>
<ScrollView style={styles.content}>
<DeviceStatusCard status={deviceStatus} />
<Text style={styles.sectionTitle}>滤芯状态</Text>
{filterElements.map(element => (
<FilterElementCard
key={element.id}
element={element}
onReplace={handleReplaceFilter}
/>
))}
<Text style={styles.sectionTitle}>功能中心</Text>
<View style={styles.featureGrid}>
<FeatureCard
title="滤芯记录"
icon={ICONS.filter}
description="查看历史更换记录"
onPress={() => handleFeaturePress('滤芯记录')}
/>
<FeatureCard
title="水质检测"
icon={ICONS.water}
description="实时监测水质状况"
onPress={() => handleFeaturePress('水质检测')}
/>
<FeatureCard
title="定时提醒"
icon={ICONS.timer}
description="设置定期维护提醒"
onPress={() => handleFeaturePress('定时提醒')}
/>
<FeatureCard
title="使用指南"
icon={ICONS.info}
description="查看设备使用说明"
onPress={() => handleFeaturePress('使用指南')}
/>
</View>
<Text style={styles.sectionTitle}>水质标准</Text>
<View style={styles.waterQualityGuide}>
<View style={styles.qualityItem}>
<Text style={[styles.qualityIcon, { color: '#10b981' }]}>{ICONS.check}</Text>
<Text style={styles.qualityText}>优良 (95-100%) - 直接饮用</Text>
</View>
<View style={styles.qualityItem}>
<Text style={[styles.qualityIcon, { color: '#f59e0b' }]}>{ICONS.warning}</Text>
<Text style={styles.qualityText}>一般 (80-94%) - 建议烧开</Text>
</View>
<View style={styles.qualityItem}>
<Text style={[styles.qualityIcon, { color: '#ef4444' }]}>{ICONS.warning}</Text>
<Text style={styles.qualityText}>较差 (0-79%) - 不建议饮用</Text>
</View>
</View>
</ScrollView>
<View style={styles.bottomNav}>
<TouchableOpacity style={styles.navItem}>
<Text style={styles.navIcon}>{ICONS.water}</Text>
<Text style={styles.navText}>水质</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.navItem}>
<Text style={styles.navIcon}>{ICONS.filter}</Text>
<Text style={styles.navText}>滤芯</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.navItem, styles.activeNavItem]}>
<Text style={styles.navIcon}>{ICONS.info}</Text>
<Text style={styles.navText}>设备</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.navItem}>
<Text style={styles.navIcon}>{ICONS.settings}</Text>
<Text style={styles.navText}>设置</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
};
页面由三大区域构成:头部展示标题与设置入口;主体滚动区域包含设备状态、滤芯列表、功能中心与水质标准说明;底部导航保持固定以承载分区切换的视觉语言。交互以 Alert 为占位,点击滤芯更换进行二次确认,点击功能卡片提示已点击的功能项。底部导航的选中态通过样式加粗底边实现,代码中已定义 activeNavIcon/activeNavText,可进一步应用到选中项以增强可视反馈。
导出声明
export default WaterPurifierApp;
默认导出页面组件,便于在路由或入口文件中直接引用。若与导航体系(如 React Navigation)整合,可将该组件作为栈或底部 Tab 的一页。
实践建议与可扩展性
实际工程推进时,可以考虑几点增强:将滤芯状态由一个派生函数统一计算,避免 remainingDays 与 status 双维护;为进度与颜色计算使用 useMemo 优化;将 Alert 行为替换为真正的流程(导航到更换向导、状态更新与持久化);将滤芯列表换为 FlatList 提升长列表性能;将底部导航接入路由,应用 activeNavIcon/activeNavText;在 DeviceStatusCard 中为异常值添加醒目提示与动画过渡;抽取所有文案为资源字典以便国际化。通过这些演进,当前的原型能自然过渡到可发布的生产界面,同时保留良好的组件化与可维护性。
完整代码演示:
// app.tsx
import React, { useState } from 'react';
import { SafeAreaView, View, Text, StyleSheet, TouchableOpacity, ScrollView, Dimensions, Alert } from 'react-native';
// 图标库
const ICONS = {
water: '💧',
filter: '🔧',
power: '⚡',
timer: '⏱️',
settings: '⚙️',
warning: '⚠️',
info: 'ℹ️',
check: '✅',
};
const { width } = Dimensions.get('window');
// 滤芯信息类型
type FilterElement = {
id: number;
name: string;
installedDate: string;
lifeSpan: number; // 天数
remainingDays: number;
status: 'normal' | 'warning' | 'replace';
};
// 设备状态类型
type DeviceStatus = {
waterQuality: number; // 0-100
temperature: number; // 摄氏度
pressure: number; // bar
flowRate: number; // L/min
};
// 滤芯组件
const FilterElementCard = ({
element,
onReplace
}: {
element: FilterElement;
onReplace: (id: number) => void
}) => {
const getProgressColor = () => {
if (element.remainingDays <= 0) return '#ef4444'; // 红色
if (element.remainingDays <= 30) return '#f59e0b'; // 黄色
return '#10b981'; // 绿色
};
const getProgressPercentage = () => {
const usedDays = element.lifeSpan - element.remainingDays;
return Math.min(100, Math.max(0, (usedDays / element.lifeSpan) * 100));
};
return (
<View style={styles.filterCard}>
<View style={styles.filterHeader}>
<Text style={styles.filterIcon}>{ICONS.filter}</Text>
<Text style={styles.filterName}>{element.name}</Text>
<Text style={[
styles.filterStatus,
element.remainingDays <= 0 && styles.statusReplace,
element.remainingDays > 0 && element.remainingDays <= 30 && styles.statusWarning
]}>
{element.remainingDays <= 0 ? '需更换' : element.remainingDays <= 30 ? '警告' : '正常'}
</Text>
</View>
<View style={styles.filterProgressContainer}>
<View style={styles.filterProgressBackground}>
<View
style={[
styles.filterProgressFill,
{ backgroundColor: getProgressColor(), width: `${getProgressPercentage()}%` }
]}
/>
</View>
<Text style={styles.filterProgressText}>
{element.remainingDays > 0 ? `${element.remainingDays}天后更换` : '立即更换'}
</Text>
</View>
<View style={styles.filterDetails}>
<Text style={styles.filterDetailText}>安装日期: {element.installedDate}</Text>
<Text style={styles.filterDetailText}>使用寿命: {element.lifeSpan}天</Text>
</View>
<TouchableOpacity
style={[
styles.replaceButton,
element.remainingDays <= 0 && styles.replaceButtonUrgent
]}
onPress={() => onReplace(element.id)}
>
<Text style={styles.replaceButtonText}>
{element.remainingDays <= 0 ? `${ICONS.warning} 立即更换` : '更换滤芯'}
</Text>
</TouchableOpacity>
</View>
);
};
// 设备状态卡片
const DeviceStatusCard = ({ status }: { status: DeviceStatus }) => {
return (
<View style={styles.deviceStatusCard}>
<Text style={styles.deviceStatusTitle}>设备状态</Text>
<View style={styles.statusRow}>
<View style={styles.statusItem}>
<Text style={styles.statusIcon}>{ICONS.water}</Text>
<Text style={styles.statusLabel}>水质</Text>
<Text style={styles.statusValue}>{status.waterQuality}%</Text>
</View>
<View style={styles.statusItem}>
<Text style={styles.statusIcon}>{ICONS.power}</Text>
<Text style={styles.statusLabel}>温度</Text>
<Text style={styles.statusValue}>{status.temperature}°C</Text>
</View>
</View>
<View style={styles.statusRow}>
<View style={styles.statusItem}>
<Text style={styles.statusIcon}>{ICONS.timer}</Text>
<Text style={styles.statusLabel}>压力</Text>
<Text style={styles.statusValue}>{status.pressure} bar</Text>
</View>
<View style={styles.statusItem}>
<Text style={styles.statusIcon}>{ICONS.filter}</Text>
<Text style={styles.statusLabel}>流量</Text>
<Text style={styles.statusValue}>{status.flowRate} L/min</Text>
</View>
</View>
</View>
);
};
// 功能卡片
const FeatureCard = ({
title,
icon,
description,
onPress
}: {
title: string;
icon: string;
description: string;
onPress: () => void
}) => {
return (
<TouchableOpacity style={styles.featureCard} onPress={onPress}>
<Text style={styles.featureIcon}>{icon}</Text>
<Text style={styles.featureTitle}>{title}</Text>
<Text style={styles.featureDescription}>{description}</Text>
</TouchableOpacity>
);
};
// 主页面组件
const WaterPurifierApp: React.FC = () => {
const [deviceStatus] = useState<DeviceStatus>({
waterQuality: 98,
temperature: 22,
pressure: 3.2,
flowRate: 1.5,
});
const [filterElements] = useState<FilterElement[]>([
{ id: 1, name: 'PP棉滤芯', installedDate: '2023-01-15', lifeSpan: 180, remainingDays: 45, status: 'normal' },
{ id: 2, name: '活性炭滤芯', installedDate: '2023-01-15', lifeSpan: 365, remainingDays: 120, status: 'normal' },
{ id: 3, name: 'RO反渗透膜', installedDate: '2023-01-15', lifeSpan: 730, remainingDays: 15, status: 'warning' },
{ id: 4, name: '后置活性炭', installedDate: '2023-01-15', lifeSpan: 365, remainingDays: 0, status: 'replace' },
]);
const handleReplaceFilter = (id: number) => {
Alert.alert(
'滤芯更换',
`确定要更换${filterElements.find(f => f.id === id)?.name}吗?`,
[
{ text: '取消', style: 'cancel' },
{
text: '确定',
onPress: () => Alert.alert('提示', '请按照说明书进行滤芯更换操作')
}
]
);
};
const handleFeaturePress = (feature: string) => {
Alert.alert('功能', `您点击了${feature}功能`);
};
return (
<SafeAreaView style={styles.container}>
{/* 头部 */}
<View style={styles.header}>
<Text style={styles.title}>净水机管理</Text>
<TouchableOpacity style={styles.settingsButton}>
<Text style={styles.settingsIcon}>{ICONS.settings}</Text>
</TouchableOpacity>
</View>
{/* 主内容 */}
<ScrollView style={styles.content}>
{/* 设备状态 */}
<DeviceStatusCard status={deviceStatus} />
{/* 滤芯状态 */}
<Text style={styles.sectionTitle}>滤芯状态</Text>
{filterElements.map(element => (
<FilterElementCard
key={element.id}
element={element}
onReplace={handleReplaceFilter}
/>
))}
{/* 功能卡片 */}
<Text style={styles.sectionTitle}>功能中心</Text>
<View style={styles.featureGrid}>
<FeatureCard
title="滤芯记录"
icon={ICONS.filter}
description="查看历史更换记录"
onPress={() => handleFeaturePress('滤芯记录')}
/>
<FeatureCard
title="水质检测"
icon={ICONS.water}
description="实时监测水质状况"
onPress={() => handleFeaturePress('水质检测')}
/>
<FeatureCard
title="定时提醒"
icon={ICONS.timer}
description="设置定期维护提醒"
onPress={() => handleFeaturePress('定时提醒')}
/>
<FeatureCard
title="使用指南"
icon={ICONS.info}
description="查看设备使用说明"
onPress={() => handleFeaturePress('使用指南')}
/>
</View>
{/* 水质说明 */}
<Text style={styles.sectionTitle}>水质标准</Text>
<View style={styles.waterQualityGuide}>
<View style={styles.qualityItem}>
<Text style={[styles.qualityIcon, { color: '#10b981' }]}>{ICONS.check}</Text>
<Text style={styles.qualityText}>优良 (95-100%) - 直接饮用</Text>
</View>
<View style={styles.qualityItem}>
<Text style={[styles.qualityIcon, { color: '#f59e0b' }]}>{ICONS.warning}</Text>
<Text style={styles.qualityText}>一般 (80-94%) - 建议烧开</Text>
</View>
<View style={styles.qualityItem}>
<Text style={[styles.qualityIcon, { color: '#ef4444' }]}>{ICONS.warning}</Text>
<Text style={styles.qualityText}>较差 (0-79%) - 不建议饮用</Text>
</View>
</View>
</ScrollView>
{/* 底部导航 */}
<View style={styles.bottomNav}>
<TouchableOpacity style={styles.navItem}>
<Text style={styles.navIcon}>{ICONS.water}</Text>
<Text style={styles.navText}>水质</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.navItem}>
<Text style={styles.navIcon}>{ICONS.filter}</Text>
<Text style={styles.navText}>滤芯</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.navItem, styles.activeNavItem]}>
<Text style={styles.navIcon}>{ICONS.info}</Text>
<Text style={styles.navText}>设备</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.navItem}>
<Text style={styles.navIcon}>{ICONS.settings}</Text>
<Text style={styles.navText}>设置</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f8fafc',
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
padding: 20,
backgroundColor: '#ffffff',
borderBottomWidth: 1,
borderBottomColor: '#e2e8f0',
},
title: {
fontSize: 20,
fontWeight: 'bold',
color: '#1e293b',
},
settingsButton: {
padding: 8,
},
settingsIcon: {
fontSize: 20,
color: '#64748b',
},
content: {
flex: 1,
padding: 16,
},
sectionTitle: {
fontSize: 18,
fontWeight: 'bold',
color: '#1e293b',
marginVertical: 12,
},
deviceStatusCard: {
backgroundColor: '#ffffff',
borderRadius: 12,
padding: 16,
marginBottom: 16,
},
deviceStatusTitle: {
fontSize: 18,
fontWeight: 'bold',
color: '#1e293b',
marginBottom: 12,
},
statusRow: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 8,
},
statusItem: {
flex: 1,
alignItems: 'center',
},
statusIcon: {
fontSize: 20,
marginBottom: 4,
},
statusLabel: {
fontSize: 12,
color: '#64748b',
marginBottom: 4,
},
statusValue: {
fontSize: 16,
fontWeight: 'bold',
color: '#1e293b',
},
filterCard: {
backgroundColor: '#ffffff',
borderRadius: 12,
padding: 16,
marginBottom: 12,
elevation: 2,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.1,
shadowRadius: 2,
},
filterHeader: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 12,
},
filterIcon: {
fontSize: 20,
marginRight: 8,
},
filterName: {
fontSize: 16,
fontWeight: 'bold',
color: '#1e293b',
flex: 1,
},
filterStatus: {
fontSize: 12,
fontWeight: 'bold',
paddingVertical: 4,
paddingHorizontal: 8,
borderRadius: 12,
backgroundColor: '#d1fae5',
color: '#047857',
},
statusWarning: {
backgroundColor: '#fef3c7',
color: '#d97706',
},
statusReplace: {
backgroundColor: '#fee2e2',
color: '#dc2626',
},
filterProgressContainer: {
marginBottom: 12,
},
filterProgressBackground: {
height: 8,
backgroundColor: '#e2e8f0',
borderRadius: 4,
overflow: 'hidden',
marginBottom: 4,
},
filterProgressFill: {
height: '100%',
},
filterProgressText: {
fontSize: 12,
color: '#64748b',
textAlign: 'right',
},
filterDetails: {
marginBottom: 12,
},
filterDetailText: {
fontSize: 12,
color: '#64748b',
marginBottom: 4,
},
replaceButton: {
backgroundColor: '#3b82f6',
paddingVertical: 10,
paddingHorizontal: 16,
borderRadius: 8,
alignItems: 'center',
},
replaceButtonUrgent: {
backgroundColor: '#ef4444',
},
replaceButtonText: {
color: '#ffffff',
fontSize: 14,
fontWeight: '500',
},
featureGrid: {
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-between',
},
featureCard: {
backgroundColor: '#ffffff',
borderRadius: 12,
padding: 16,
width: (width - 48) / 2,
marginBottom: 16,
elevation: 2,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.1,
shadowRadius: 2,
},
featureIcon: {
fontSize: 24,
marginBottom: 8,
},
featureTitle: {
fontSize: 16,
fontWeight: 'bold',
color: '#1e293b',
marginBottom: 4,
},
featureDescription: {
fontSize: 12,
color: '#64748b',
lineHeight: 18,
},
waterQualityGuide: {
backgroundColor: '#ffffff',
borderRadius: 12,
padding: 16,
},
qualityItem: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 12,
},
qualityIcon: {
fontSize: 16,
marginRight: 8,
},
qualityText: {
fontSize: 14,
color: '#1e293b',
},
bottomNav: {
flexDirection: 'row',
justifyContent: 'space-around',
backgroundColor: '#ffffff',
borderTopWidth: 1,
borderTopColor: '#e2e8f0',
paddingVertical: 12,
},
navItem: {
alignItems: 'center',
},
activeNavItem: {
paddingBottom: 2,
borderBottomWidth: 2,
borderBottomColor: '#3b82f6',
},
navIcon: {
fontSize: 20,
color: '#94a3b8',
marginBottom: 4,
},
activeNavIcon: {
color: '#3b82f6',
},
navText: {
fontSize: 12,
color: '#94a3b8',
},
activeNavText: {
color: '#3b82f6',
fontWeight: '500',
},
});
export default WaterPurifierApp;

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

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

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

欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)