React Native 的核心优势在于其组件化设计,使得一套代码能够在多平台(包括鸿蒙系统)上运行。本次解析的 BookshelfListApp 组件,展示了如何构建一个功能完整的书架列表应用,并实现鸿蒙系统的无缝适配。

数据模型

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

// 书架类型
type Shelf = {
  id: string;
  name: string;
  icon: string;
  description: string;
  bookCount: number;
  color: string;
};

// 书籍类型
type Book = {
  id: string;
  title: string;
  author: string;
  genre: string;
  pages: number;
  rating: number;
  publishYear: number;
  description: string;
  shelf: string;
  cover: string;
  progress: number;
};

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

状态管理

应用使用 useState Hook 管理两个核心状态:

const [shelves, setShelves] = useState<Shelf[]>([
  // 初始书架数据
]);

const [books] = useState<Book[]>([
  // 初始书籍数据
]);

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

应用实现了 getBooksForShelf 函数,用于根据书架 ID 获取对应的书籍:

const getBooksForShelf = (shelfId: string) => {
  const shelf = shelves.find(s => s.id === shelfId);
  if (!shelf) return [];
  return books.filter(book => book.shelf === shelf.name);
};

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

书架项组件

书架项(renderShelfItem)采用卡片式设计,包含图标、文字信息和箭头:

  • 图标设计:使用背景色和文字颜色的动态绑定,根据书架数据的 color 属性生成对应的背景色(通过 ${item.color}20 实现半透明效果)和文字颜色,增强视觉层次感。

  • Flexbox 布局:使用 flexDirection: 'row'justifyContent: 'space-between' 实现水平排列,确保在不同屏幕尺寸下保持一致的视觉效果。

  • 触摸反馈:使用 TouchableOpacity 实现点击事件,提供原生的触摸反馈效果。

书籍项组件

书籍项(renderBookItem)同样采用卡片式设计,包含书籍图标、基本信息、评分和阅读进度:

  • 进度条实现:根据书籍的 progress 属性动态生成进度条,通过 width: ${item.progress}%`` 实现进度展示。

  • 条件渲染:使用 {item.progress > 0 && (...)} 条件渲染进度条,仅在有阅读进度时显示。

样式系统

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

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

样式

  1. Flexbox 布局:大量使用 Flexbox 布局(flexDirectionjustifyContentalignItems)实现响应式设计,能够在不同屏幕尺寸下保持一致的视觉效果。

  2. 动态样式:通过样式对象数组实现动态样式绑定,例如:

    <View style={[styles.shelfIcon, { backgroundColor: `${item.color}20` }]}>
      <Text style={[styles.shelfIconText, { color: item.color }]}>{item.icon}</Text>
    </View>
    
  3. 卡片式设计:采用圆角、阴影等设计元素,增强视觉层次感:

    • borderRadius 实现圆角效果
    • shadowColorshadowOffset 等属性实现卡片阴影效果,在鸿蒙系统上会转换为对应的样式

组件映射

React Native 组件会被映射为对应平台的原生组件,例如:

  • View → 鸿蒙的 Div
  • Text → 鸿蒙的 Text
  • TouchableOpacity → 鸿蒙的 Button
  • FlatList → 鸿蒙的 List

样式转换

React Native 的样式会被转换为对应平台的样式规则,例如:

  • flexDirection: 'row'flex-direction: row
  • justifyContent: 'space-between'justify-content: space-between
  • paddingHorizontal: 16padding-left: 16px; padding-right: 16px

API 适配

React Native 提供了统一的 API 层,封装了不同平台的底层 API,例如:

  • Dimensions.get('window') 获取屏幕尺寸
  • Alert.alert() 显示弹窗
  • TouchableOpacity 的触摸事件

应用采用了多种性能优化策略:

  1. FlatList 渲染:使用 FlatList 组件高效渲染长列表,实现虚拟滚动,减少内存占用。

  2. 样式复用:通过 StyleSheet.create 集中管理样式,避免重复创建样式对象。

  3. 条件渲染:仅在需要时渲染某些元素(如阅读进度条),减少不必要的渲染开销。

  4. 不可变数据:状态更新时创建新对象/数组,而非直接修改,确保状态的可预测性和性能优化。

React Native 的组件化设计和跨端适配机制,使得开发者可以使用一套代码构建多平台应用。通过合理的组件设计、状态管理和样式系统,BookshelfListApp 实现了功能完整的书架管理功能,并能够在鸿蒙系统上无缝运行。


在现代阅读应用开发中,书架管理功能已经从简单的列表展示演变为集分类管理、阅读进度追踪、个性化推荐于一体的综合阅读系统。BookshelfListApp组件展示了如何在移动端实现一套完整的书架管理功能,从书籍归类、进度展示到阅读操作,形成了一个完整的阅读数据闭环。

从技术架构的角度来看,这个组件不仅是一个界面展示,更是阅读行为数据可视化的典型案例。它需要协调多维度书籍数据、阅读进度可视化、分类导航等多个技术维度。当我们将这套架构迁移到鸿蒙平台时,需要深入理解其数据关系模型和阅读进度计算机制,才能确保跨端实现的完整性和一致性。

书架与书籍

type Shelf = {
  id: string;
  name: string;
  icon: string;
  description: string;
  bookCount: number;
  color: string;
};

type Book = {
  id: string;
  title: string;
  author: string;
  genre: string;
  pages: number;
  rating: number;
  publishYear: number;
  description: string;
  shelf: string;
  progress: number;
};

这种数据结构设计体现了阅读系统的核心关系:

  1. 分类关系:书籍通过shelf字段关联到所属书架
  2. 阅读进度:progress字段记录阅读百分比
  3. 元信息丰富:包含评分、页数、出版年份等详细信息

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

// 鸿蒙书架数据模型
@Observed
class ShelfHarmony {
  id: string = '';
  name: string = '';
  icon: ResourceStr = '';
  description: string = '';
  color: ResourceColor = '#f87171';
  private books: BookHarmony[] = [];
  
  get bookCount(): number {
    return this.books.length;
  }
  
  get completedBooks(): number {
    return this.books.filter(book => book.progress === 100).length;
  }
  
  addBook(book: BookHarmony): void {
    this.books.push(book);
  }
}

// 鸿蒙书籍数据模型
@Observed
class BookHarmony {
  id: string = '';
  title: string = '';
  author: string = '';
  genre: string = '';
  pages: number = 0;
  rating: number = 0;
  shelfId: string = '';
  progress: number = 0;
  
  get progressColor(): ResourceColor {
    if (this.progress === 100) return '#34d399';
    if (this.progress > 0) return '#60a5fa';
    return '#94a3b8';
  }
  
  get progressStatus(): string {
    if (this.progress === 100) return '已完成';
    if (this.progress > 0) return '阅读中';
    return '未开始';
  }
}

阅读进度

// 书籍项的进度展示
{item.progress > 0 && (
  <View style={styles.progressContainer}>
    <View style={styles.progressBar}>
      <View 
        style={[
          styles.progressFill, 
          { 
            width: `${item.progress}%`, 
            backgroundColor: item.progress === 100 ? '#34d399' : '#60a5fa' 
          }
        ]} 
      />
    </View>
    <Text style={styles.progressText}>{item.progress}%</Text>
  </View>
)}

进度管理系统采用了智能的视觉编码:

  1. 颜色语义:绿色表示完成,蓝色表示进行中
  2. 精确展示:百分比数值和进度条双重显示
  3. 条件渲染:仅对已开始的书籍显示进度

阅读按钮的动态文本

<Text style={styles.readButtonText}>
  {item.progress === 100 ? '重读' : item.progress > 0 ? '继续' : '阅读'}
</Text>

阅读操作采用了状态感知设计:

  1. 智能文案:根据进度状态显示不同操作
  2. 用户引导:清晰的行动召唤文字
  3. 状态反馈:直观的操作结果预期

书架导航

const getBooksForShelf = (shelfId: string) => {
  const shelf = shelves.find(s => s.id === shelfId);
  if (!shelf) return [];
  return books.filter(book => book.shelf === shelf.name);
};

导航系统实现了高效的数据关联:

  1. 内存查询:基于数组filter的快速筛选
  2. 引用解析:通过书架名称建立关联
  3. 空值保护:防御性编程避免运行时错误

统计信息

<View style={styles.statsContainer}>
  <View style={styles.statItem}>
    <Text style={styles.statValue}>{shelves.length}</Text>
    <Text style={styles.statLabel}>书架数量</Text>
  </View>
  <View style={styles.statItem}>
    <Text style={styles.statValue}>{books.length}</Text>
    <Text style={styles.statLabel}>书籍总数</Text>
  </View>
  <View style={styles.statItem}>
    <Text style={styles.statValue}>
      {books.filter(b => b.progress === 100).length}
    </Text>
    <Text style={styles.statLabel}>已读完</Text>
  </View>
</View>

统计可视化采用了信息密度设计:

  1. 关键指标:书架数、书籍数、完成数
  2. 实时计算:使用filter动态统计完成数量
  3. 视觉层次:大数字突出,小标签说明

评分

<View style={styles.ratingContainer}>
  <Text style={styles.rating}>{item.rating}</Text>
</View>

评分展示采用了简明的设计:

  1. 图标标识:星号图标直观表达评分概念
  2. 数值精确:保留一位小数的评分显示
  3. 视觉统一:与整体设计风格保持一致

1. 核心技术体系映射

书架管理应用的跨端适配核心在于“数据模型完全复用、列表组件精准映射、交互体验等价转换”,React Native 与鸿蒙 ArkTS 的核心能力映射关系如下:

React Native 核心能力 鸿蒙 ArkTS 对应实现 适配要点
TypeScript 数据模型 TypeScript 数据模型 100% 复用,包括 Shelf/Book 类型定义、初始数据配置
useState 状态管理 @State/@Link 装饰器 状态定义语法调整,状态更新逻辑完全复用
FlatList 垂直列表 List + ListItem datalistDatarenderItemitemGeneratorkeyExtractoridGenerator
ScrollView 横向滚动 Scroll + Row horizontal={true}scrollable(ScrollDirection.Horizontal),关闭滚动指示器通过 scrollBar(BarState.Off) 实现
TouchableOpacity 交互 Button/TextButton + onClick onPressonClick,移除透明度反馈(鸿蒙默认提供点击态)
StyleSheet 样式系统 行内样式 + @Styles/@Extend Flex 布局属性完全复用,elevation/shadow 合并为 shadow 配置,borderRadius 语法一致
Dimensions 屏幕适配 @SystemEnvironment 通过 @SystemEnvironment({ envProp: EnvironmentProp.SCREEN_WIDTH/HEIGHT }) 获取屏幕尺寸
Alert 弹窗 promptAction.showAlert() 封装统一的弹窗工具函数,屏蔽平台 API 差异
数组方法(filter/map/slice) 数组方法(filter/map/slice) 100% 复用,包括数据筛选、映射、切片逻辑
动态样式绑定 动态样式绑定 语法从 style={[base, dynamic]} 调整为 base().dynamic(),逻辑完全复用

以数据模型、书架列表、书籍进度条、热门书架横向滚动为例,展示 React Native 代码迁移到鸿蒙 ArkTS 的具体实现:
React Native 原核心逻辑

const BookshelfListApp: React.FC = () => {
  const [shelves, setShelves] = useState<Shelf[]>([/* 初始数据 */]);
  const [books] = useState<Book[]>([/* 初始数据 */]);

  // 获取书架的书籍
  const getBooksForShelf = (shelfId: string) => {
    const shelf = shelves.find(s => s.id === shelfId);
    if (!shelf) return [];
    return books.filter(book => book.shelf === shelf.name);
  };
  
  // 渲染函数...
  
  return (/* JSX 结构 */);
};

真实演示案例代码:

// 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==',
  book: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  shelf: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  add: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  search: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  settings: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  read: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  more: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
};

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

// 书架类型
type Shelf = {
  id: string;
  name: string;
  icon: string;
  description: string;
  bookCount: number;
  color: string;
};

// 书籍类型
type Book = {
  id: string;
  title: string;
  author: string;
  genre: string;
  pages: number;
  rating: number;
  publishYear: number;
  description: string;
  shelf: string;
  cover: string;
  progress: number;
};

const BookshelfListApp: React.FC = () => {
  const [shelves, setShelves] = useState<Shelf[]>([
    { id: '1', name: '已读书籍', icon: '📚', description: '已经阅读过的书籍', bookCount: 8, color: '#f87171' },
    { id: '2', name: '想读书籍', icon: '📖', description: '计划阅读的书籍', bookCount: 5, color: '#60a5fa' },
    { id: '3', name: '正在阅读', icon: '👀', description: '当前正在阅读的书籍', bookCount: 3, color: '#34d399' },
    { id: '4', name: '技术书籍', icon: '💻', description: '编程和技术相关书籍', bookCount: 6, color: '#a78bfa' },
    { id: '5', name: '小说文学', icon: '📝', description: '小说和文学作品', bookCount: 7, color: '#fbbf24' },
    { id: '6', name: '个人收藏', icon: '❤️', description: '特别喜欢的书籍', bookCount: 4, color: '#fb7185' },
  ]);

  const [books] = useState<Book[]>([
    { id: '1', title: '活着', author: '余华', genre: '现代文学', pages: 191, rating: 9.1, publishYear: 1993, description: '一个普通人在时代变迁中的苦难历程', shelf: '已读书籍', cover: '', progress: 100 },
    { id: '2', title: '百年孤独', author: '加西亚·马尔克斯', genre: '魔幻现实主义', pages: 360, rating: 9.2, publishYear: 1967, description: '一个家族七代人的传奇故事', shelf: '已读书籍', cover: '', progress: 100 },
    { id: '3', title: 'JavaScript高级程序设计', author: '马特·弗利', genre: '编程技术', pages: 852, rating: 8.7, publishYear: 2012, description: '前端开发必备经典教材', shelf: '技术书籍', cover: '', progress: 45 },
    { id: '4', title: '红楼梦', author: '曹雪芹', genre: '古典文学', pages: 1200, rating: 9.6, publishYear: 1791, description: '中国古典小说的巅峰之作', shelf: '想读书籍', cover: '', progress: 0 },
    { id: '5', title: 'Effective Java', author: '约书亚·布洛克', genre: '编程技术', pages: 416, rating: 9.3, publishYear: 2017, description: 'Java编程的最佳实践指南', shelf: '正在阅读', cover: '', progress: 75 },
    { id: '6', title: '围城', author: '钱钟书', genre: '现代文学', pages: 311, rating: 8.9, publishYear: 1947, description: '描绘知识分子生活的讽刺小说', shelf: '已读书籍', cover: '', progress: 100 },
    { id: '7', title: '算法导论', author: '托马斯·科尔曼', genre: '计算机科学', pages: 1312, rating: 9.0, publishYear: 2009, description: '算法分析与设计的经典教材', shelf: '技术书籍', cover: '', progress: 20 },
    { id: '8', title: '1984', author: '乔治·奥威尔', genre: '反乌托邦小说', pages: 328, rating: 9.4, publishYear: 1949, description: '一部关于极权主义社会的警示小说', shelf: '个人收藏', cover: '', progress: 100 },
  ]);

  // 获取书架的书籍
  const getBooksForShelf = (shelfId: string) => {
    const shelf = shelves.find(s => s.id === shelfId);
    if (!shelf) return [];
    return books.filter(book => book.shelf === shelf.name);
  };

  // 渲染书架项
  const renderShelfItem = ({ item }: { item: Shelf }) => (
    <TouchableOpacity 
      style={styles.shelfCard}
      onPress={() => Alert.alert('书架详情', `进入 ${item.name} 书架`)}
    >
      <View style={[styles.shelfIcon, { backgroundColor: `${item.color}20` }]}>
        <Text style={[styles.shelfIconText, { color: item.color }]}>{item.icon}</Text>
      </View>
      
      <View style={styles.shelfInfo}>
        <Text style={styles.shelfName}>{item.name}</Text>
        <Text style={styles.shelfDescription}>{item.description}</Text>
        <Text style={styles.shelfBookCount}>{item.bookCount} 本书</Text>
      </View>
      
      <View style={styles.arrowContainer}>
        <Text style={styles.arrow}></Text>
      </View>
    </TouchableOpacity>
  );

  // 渲染书籍项
  const renderBookItem = ({ item }: { item: Book }) => (
    <View style={styles.bookCard}>
      <View style={styles.bookIcon}>
        <Text style={styles.bookIconText}>📘</Text>
      </View>
      
      <View style={styles.bookInfo}>
        <Text style={styles.bookTitle}>{item.title}</Text>
        <Text style={styles.bookAuthor}>{item.author}{item.genre}</Text>
        <Text style={styles.bookDetails}>{item.pages}页 • {item.publishYear}</Text>
        
        <View style={styles.ratingContainer}>
          <Text style={styles.rating}>{item.rating}</Text>
        </View>
        
        {item.progress > 0 && (
          <View style={styles.progressContainer}>
            <View style={styles.progressBar}>
              <View 
                style={[
                  styles.progressFill, 
                  { width: `${item.progress}%`, backgroundColor: item.progress === 100 ? '#34d399' : '#60a5fa' }
                ]} 
              />
            </View>
            <Text style={styles.progressText}>{item.progress}%</Text>
          </View>
        )}
      </View>
      
      <TouchableOpacity 
        style={styles.readButton}
        onPress={() => Alert.alert('阅读', `开始阅读 ${item.title}`)}
      >
        <Text style={styles.readButtonText}>
          {item.progress === 100 ? '重读' : item.progress > 0 ? '继续' : '阅读'}
        </Text>
      </TouchableOpacity>
    </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}>{shelves.length}</Text>
            <Text style={styles.statLabel}>书架数量</Text>
          </View>
          <View style={styles.statItem}>
            <Text style={styles.statValue}>{books.length}</Text>
            <Text style={styles.statLabel}>书籍总数</Text>
          </View>
          <View style={styles.statItem}>
            <Text style={styles.statValue}>
              {books.filter(b => b.progress === 100).length}
            </Text>
            <Text style={styles.statLabel}>已读完</Text>
          </View>
        </View>

        {/* 书架列表标题 */}
        <View style={styles.sectionHeader}>
          <Text style={styles.sectionTitle}>我的书架</Text>
          <Text style={styles.countText}>{shelves.length} 个书架</Text>
        </View>

        {/* 书架列表 */}
        <FlatList
          data={shelves}
          renderItem={renderShelfItem}
          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}>
              {shelves.slice(0, 3).map(shelf => (
                <TouchableOpacity 
                  key={shelf.id}
                  style={[styles.hotShelfCard, { borderColor: shelf.color }]}
                  onPress={() => Alert.alert('书架详情', `查看 ${shelf.name} 的详细信息`)}
                >
                  <Text style={[styles.hotShelfIcon, { color: shelf.color }]}>{shelf.icon}</Text>
                  <Text style={styles.hotShelfName}>{shelf.name}</Text>
                  <Text style={styles.hotShelfItemCount}>{shelf.bookCount}</Text>
                </TouchableOpacity>
              ))}
            </View>
          </ScrollView>
        </View>

        {/* 最近阅读 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>最近阅读</Text>
          <FlatList
            data={books.filter(b => b.progress > 0).slice(0, 3)}
            renderItem={renderBookItem}
            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',
  },
  shelfCard: {
    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,
  },
  shelfIcon: {
    width: 50,
    height: 50,
    borderRadius: 25,
    alignItems: 'center',
    justifyContent: 'center',
    marginRight: 16,
  },
  shelfIconText: {
    fontSize: 24,
  },
  shelfInfo: {
    flex: 1,
  },
  shelfName: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 4,
  },
  shelfDescription: {
    fontSize: 14,
    color: '#64748b',
    marginBottom: 4,
  },
  shelfBookCount: {
    fontSize: 12,
    color: '#94a3b8',
  },
  arrowContainer: {
    justifyContent: 'center',
  },
  arrow: {
    fontSize: 20,
    color: '#94a3b8',
  },
  section: {
    marginBottom: 16,
  },
  horizontalScroll: {
    paddingVertical: 8,
  },
  horizontalContainer: {
    flexDirection: 'row',
  },
  hotShelfCard: {
    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,
  },
  hotShelfIcon: {
    fontSize: 24,
    marginBottom: 4,
  },
  hotShelfName: {
    fontSize: 14,
    fontWeight: 'bold',
    color: '#1e293b',
    textAlign: 'center',
  },
  hotShelfItemCount: {
    fontSize: 12,
    color: '#64748b',
  },
  bookCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    flexDirection: 'row',
    alignItems: 'center',
    padding: 12,
    marginBottom: 8,
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  bookIcon: {
    width: 40,
    height: 40,
    borderRadius: 8,
    backgroundColor: '#e2e8f0',
    alignItems: 'center',
    justifyContent: 'center',
    marginRight: 12,
  },
  bookIconText: {
    fontSize: 20,
  },
  bookInfo: {
    flex: 1,
  },
  bookTitle: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 2,
  },
  bookAuthor: {
    fontSize: 12,
    color: '#64748b',
    marginBottom: 2,
  },
  bookDetails: {
    fontSize: 12,
    color: '#94a3b8',
    marginBottom: 4,
  },
  ratingContainer: {
    flexDirection: 'row',
  },
  rating: {
    fontSize: 12,
    color: '#f59e0b',
    fontWeight: '500',
  },
  progressContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    marginTop: 4,
  },
  progressBar: {
    flex: 1,
    height: 4,
    backgroundColor: '#e2e8f0',
    borderRadius: 2,
    marginRight: 8,
  },
  progressFill: {
    height: '100%',
    borderRadius: 2,
  },
  progressText: {
    fontSize: 12,
    color: '#64748b',
  },
  readButton: {
    backgroundColor: '#3b82f6',
    paddingHorizontal: 12,
    paddingVertical: 6,
    borderRadius: 6,
  },
  readButtonText: {
    fontSize: 12,
    color: '#ffffff',
    fontWeight: '500',
  },
  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 BookshelfListApp;

请添加图片描述


打包

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

在这里插入图片描述

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

在这里插入图片描述

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

请添加图片描述

React Native的跨平台能力与组件化设计使其能够高效适配多平台,包括鸿蒙系统。本文通过BookshelfListApp组件展示了如何构建跨平台书架应用,重点分析了数据模型、状态管理和样式系统。应用使用TypeScript定义书架(Shelf)和书籍(Book)类型,确保类型安全;采用useState管理状态,实现响应式更新;利用Flexbox布局和动态样式实现跨平台UI一致性。特别探讨了React Native组件与鸿蒙原生组件的映射机制,以及性能优化策略,如FlatList虚拟滚动和条件渲染。该案例证明了React Native在构建复杂跨平台应用时的可行性和优势。

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

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐