在移动应用开发领域,跨端技术已成为主流趋势,尤其是随着鸿蒙系统的兴起,如何实现一套代码覆盖多平台(iOS、Android、鸿蒙)成为开发者关注的焦点。本文将深入解析一个基于 React Native 开发的房间列表应用,探讨其架构设计、核心技术实现以及在鸿蒙系统上的跨端适配策略。

组件化

房间列表应用采用了典型的 React Native 组件化架构,核心组件包括:

  • SafeAreaView:作为根容器,确保内容在不同设备的安全区域内显示,自动适配刘海屏、状态栏和底部导航栏。在鸿蒙系统中,React Native 会调用系统 API 获取安全区域信息,确保内容不被遮挡。

  • TouchableOpacity:实现可点击区域,提供触摸反馈效果。在鸿蒙系统中,TouchableOpacity 会转换为具有点击效果的 ArkUI 组件,通过 stateStyles 实现按压状态的样式变化。

  • FlatList:用于高效渲染房间列表和家具列表。FlatList 实现了虚拟列表功能,只渲染可见区域的内容,减少了内存占用和渲染时间。在鸿蒙系统中,FlatList 会转换为 ArkUI 的 list 组件,保持高效的渲染性能。

  • ScrollView:作为页面的主要滚动容器,处理内容的滚动显示。在鸿蒙系统中,ScrollView 会映射为 ArkUI 的 scroll-view 组件,支持惯性滚动和回弹效果。

TypeScript 类型

应用定义了两个核心数据类型:

// 房间类型
type Room = {
  id: string;
  name: string;
  icon: string;
  itemCount: number;
  totalCost: number;
  color: string;
};

// 家具类型
type FurnitureItem = {
  id: string;
  name: string;
  room: string;
  category: string;
  price: number;
  purchaseDate: string;
  brand: string;
  description: string;
  roomColor: string;
};

使用 TypeScript 进行类型定义,确保了代码的类型安全和可读性,减少了运行时错误。在跨端开发中,类型定义尤为重要,能够提前发现潜在的类型错误,提高代码的可维护性。

状态管理与数据流

Hooks 状态管理

应用使用 useState Hook 管理应用状态:

const [rooms, setRooms] = useState<Room[]>([
  // 初始房间数据
]);

const [furnitureItems] = useState<FurnitureItem[]>([
  // 初始家具数据
]);

在鸿蒙系统中,React Native 的 Hook 机制会被转换为对应的 ArkUI 状态管理机制,例如 useState 会映射为 ArkUI 的 @State 装饰器,实现状态的响应式更新。当状态变化时,相关组件会自动重新渲染,无需手动操作 DOM。

数据处理

应用实现了根据房间 ID 获取对应家具的逻辑:

const getFurnitureForRoom = (roomId: string) => {
  const room = rooms.find(r => r.id === roomId);
  if (!room) return [];
  return furnitureItems.filter(item => item.room === room.name);
};

这种数据处理逻辑在鸿蒙系统上同样能够正常工作,React Native 的数组方法(findfilter)会被转换为对应的 JavaScript 执行逻辑,确保跨平台数据处理的一致性。

StyleSheet 样式

应用使用 StyleSheet.create 方法定义样式,将所有样式集中管理:

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  // 其他样式定义
});

在鸿蒙系统中,React Native 的样式会被转换为 ArkUI 的样式规则,例如:

  • flex: 1 转换为 flex-grow: 1
  • backgroundColor: '#f5f5f5' 转换为 background-color: #f5f5f5
  • borderRadius: 8 转换为 border-radius: 8px
  • borderLeftColor: item.roomColor 转换为 border-left-color: item.roomColor

这种转换机制确保了跨平台视觉一致性,开发者可以使用熟悉的 React Native 样式语法,同时获得原生的视觉效果。

动态样式

应用实现了动态样式,根据数据属性动态设置样式:

<View style={[styles.roomIcon, { backgroundColor: `${item.color}20` }]}>
  <Text style={[styles.roomIconText, { color: item.color }]}>{item.icon}</Text>
</View>

在鸿蒙系统中,动态样式同样能够正常工作,React Native 会将动态样式转换为对应的 ArkUI 动态样式,通过状态管理机制实现样式的动态更新。

组件映射

React Native 组件到鸿蒙 ArkUI 组件的映射是跨端适配的核心机制。以下是应用中主要组件的映射关系:

React Native 组件 鸿蒙 ArkUI 组件 说明
SafeAreaView Stack 安全区域容器
View Div 基础容器组件
Text Text 文本组件
TouchableOpacity Button 可点击组件
FlatList List 高效列表组件
Alert AlertDialog 弹窗组件

这种映射机制确保了 React Native 组件在鸿蒙系统上的原生表现,同时保持了开发体验的一致性。开发者可以使用熟悉的 React Native 组件,无需学习全新的 ArkUI 组件库。

交互处理

应用中的交互事件处理,如按钮点击、Alert 弹窗等,在鸿蒙系统上都能得到良好的适配:

  • 按钮点击:通过 onPress 属性绑定的事件处理函数,在鸿蒙系统上会被转换为 ArkUI 组件的 onClick 事件。
  • Alert 弹窗Alert.alert 会调用系统原生的弹窗 API,确保弹窗样式与系统一致,提供原生的用户体验。

策略

应用采用了多种性能优化策略,确保在鸿蒙系统上也能流畅运行:

  1. FlatList 高性能渲染:使用 FlatList 组件渲染房间列表和家具列表,实现虚拟列表功能,提高长列表的渲染性能。
  2. 样式优化:使用 StyleSheet.create 定义样式,避免内联样式的性能问题。
  3. 不可变数据更新:状态更新时创建新对象/数组,避免直接修改原有数据,减少不必要的组件重渲染。
  4. 条件渲染:根据状态条件渲染组件,减少初始渲染的组件数量。

React Native 鸿蒙跨端开发为开发者提供了一种高效的解决方案,能够使用一套代码构建出在多平台上表现一致的高质量应用。本次解析的房间列表应用,展示了如何利用 React Native 的组件化设计、状态管理、TypeScript 类型支持和样式系统,构建一个功能完整、交互流畅的家居管理应用,并实现鸿蒙系统的无缝适配。


现代家居管理应用已经从简单的清单记录演变为集空间管理、资产跟踪、成本分析于一体的综合系统。RoomListApp组件展示了如何在移动端实现一套完整的房间与家具管理系统,从数据关联、可视化展示到交互操作,形成了一个完整的家居数据管理闭环。

从技术架构的角度来看,这个组件不仅是一个界面展示,更是实体关系管理的典型案例。它需要处理房间与家具的一对多关系、数据聚合计算、颜色编码系统等多个技术维度。当我们将这套架构迁移到鸿蒙平台时,需要深入理解其数据关系模型和交互设计模式,才能确保跨端实现的完整性和一致性。

房间与家具的关系模型

type Room = {
  id: string;
  name: string;
  icon: string;
  itemCount: number;
  totalCost: number;
  color: string;
};

type FurnitureItem = {
  id: string;
  name: string;
  room: string; // 关联房间名称
  roomColor: string; // 继承房间颜色
};

这种数据结构设计体现了家居管理的核心关系:

  1. 主从关系:家具通过room字段关联到所属房间
  2. 数据冗余:家具存储roomColor避免频繁查询
  3. 聚合计算:房间维护itemCount和totalCost

在鸿蒙ArkUI中,可以使用关系型数据类:

// 鸿蒙房间数据模型
@Observed
class RoomHarmony {
  id: string = '';
  name: string = '';
  icon: ResourceStr = '';
  color: ResourceColor = '#f87171';
  private furnitureItems: FurnitureItemHarmony[] = [];
  
  get itemCount(): number {
    return this.furnitureItems.length;
  }
  
  get totalCost(): number {
    return this.furnitureItems.reduce((sum, item) => sum + item.price, 0);
  }
  
  addFurniture(item: FurnitureItemHarmony): void {
    this.furnitureItems.push(item);
  }
}

// 鸿蒙家具数据模型
@Observed
class FurnitureItemHarmony {
  id: string = '';
  name: string = '';
  roomId: string = '';
  category: string = '';
  price: number = 0;
  
  constructor(data: Partial<FurnitureItemHarmony>) {
    Object.assign(this, data);
  }
}

数据聚合与查询

// 获取房间的家具
const getFurnitureForRoom = (roomId: string) => {
  const room = rooms.find(r => r.id === roomId);
  if (!room) return [];
  return furnitureItems.filter(item => item.room === room.name);
};

查询系统实现了高效的关联查询:

  1. 内存查询:基于数组的filter操作
  2. 引用传递:通过房间名称建立关联
  3. 空值处理:防御性编程避免异常

房间卡片

const renderRoomItem = ({ item }: { item: Room }) => (
  <TouchableOpacity style={styles.roomCard}>
    <View style={[styles.roomIcon, { backgroundColor: `${item.color}20` }]}>
      <Text style={[styles.roomIconText, { color: item.color }]}>{item.icon}</Text>
    </View>
    <View style={styles.roomInfo}>
      <Text style={styles.roomName}>{item.name}</Text>
      <Text style={styles.roomDetails}>{item.itemCount} 件家具 • ¥{item.totalCost}</Text>
    </View>
  </TouchableOpacity>
);

卡片设计融合了多个交互元素:

  1. 视觉标识:彩色图标区分不同房间
  2. 信息密度:关键数据集中展示
  3. 点击反馈:TouchableOpacity提供按压效果
  4. 颜色系统:主色与浅色背景的协调搭配

家具列表

const renderFurnitureItem = ({ item }: { item: FurnitureItem }) => (
  <View style={[styles.furnitureCard, { borderLeftColor: item.roomColor }]}>
    <Text style={styles.furnitureName}>{item.name}</Text>
    <Text style={styles.furnitureCategory}>{item.category}{item.brand}</Text>
  </View>
);

关联列表设计特点:

  1. 视觉线索:左侧边框使用房间颜色
  2. 层级清晰:名称与类别分行显示
  3. 空间关联:直观展示家具所属房间

家居资产管理应用的核心是对“房间-家具”这一主从关系数据的精准建模,应用基于 TypeScript 构建了完整的类型体系,覆盖房间与家具的全维度信息,为后续的状态管理、数据关联与跨端迁移奠定了强类型基础:

// 房间类型
type Room = {
  id: string;
  name: string;
  icon: string;
  itemCount: number;
  totalCost: number;
  color: string;
};

// 家具类型
type FurnitureItem = {
  id: string;
  name: string;
  room: string;
  category: string;
  price: number;
  purchaseDate: string;
  brand: string;
  description: string;
  roomColor: string;
};

这一类型定义充分体现了家居资产管理场景的业务特性:

  • 主从关系清晰化:通过 FurnitureItem 中的 room 字段与 Roomname 字段建立关联,形成“房间-家具”的主从数据结构,符合用户对家居资产的认知逻辑;
  • 视觉属性内置化:为每个房间定义专属 color,并在家具类型中同步 roomColor,实现视觉风格的统一管理,避免跨组件传递样式;
  • 数据维度完整性:房间类型覆盖标识、名称、视觉图标、资产数量、总价值等核心维度,家具类型补充品类、品牌、购买日期、价格等精细化信息,满足家居资产管理的全部数据需求;
  • 数值标准化:价格、数量等核心指标采用数值类型,便于后续的统计计算(总价值、平均价格),日期采用标准化字符串格式,保证跨平台数据解析的一致性。

2. 分层

家居资产管理应用的核心逻辑是房间与家具数据的关联查询与展示,应用通过 React Hooks 构建了轻量且高效的状态管理体系,同时设计了符合业务逻辑的数据关联方法:

const [rooms, setRooms] = useState<Room[]>([/* 初始房间数据 */]);
const [furnitureItems] = useState<FurnitureItem[]>([/* 初始家具数据 */]);

// 获取房间的家具
const getFurnitureForRoom = (roomId: string) => {
  const room = rooms.find(r => r.id === roomId);
  if (!room) return [];
  return furnitureItems.filter(item => item.room === room.name);
};
  • 状态分层存储:将房间数据(rooms)与家具数据(furnitureItems)拆分为独立状态,符合“单一数据源”原则,便于分别管理与更新;
  • 只读状态优化:家具数据使用 const [furnitureItems] = useState() 定义为只读状态(无更新逻辑),避免不必要的状态更新开销;
  • 数据关联方法封装:通过 getFurnitureForRoom 方法封装房间与家具的关联查询逻辑,输入房间ID即可获取对应家具列表,实现业务逻辑的复用与解耦;
  • 边界值处理:关联查询时先校验房间是否存在,避免空指针异常,符合健壮性编码原则。

3. 多形态列表

家居资产管理应用的核心交互是不同形态的列表展示(垂直房间列表、横向热门房间列表、家具列表),应用构建了多层次、多形态的列表渲染体系,适配不同类型的家居数据展示需求:

(1)垂直房间列表(FlatList)

房间列表作为应用核心模块,采用 FlatList 替代基础的 map 渲染,兼顾性能与交互体验:

<FlatList
  data={rooms}
  renderItem={renderRoomItem}
  keyExtractor={item => item.id}
  showsVerticalScrollIndicator={false}
/>
  • 性能优化FlatList 内置虚拟列表机制,仅渲染可视区域内的房间项,大幅降低长列表场景下的内存占用,相比 map 渲染性能提升显著;
  • 关键属性配置:通过 keyExtractor 指定唯一标识,避免列表重渲染时的性能损耗;关闭垂直滚动指示器(showsVerticalScrollIndicator={false}),提升视觉简洁性;
  • 视觉设计:房间卡片采用“图标+信息+箭头”的三栏式布局,核心信息(房间名称、家具数量、总价值)层级清晰,符合用户“快速浏览+点击查看详情”的交互路径:
const renderRoomItem = ({ item }: { item: Room }) => (
  <TouchableOpacity 
    style={styles.roomCard}
    onPress={() => Alert.alert('房间详情', `进入 ${item.name} 房间的家具列表`)}
  >
    <View style={[styles.roomIcon, { backgroundColor: `${item.color}20` }]}>
      <Text style={[styles.roomIconText, { color: item.color }]}>{item.icon}</Text>
    </View>
    
    <View style={styles.roomInfo}>
      <Text style={styles.roomName}>{item.name}</Text>
      <Text style={styles.roomDetails}>{item.itemCount} 件家具 • ¥{item.totalCost.toLocaleString()}</Text>
    </View>
    
    <View style={styles.arrowContainer}>
      <Text style={styles.arrow}>›</Text>
    </View>
  </TouchableOpacity>
);
  • 视觉一致性:通过 ${item.color}20 生成房间主色的半透明背景,配合主色文字,形成统一且差异化的视觉风格,每个房间拥有专属视觉标识;
  • 数值格式化:使用 toLocaleString() 格式化金额,自动添加千位分隔符,提升数值可读性;
  • 交互反馈TouchableOpacity 提供点击透明度变化反馈,符合移动端交互习惯;箭头图标明确指示“可点击进入详情”的交互意图。
(2)横向热门房间列表(ScrollView + 水平布局)

热门房间模块采用横向滚动布局,突出展示核心房间,适配“快速切换查看”的交互场景:

<ScrollView 
  horizontal 
  showsHorizontalScrollIndicator={false} 
  style={styles.horizontalScroll}
>
  <View style={styles.horizontalContainer}>
    {rooms.slice(0, 3).map(room => (
      <TouchableOpacity 
        key={room.id}
        style={[styles.hotRoomCard, { borderColor: room.color }]}
        onPress={() => Alert.alert('房间详情', `查看 ${room.name} 的详细信息`)}
      >
        <Text style={[styles.hotRoomIcon, { color: room.color }]}>{room.icon}</Text>
        <Text style={styles.hotRoomName}>{room.name}</Text>
        <Text style={styles.hotRoomItemCount}>{room.itemCount} 件</Text>
      </TouchableOpacity>
    ))}
  </View>
</ScrollView>
  • 数据筛选:通过 slice(0, 3) 筛选前3个房间作为热门房间,符合“精选展示”的业务逻辑;
  • 布局适配ScrollView 设置 horizontal={true} 实现横向滚动,关闭水平滚动指示器提升视觉体验;
  • 视觉差异化:热门房间卡片采用边框配色(borderColor: room.color)替代背景色,与普通房间卡片形成视觉区分,同时保持风格统一;
  • 信息简化:仅展示图标、名称、家具数量核心信息,适配横向卡片的有限展示空间。
(3)家具列表(FlatList)

家具列表采用“左侧图标+中间信息+右侧价格”的经典布局,突出核心信息层级:

const renderFurnitureItem = ({ item }: { item: FurnitureItem }) => (
  <View style={[styles.furnitureCard, { borderLeftColor: item.roomColor }]}>
    <View style={styles.furnitureIcon}>
      <Text style={styles.furnitureIconText}>🪑</Text>
    </View>
    
    <View style={styles.furnitureInfo}>
      <Text style={styles.furnitureName}>{item.name}</Text>
      <Text style={styles.furnitureCategory}>{item.category} • {item.brand}</Text>
      <Text style={styles.furnitureDate}>{item.purchaseDate}</Text>
    </View>
    
    <View style={styles.furniturePrice}>
      <Text style={styles.priceText}>¥{item.price.toLocaleString()}</Text>
    </View>
  </View>
);
  • 视觉关联:通过 borderLeftColor: item.roomColor 为家具卡片添加房间主色的左侧边框,直观关联所属房间,强化“房间-家具”的主从关系;
  • 信息层级:家具名称(大号粗体)→ 品类/品牌(中号灰色)→ 购买日期(小号浅灰),形成清晰的信息层级,符合用户“先看名称,再看详情”的信息获取路径;
  • 价格突出:价格信息单独放置在右侧,使用粗体大号字体,满足用户对资产价值的核心关注需求。

真实演示案例代码:

// app.tsx
import React, { useState } from 'react';
import { SafeAreaView, View, Text, StyleSheet, TouchableOpacity, ScrollView, Dimensions, Alert, FlatList } from 'react-native';

// Base64 图标库
const ICONS_BASE64 = {
  home: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  furniture: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  room: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  add: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  search: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  settings: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  cart: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  more: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
};

const { width, height } = Dimensions.get('window');

// 房间类型
type Room = {
  id: string;
  name: string;
  icon: string;
  itemCount: number;
  totalCost: number;
  color: string;
};

// 家具类型
type FurnitureItem = {
  id: string;
  name: string;
  room: string;
  category: string;
  price: number;
  purchaseDate: string;
  brand: string;
  description: string;
  roomColor: string;
};

const RoomListApp: React.FC = () => {
  const [rooms, setRooms] = useState<Room[]>([
    { id: '1', name: '客厅', icon: '🛋️', itemCount: 5, totalCost: 8500, color: '#f87171' },
    { id: '2', name: '卧室', icon: '🛏️', itemCount: 3, totalCost: 6200, color: '#60a5fa' },
    { id: '3', name: '厨房', icon: '🍳', itemCount: 4, totalCost: 4800, color: '#34d399' },
    { id: '4', name: '书房', icon: '📚', itemCount: 2, totalCost: 3500, color: '#a78bfa' },
    { id: '5', name: '餐厅', icon: '🍽️', itemCount: 2, totalCost: 2800, color: '#fbbf24' },
    { id: '6', name: '浴室', icon: '🚿', itemCount: 1, totalCost: 1200, color: '#2dd4bf' },
  ]);

  const [furnitureItems] = useState<FurnitureItem[]>([
    { id: '1', name: '沙发', room: '客厅', category: '座椅', price: 3500, purchaseDate: '2023-05-15', brand: '宜家', description: '三人座布艺沙发,灰色', roomColor: '#f87171' },
    { id: '2', name: '茶几', room: '客厅', category: '桌子', price: 800, purchaseDate: '2023-05-16', brand: '宜家', description: '简约风格圆形茶几', roomColor: '#f87171' },
    { id: '3', name: '餐桌', room: '餐厅', category: '桌子', price: 2000, purchaseDate: '2023-04-20', brand: '曲美', description: '实木餐桌,可伸缩设计', roomColor: '#fbbf24' },
    { id: '4', name: '书桌', room: '书房', category: '桌子', price: 1200, purchaseDate: '2023-03-10', brand: '宜家', description: '简约办公桌,带抽屉', roomColor: '#a78bfa' },
    { id: '5', name: '床', room: '卧室', category: '床具', price: 2500, purchaseDate: '2023-02-28', brand: '顾家', description: '双人床,带床垫', roomColor: '#60a5fa' },
    { id: '6', name: '衣柜', room: '卧室', category: '储物', price: 1800, purchaseDate: '2023-02-28', brand: '索菲亚', description: '定制衣柜,推拉门设计', roomColor: '#60a5fa' },
    { id: '7', name: '冰箱', room: '厨房', category: '电器', price: 2800, purchaseDate: '2023-01-15', brand: '海尔', description: '双开门冰箱,节能静音', roomColor: '#34d399' },
    { id: '8', name: '洗衣机', room: '厨房', category: '电器', price: 1500, purchaseDate: '2023-01-15', brand: '小天鹅', description: '滚筒洗衣机,8公斤', roomColor: '#34d399' },
    { id: '9', name: '浴缸', room: '浴室', category: '卫浴', price: 1200, purchaseDate: '2022-12-10', brand: '科勒', description: '独立式浴缸', roomColor: '#2dd4bf' },
  ]);

  // 获取房间的家具
  const getFurnitureForRoom = (roomId: string) => {
    const room = rooms.find(r => r.id === roomId);
    if (!room) return [];
    return furnitureItems.filter(item => item.room === room.name);
  };

  // 渲染房间项
  const renderRoomItem = ({ item }: { item: Room }) => (
    <TouchableOpacity 
      style={styles.roomCard}
      onPress={() => Alert.alert('房间详情', `进入 ${item.name} 房间的家具列表`)}
    >
      <View style={[styles.roomIcon, { backgroundColor: `${item.color}20` }]}>
        <Text style={[styles.roomIconText, { color: item.color }]}>{item.icon}</Text>
      </View>
      
      <View style={styles.roomInfo}>
        <Text style={styles.roomName}>{item.name}</Text>
        <Text style={styles.roomDetails}>{item.itemCount} 件家具 • ¥{item.totalCost.toLocaleString()}</Text>
      </View>
      
      <View style={styles.arrowContainer}>
        <Text style={styles.arrow}></Text>
      </View>
    </TouchableOpacity>
  );

  // 渲染家具项
  const renderFurnitureItem = ({ item }: { item: FurnitureItem }) => (
    <View style={[styles.furnitureCard, { borderLeftColor: item.roomColor }]}>
      <View style={styles.furnitureIcon}>
        <Text style={styles.furnitureIconText}>🪑</Text>
      </View>
      
      <View style={styles.furnitureInfo}>
        <Text style={styles.furnitureName}>{item.name}</Text>
        <Text style={styles.furnitureCategory}>{item.category}{item.brand}</Text>
        <Text style={styles.furnitureDate}>{item.purchaseDate}</Text>
      </View>
      
      <View style={styles.furniturePrice}>
        <Text style={styles.priceText}>¥{item.price.toLocaleString()}</Text>
      </View>
    </View>
  );

  return (
    <SafeAreaView style={styles.container}>
      {/* 头部 */}
      <View style={styles.header}>
        <Text style={styles.title}>房间列表</Text>
        <TouchableOpacity 
          style={styles.addButton}
          onPress={() => Alert.alert('添加房间', '添加新的房间')}
        >
          <Text style={styles.addButtonText}>+</Text>
        </TouchableOpacity>
      </View>

      <ScrollView style={styles.content}>
        {/* 搜索栏 */}
        <View style={styles.searchContainer}>
          <Text style={styles.searchIcon}>🔍</Text>
          <Text style={styles.searchPlaceholder}>搜索房间或家具</Text>
        </View>

        {/* 房间总数统计 */}
        <View style={styles.statsContainer}>
          <View style={styles.statItem}>
            <Text style={styles.statValue}>{rooms.length}</Text>
            <Text style={styles.statLabel}>房间总数</Text>
          </View>
          <View style={styles.statItem}>
            <Text style={styles.statValue}>{furnitureItems.length}</Text>
            <Text style={styles.statLabel}>家具总数</Text>
          </View>
          <View style={styles.statItem}>
            <Text style={styles.statValue}>¥{furnitureItems.reduce((sum, item) => sum + item.price, 0).toLocaleString()}</Text>
            <Text style={styles.statLabel}>总价值</Text>
          </View>
        </View>

        {/* 房间列表标题 */}
        <View style={styles.sectionHeader}>
          <Text style={styles.sectionTitle}>我的房间</Text>
          <Text style={styles.countText}>{rooms.length} 个房间</Text>
        </View>

        {/* 房间列表 */}
        <FlatList
          data={rooms}
          renderItem={renderRoomItem}
          keyExtractor={item => item.id}
          showsVerticalScrollIndicator={false}
        />

        {/* 热门房间 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>热门房间</Text>
          <ScrollView 
            horizontal 
            showsHorizontalScrollIndicator={false} 
            style={styles.horizontalScroll}
          >
            <View style={styles.horizontalContainer}>
              {rooms.slice(0, 3).map(room => (
                <TouchableOpacity 
                  key={room.id}
                  style={[styles.hotRoomCard, { borderColor: room.color }]}
                  onPress={() => Alert.alert('房间详情', `查看 ${room.name} 的详细信息`)}
                >
                  <Text style={[styles.hotRoomIcon, { color: room.color }]}>{room.icon}</Text>
                  <Text style={styles.hotRoomName}>{room.name}</Text>
                  <Text style={styles.hotRoomItemCount}>{room.itemCount}</Text>
                </TouchableOpacity>
              ))}
            </View>
          </ScrollView>
        </View>

        {/* 最近购买的家具 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>最近购买</Text>
          <FlatList
            data={furnitureItems.slice(0, 3)}
            renderItem={renderFurnitureItem}
            keyExtractor={item => item.id}
            showsVerticalScrollIndicator={false}
          />
        </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>

      {/* 底部导航 */}
      <View style={styles.bottomNav}>
        <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>
        
        <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: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    padding: 20,
    backgroundColor: '#ffffff',
    borderBottomWidth: 1,
    borderBottomColor: '#e2e8f0',
  },
  title: {
    fontSize: 20,
    fontWeight: 'bold',
    color: '#1e293b',
  },
  addButton: {
    width: 36,
    height: 36,
    borderRadius: 18,
    backgroundColor: '#3b82f6',
    alignItems: 'center',
    justifyContent: 'center',
  },
  addButtonText: {
    fontSize: 20,
    color: '#ffffff',
    fontWeight: 'bold',
  },
  content: {
    flex: 1,
    padding: 16,
  },
  searchContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#ffffff',
    borderRadius: 20,
    paddingVertical: 12,
    paddingHorizontal: 16,
    marginBottom: 16,
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  searchIcon: {
    fontSize: 18,
    color: '#64748b',
  },
  searchPlaceholder: {
    fontSize: 14,
    color: '#94a3b8',
    marginLeft: 12,
    flex: 1,
  },
  statsContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    backgroundColor: '#ffffff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 16,
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  statItem: {
    alignItems: 'center',
  },
  statValue: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#3b82f6',
  },
  statLabel: {
    fontSize: 12,
    color: '#64748b',
    marginTop: 4,
    textAlign: 'center',
  },
  sectionHeader: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: 12,
  },
  sectionTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#1e293b',
  },
  countText: {
    fontSize: 14,
    color: '#64748b',
  },
  roomCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    flexDirection: 'row',
    alignItems: 'center',
    padding: 16,
    marginBottom: 12,
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  roomIcon: {
    width: 50,
    height: 50,
    borderRadius: 25,
    alignItems: 'center',
    justifyContent: 'center',
    marginRight: 16,
  },
  roomIconText: {
    fontSize: 24,
  },
  roomInfo: {
    flex: 1,
  },
  roomName: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 4,
  },
  roomDetails: {
    fontSize: 14,
    color: '#64748b',
  },
  arrowContainer: {
    justifyContent: 'center',
  },
  arrow: {
    fontSize: 20,
    color: '#94a3b8',
  },
  section: {
    marginBottom: 16,
  },
  horizontalScroll: {
    paddingVertical: 8,
  },
  horizontalContainer: {
    flexDirection: 'row',
  },
  hotRoomCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    padding: 12,
    marginRight: 12,
    borderWidth: 1,
    alignItems: 'center',
    minWidth: 80,
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  hotRoomIcon: {
    fontSize: 24,
    marginBottom: 4,
  },
  hotRoomName: {
    fontSize: 14,
    fontWeight: 'bold',
    color: '#1e293b',
    textAlign: 'center',
  },
  hotRoomItemCount: {
    fontSize: 12,
    color: '#64748b',
  },
  furnitureCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    flexDirection: 'row',
    alignItems: 'center',
    padding: 12,
    marginBottom: 8,
    borderLeftWidth: 4,
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  furnitureIcon: {
    width: 40,
    height: 40,
    borderRadius: 8,
    backgroundColor: '#e2e8f0',
    alignItems: 'center',
    justifyContent: 'center',
    marginRight: 12,
  },
  furnitureIconText: {
    fontSize: 20,
  },
  furnitureInfo: {
    flex: 1,
  },
  furnitureName: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 2,
  },
  furnitureCategory: {
    fontSize: 12,
    color: '#64748b',
    marginBottom: 2,
  },
  furnitureDate: {
    fontSize: 12,
    color: '#94a3b8',
  },
  furniturePrice: {
    alignItems: 'flex-end',
  },
  priceText: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#1e293b',
  },
  infoCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    padding: 16,
    marginTop: 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,
  },
  bottomNav: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    backgroundColor: '#ffffff',
    borderTopWidth: 1,
    borderTopColor: '#e2e8f0',
    paddingVertical: 12,
  },
  navItem: {
    alignItems: 'center',
    flex: 1,
  },
  navIcon: {
    fontSize: 20,
    color: '#94a3b8',
    marginBottom: 4,
  },
  navText: {
    fontSize: 12,
    color: '#94a3b8',
  },
});

export default RoomListApp;

请添加图片描述


打包

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

在这里插入图片描述

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

在这里插入图片描述

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

请添加图片描述
本文探讨了基于React Native开发的房间列表应用在跨平台(iOS、Android、鸿蒙)适配中的关键技术实现。文章重点分析了组件化架构设计(SafeAreaView、FlatList等)、TypeScript类型安全、Hooks状态管理以及StyleSheet样式系统,并详细阐述了React Native组件与鸿蒙ArkUI的映射机制。通过一个家居管理应用案例,展示了如何实现房间与家具的一对多关系模型、数据聚合计算以及跨平台性能优化策略(虚拟列表、条件渲染等)。特别针对鸿蒙系统,说明了状态管理(@State装饰器)、样式转换和交互事件处理的适配方案,验证了使用React Native实现多平台一致性的可行性。

欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐