该手风琴组件采用了经典的状态驱动设计模式,通过管理每个折叠项的 expanded 状态来控制内容的展开与收起。这种设计模式在 React Native 鸿蒙跨端开发中具有很好的通用性,能够适应不同平台的渲染机制。组件整体结构清晰,分为头部、内容区和配置选项,遵循了单一职责原则,便于维护和扩展。

在手风琴项的渲染逻辑中,使用了条件渲染 {item.expanded && (...)} 来控制内容的显示与隐藏,这种方式在 React Native 和 HarmonyOS ArkUI 中都能高效执行,不会产生额外的性能开销。同时,组件支持单选模式(点击一个展开项时自动收起其他项),通过 toggleAccordion 函数实现,这种交互逻辑可以直接复用在跨端开发中。

数据模型

应用使用 TypeScript 定义了 AccordionItem 类型,包含 idtitlecontentexpanded 四个属性。这种强类型设计在跨端开发中具有显著优势:

  • 编译阶段捕获类型错误,减少运行时异常
  • 提供清晰的接口定义,便于团队协作
  • 支持 IDE 智能提示,提高开发效率
  • 确保数据结构在不同平台上的一致性

在 HarmonyOS ArkUI 中,TypeScript 类型定义同样受到支持,能够直接复用,这大大降低了跨端迁移的成本。强类型设计也使得组件的 Props 和 State 更加明确,便于后续的组件扩展和功能增强。

状态管理

应用使用 React Hooks 中的 useState 管理手风琴项的展开状态,这是 React Native 中最基础的状态管理方式。在 HarmonyOS ArkUI 中,useState 可以映射到 @State 装饰器,两者都能实现状态的响应式更新,当状态变化时自动触发组件重渲染。

toggleAccordion 函数是状态管理的核心,它通过更新 expanded 状态来控制手风琴的展开与收起。这种纯 JavaScript 逻辑在跨端开发中可以直接复用,无需针对不同平台进行修改。需要注意的是,在处理大量手风琴项时,频繁的状态更新可能导致性能问题,建议在跨端应用中考虑使用 useMemouseCallback 进行优化,避免不必要的组件重渲染。

UI 组件

应用使用了 React Native 核心组件库构建用户界面,主要包括:

  • SafeAreaView 确保内容在安全区域内显示,适配不同设备的刘海屏和底部手势区域
  • ScrollView 实现可滚动的内容区域,支持长列表的展示
  • TouchableOpacity 实现可点击的手风琴标题,提供视觉反馈
  • ViewText 构建基础界面元素
  • StyleSheet 实现样式与逻辑分离
  • Alert 用于配置选项的弹窗提示
  • Dimensions 获取屏幕尺寸,实现响应式布局

在 HarmonyOS ArkUI 中,这些组件可以映射到对应的 ArkUI 组件:

  • SafeAreaView 对应 ArkUI 的 SafeArea 组件,确保内容在安全区域内显示
  • ScrollView 对应 ArkUI 的 Scroll 组件,同样支持垂直和水平滚动
  • TouchableOpacity 对应 ArkUI 的 Button 组件或 Gesture 手势组件,通过 onClick 事件实现交互
  • ViewText 是 ArkUI 的基础组件,API 设计相似,便于迁移
  • StyleSheet 的样式定义可以通过工具转换为 ArkUI 的样式系统,两者都基于 Flexbox 布局
  • Alert 对应 ArkUI 的 dialog.showAlertDialog API,需要进行适配封装
  • Dimensions.get('window') 对应 ArkUI 的 window.getWindowProperties API,用于获取屏幕尺寸

样式

应用使用 StyleSheet 定义组件样式,采用了模块化的样式设计。React Native 的样式系统与 CSS 类似,但在属性名称和值上存在差异(如 backgroundColor 而非 background-color,使用对象而非字符串)。在 HarmonyOS ArkUI 中,样式系统采用了类似 CSS 的语法,但支持的数据类型和属性可能有所不同。

为了实现跨端样式的一致性,该应用采用了以下策略:

  • 使用 Flexbox 布局作为主要布局方式,确保在不同平台上的表现一致
  • 采用相对单位(如 width: '100%')而非固定像素值,适应不同设备屏幕尺寸
  • 提取公共样式(如 accordionItemaccordionHeader),便于复用和维护
  • 使用主题色变量(虽然代码中未显式定义,但可以扩展),便于统一管理和主题切换

需要注意的是,部分样式属性在不同平台上的表现可能存在差异,例如阴影效果、圆角处理等。建议在跨端项目中使用条件样式或平台特定样式,以确保在所有平台上的视觉一致性。

交互

应用实现了流畅的手风琴交互体验,包括:

  • 点击标题时的视觉反馈(通过 TouchableOpacity 的透明度变化实现)
  • 清晰的展开/收起状态指示(通过 +/ 图标实现)
  • 平滑的内容展开/收起过渡(虽然当前代码未实现动画,但可以轻松添加)
  • 单选模式的逻辑处理,确保一次只有一个项展开

在跨端开发中,用户体验的一致性是关键。TouchableOpacity 的透明度变化效果在 HarmonyOS 中可以通过 Button 组件的 stateEffect 属性实现,或者使用 Gesture 组件结合动画效果。展开/收起动画可以使用 React Native 的 Animated API 或 HarmonyOS ArkUI 的 animateTo 方法实现,两者都支持流畅的过渡效果。

该手风琴组件展示了 React Native 跨端开发的核心技术要点,包括组件架构设计、数据模型定义、状态管理、UI 组件使用和样式系统等。在 HarmonyOS 跨端开发中,这些技术大多能够直接复用或通过适配实现,体现了 React Native 跨端开发的高效性和灵活性。


手风琴(Accordion)组件作为移动端界面中高效组织层级化信息的核心控件,在FAQ、设置面板、产品说明等场景中广泛应用——其“折叠-展开”的交互形态既能节省有限的屏幕空间,又能让用户按需获取信息,是移动端交互设计的经典范式。本文以 React Native 开发的手风琴组件演示应用为例,深度拆解其“状态驱动交互、组件化封装、样式分层设计”的核心实现逻辑,并系统阐述向鸿蒙(HarmonyOS)ArkTS 跨端迁移的技术路径,聚焦“交互逻辑复用、状态管理等价转换、视觉体验跨端一致”三大核心维度,为移动端手风琴组件的跨端开发提供可落地的技术参考。

数据模型

该手风琴组件的底层基石是“类型化数据模型 + 精准状态管理”,完全贴合移动端组件的开发规范,也是跨端复用的核心前提:

  • 业务类型定义:AccordionItem 类型精准定义手风琴项的核心属性,包含 id(唯一标识)、title(标题)、content(内容)、expanded(展开状态),4 个字段完整支撑手风琴项的展示与交互;TypeScript 强类型约束不仅避免了运行时类型错误,更让跨端开发时的数据结构保持 100% 一致。
  • 状态管理策略:采用 useState 管理手风琴项数组 accordionItems,初始值预置 6 个典型的手风琴项(涵盖定义、使用方法、优势、场景等),覆盖手风琴组件的核心演示场景;expanded 字段作为每个项的状态标识,是实现“折叠-展开”交互的核心开关。
  • 核心交互逻辑:toggleAccordion 函数是手风琴组件的灵魂——接收 id 参数后,通过 map 遍历数组,仅切换目标项的 expanded 状态,同时将其他项的 expanded 置为 false,实现“单选模式”(一次仅展开一个项);这种“不可变数据更新”方式符合 React 状态管理的最佳实践,避免直接修改原数组导致的状态不一致问题,也为跨端复用提供了无副作用的纯逻辑资产。

组件化

React Native 端将手风琴组件拆解为“页面容器 + 手风琴列表 + 手风琴项”三层结构,组件化封装让代码复用性和跨端迁移效率大幅提升:

  • 手风琴项封装:renderAccordionItem 函数接收单个 AccordionItem 对象,返回完整的手风琴项 UI 结构,包含“头部(标题+图标)+ 内容区”两部分;头部采用 TouchableOpacity 封装点击交互,点击触发 toggleAccordion 函数;内容区通过 {item.expanded && ...} 实现条件渲染,仅当 expandedtrue 时展示内容,这种“按需渲染”策略既节省渲染性能,又符合手风琴的交互逻辑。
  • 视觉交互增强:头部右侧的图标(+/)随 expanded 状态动态切换,为用户提供清晰的视觉反馈;标题区设置 flex: 1 保证标题文本自适应宽度,图标始终右对齐,符合移动端界面的布局规范。
  • 列表渲染逻辑:通过 map 遍历 accordionItems 数组,调用 renderAccordionItem 渲染每个手风琴项,数组项的 id 作为隐式的 key(生产环境建议显式指定 key={item.id}),保证列表更新的性能和稳定性。

样式

该组件的样式设计遵循“功能分层 + 视觉层级”原则,既保证了组件的美观性,又为跨端样式迁移提供了清晰的映射关系:

  • 样式分层:StyleSheet.create 中定义的样式分为容器层(container/content)、卡片层(introCard/accordionItem/instructionsCard 等)、元素层(accordionHeader/accordionTitle 等)、交互层(activeNavItem 等),每层样式职责单一,便于跨端时逐层级等价转换。
  • 视觉优化:
    • 手风琴项采用 borderRadius: 8 圆角、elevation: 1 阴影,提升视觉层次感;overflow: 'hidden' 保证内容区展开时圆角效果一致;
    • 头部背景色(#f1f5f9)与内容区背景色(#ffffff)形成对比,强化视觉层级;
    • 底部导航的 activeNavItem 通过顶部 2px 蓝色边框标识当前选中项,符合移动端导航的交互习惯;
    • 辅助卡片(介绍、使用说明、配置选项等)统一采用 borderRadius: 12、阴影、内边距,保证整体视觉风格一致。
  • 响应式适配:通过 Dimensions.get('window') 获取屏幕宽高(虽未直接使用,但为后续响应式适配预留了扩展空间);文本行高(lineHeight)、内边距(padding)的精细化设置,保证不同设备上的可读性。

演示场景

该应用不仅实现了手风琴组件的核心功能,还封装了完整的演示场景,覆盖组件介绍、使用说明、配置选项、应用场景、组件特点等模块,为跨端迁移提供了完整的 UI 参考:

  • 辅助信息模块:introCard 介绍手风琴组件的定义,instructionsCard 说明使用方法,configCard 提供配置选项(多选模式、动画设置、样式设置),exampleCard 展示典型应用场景,featuresCard 总结组件特点;
  • 交互增强:配置选项和应用场景模块采用 TouchableOpacity 封装点击交互,点击触发 Alert.alert 提示,模拟实际应用中的配置逻辑;
  • 底部导航:包含首页、组件、文档、示例四个入口,当前选中“首页”,为演示应用提供完整的导航体系。

手风琴组件的跨端适配核心是“数据模型 100% 复用、交互逻辑 100% 复用、UI 组件语义等价重构、视觉体验一致”,React Native 与鸿蒙 ArkTS 的核心能力可实现精准映射,以下是手风琴组件关键技术点的等价转换:

React Native 核心能力 鸿蒙 ArkTS 等价实现 手风琴组件适配要点
TypeScript 类型定义(AccordionItem) TypeScript 类型定义(AccordionItem) 完全复用类型定义,保证手风琴项数据结构一致性
useState 状态管理(accordionItems) @State 装饰器 数组初始值完全复用,expanded 状态更新逻辑一致
toggleAccordion 核心交互函数 同名类方法 100% 复用逻辑,仅调整 this 指向,保证单选模式一致
条件渲染(item.expanded && ... if 条件语句 复用展开/折叠判断逻辑,保证内容区渲染一致
TouchableOpacity 点击交互 Gesture 手势/Button 组件 onPressonTap/onClick,交互逻辑一致
map 遍历渲染列表 ForEach 循环 遍历逻辑一致,id 作为唯一标识保证列表稳定性
StyleSheet.create 样式管理 内联样式/样式常量 样式属性等价映射(backgroundColor/borderRadius 等)
Alert.alert 交互反馈 AlertDialog.show 弹窗内容完全复用,保证交互反馈一致
ScrollView 滚动容器 ScrollView 组件 滚动行为和样式属性等价映射
交互逻辑

React Native 端的 TypeScript 类型定义、初始数据、核心交互函数可直接复制到鸿蒙 ArkTS 工程,仅需调整状态管理方式和 this 指向:

// 鸿蒙 ArkTS 端核心代码
@Entry
@Component
struct AccordionComponent {
  // 100% 复用 React Native 端的类型定义
  type AccordionItem = {
    id: string;
    title: string;
    content: string;
    expanded: boolean;
  };

  // 等价于 React Native 的 useState,初始值完全复用
  @State accordionItems: AccordionItem[] = [
    { 
      id: '1', 
      title: '什么是手风琴组件?', 
      content: '手风琴组件是一种允许用户展开和折叠内容区域的界面组件。它通过节省空间的方式展示大量信息,用户可以点击标题来展开或收起相应的内容。', 
      expanded: false 
    },
    { 
      id: '2', 
      title: '如何使用手风琴组件?', 
      content: '点击手风琴的标题部分即可展开或收起内容。在移动设备上,这种组件特别有用,因为它可以有效地组织信息并节省屏幕空间。', 
      expanded: false 
    },
    // 其他手风琴项...
  ];

  // 核心交互函数(100% 复用逻辑,仅调整 this 指向)
  toggleAccordion(id: string) {
    this.accordionItems = this.accordionItems.map(item => 
      item.id === id 
        ? { ...item, expanded: !item.expanded } 
        : { ...item, expanded: false } // 单选模式:收起其他项
    );
  }

  // 组件构建逻辑...
}

该实现中,AccordionItem 类型定义、初始数据数组、toggleAccordion 函数逻辑完全复用 React Native 端代码,仅将 useState 替换为 @State 装饰器,函数内的 setAccordionItems 替换为直接赋值 this.accordionItems,保证了手风琴组件核心逻辑的跨端一致性。

手风琴组件

React Native 端的手风琴项在鸿蒙端通过 @Builder 装饰器封装,条件渲染、点击交互、视觉样式完全复刻:

// 鸿蒙 ArkTS 端手风琴项封装
@Builder
renderAccordionItem(item: this.AccordionItem) {
  Column()
    .backgroundColor('#ffffff')
    .borderRadius(8)
    .marginBottom(8)
    .overflow(Overflow.Hidden)
    .shadow({ radius: 2, color: '#000', opacity: 0.1, offsetX: 0, offsetY: 1 })
  {
    // 手风琴头部(点击区域)
    Row()
      .justifyContent(FlexAlign.SpaceBetween)
      .alignItems(ItemAlign.Center)
      .padding(16)
      .backgroundColor('#f1f5f9')
      .onTap(() => this.toggleAccordion(item.id))
    {
      // 标题
      Text(item.title)
        .fontSize(16)
        .fontWeight(FontWeight.Medium)
        .color('#1e293b')
        .flexGrow(1);
      
      // 展开/折叠图标
      Text(item.expanded ? '−' : '+')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .color('#64748b');
    }

    // 内容区(条件渲染)
    if (item.expanded) {
      Column()
        .padding(16)
        .backgroundColor('#ffffff')
      {
        Text(item.content)
          .fontSize(14)
          .color('#64748b')
          .lineHeight(20);
      }
    }
  }
}

该实现完全复刻了 React Native 端手风琴项的结构:

  • 头部采用 Row 布局,justifyContent(FlexAlign.SpaceBetween) 实现标题左对齐、图标右对齐,onTap 替代 onPress 触发交互;
  • 内容区通过 if (item.expanded) 实现条件渲染,与 React Native 端的 {item.expanded && ...} 逻辑完全一致;
  • 样式属性一一映射:backgroundColor/borderRadius/marginBottom/padding 等属性值完全复用,overflow: 'hidden' 替换为 overflow(Overflow.Hidden),阴影效果通过 shadow 方法实现,保证视觉体验一致。

真实演示案例代码:


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

// Base64 图标库
const ICONS_BASE64 = {
  arrow: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  plus: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  minus: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  info: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  help: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  settings: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  close: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  home: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
};

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

// 手风琴项目类型
type AccordionItem = {
  id: string;
  title: string;
  content: string;
  expanded: boolean;
};

const AccordionComponent: React.FC = () => {
  const [accordionItems, setAccordionItems] = useState<AccordionItem[]>([
    { 
      id: '1', 
      title: '什么是手风琴组件?', 
      content: '手风琴组件是一种允许用户展开和折叠内容区域的界面组件。它通过节省空间的方式展示大量信息,用户可以点击标题来展开或收起相应的内容。', 
      expanded: false 
    },
    { 
      id: '2', 
      title: '如何使用手风琴组件?', 
      content: '点击手风琴的标题部分即可展开或收起内容。在移动设备上,这种组件特别有用,因为它可以有效地组织信息并节省屏幕空间。', 
      expanded: false 
    },
    { 
      id: '3', 
      title: '手风琴组件的优势', 
      content: '1. 节省屏幕空间\n2. 组织复杂信息\n3. 提升用户体验\n4. 易于导航\n5. 响应式设计友好', 
      expanded: false 
    },
    { 
      id: '4', 
      title: '应用场景', 
      content: '手风琴组件常用于FAQ页面、产品规格说明、步骤指导、设置面板等需要组织大量信息的场景。', 
      expanded: false 
    },
    { 
      id: '5', 
      title: '最佳实践', 
      content: '1. 保持标题简洁明了\n2. 内容长度适中\n3. 使用视觉指示器\n4. 提供平滑动画\n5. 确保无障碍访问', 
      expanded: false 
    },
    { 
      id: '6', 
      title: '设计建议', 
      content: '建议使用对比色突出标题,为展开/收起状态提供不同的图标,以及适当的内边距和间距来增强可读性。', 
      expanded: false 
    },
  ]);

  // 切换手风琴项目展开状态
  const toggleAccordion = (id: string) => {
    setAccordionItems(items => 
      items.map(item => 
        item.id === id 
          ? { ...item, expanded: !item.expanded } 
          : { ...item, expanded: false } // 收起其他项目(单选模式)
      )
    );
  };

  // 渲染手风琴项
  const renderAccordionItem = (item: AccordionItem) => (
    <View style={styles.accordionItem}>
      <TouchableOpacity 
        style={styles.accordionHeader}
        onPress={() => toggleAccordion(item.id)}
      >
        <Text style={styles.accordionTitle}>{item.title}</Text>
        <Text style={styles.accordionIcon}>{item.expanded ? '−' : '+'}</Text>
      </TouchableOpacity>
      
      {item.expanded && (
        <View style={styles.accordionContent}>
          <Text style={styles.accordionContentText}>{item.content}</Text>
        </View>
      )}
    </View>
  );

  return (
    <SafeAreaView style={styles.container}>
      {/* 头部 */}
      <View style={styles.header}>
        <Text style={styles.title}>手风琴组件演示</Text>
      </View>

      <ScrollView style={styles.content}>
        {/* 组件介绍 */}
        <View style={styles.introCard}>
          <Text style={styles.introTitle}>手风琴组件</Text>
          <Text style={styles.introText}>
            手风琴组件是一种交互式界面元素,允许用户通过点击标题来展开或收起内容区域。
            它非常适合在有限的空间内展示多个信息块。
          </Text>
        </View>

        {/* 手风琴列表 */}
        <View style={styles.accordionContainer}>
          {accordionItems.map(item => renderAccordionItem(item))}
        </View>

        {/* 使用说明 */}
        <View style={styles.instructionsCard}>
          <Text style={styles.instructionsTitle}>使用说明</Text>
          <Text style={styles.instructionsText}>• 点击标题展开内容</Text>
          <Text style={styles.instructionsText}>• 再次点击收起内容</Text>
          <Text style={styles.instructionsText}>• 一次只能展开一个项目</Text>
          <Text style={styles.instructionsText}>• 适合展示层级信息</Text>
        </View>

        {/* 配置选项 */}
        <View style={styles.configCard}>
          <Text style={styles.configTitle}>配置选项</Text>
          <View style={styles.configOptions}>
            <TouchableOpacity 
              style={styles.configButton}
              onPress={() => Alert.alert('多选模式', '切换到多选模式,可以同时展开多个项目')}
            >
              <Text style={styles.configButtonText}>多选模式</Text>
            </TouchableOpacity>
            <TouchableOpacity 
              style={styles.configButton}
              onPress={() => Alert.alert('动画设置', '调整展开/收起动画效果')}
            >
              <Text style={styles.configButtonText}>动画设置</Text>
            </TouchableOpacity>
            <TouchableOpacity 
              style={styles.configButton}
              onPress={() => Alert.alert('样式设置', '自定义手风琴外观')}
            >
              <Text style={styles.configButtonText}>样式设置</Text>
            </TouchableOpacity>
          </View>
        </View>

        {/* 示例应用 */}
        <View style={styles.exampleCard}>
          <Text style={styles.exampleTitle}>示例应用场景</Text>
          <View style={styles.exampleItems}>
            <TouchableOpacity 
              style={styles.exampleItem}
              onPress={() => Alert.alert('FAQ页面', '常见问题解答页面')}
            >
              <Text style={styles.exampleItemText}>FAQ页面</Text>
            </TouchableOpacity>
            <TouchableOpacity 
              style={styles.exampleItem}
              onPress={() => Alert.alert('产品规格', '展示产品的详细规格信息')}
            >
              <Text style={styles.exampleItemText}>产品规格</Text>
            </TouchableOpacity>
            <TouchableOpacity 
              style={styles.exampleItem}
              onPress={() => Alert.alert('设置面板', '应用程序的设置选项')}
            >
              <Text style={styles.exampleItemText}>设置面板</Text>
            </TouchableOpacity>
          </View>
        </View>

        {/* 组件特点 */}
        <View style={styles.featuresCard}>
          <Text style={styles.featuresTitle}>组件特点</Text>
          <View style={styles.featureItems}>
            <View style={styles.featureItem}>
              <Text style={styles.featureIcon}></Text>
              <Text style={styles.featureText}>节省空间</Text>
            </View>
            <View style={styles.featureItem}>
              <Text style={styles.featureIcon}>📱</Text>
              <Text style={styles.featureText}>响应式设计</Text>
            </View>
            <View style={styles.featureItem}>
              <Text style={styles.featureIcon}></Text>
              <Text style={styles.featureText}>平滑动画</Text>
            </View>
            <View style={styles.featureItem}>
              <Text style={styles.featureIcon}>🎨</Text>
              <Text style={styles.featureText}>高度可定制</Text>
            </View>
          </View>
        </View>
      </ScrollView>

      {/* 底部导航 */}
      <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',
    textAlign: 'center',
  },
  content: {
    flex: 1,
    padding: 16,
  },
  introCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 16,
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  introTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 8,
  },
  introText: {
    fontSize: 14,
    color: '#64748b',
    lineHeight: 20,
  },
  accordionContainer: {
    marginBottom: 16,
  },
  accordionItem: {
    backgroundColor: '#ffffff',
    borderRadius: 8,
    marginBottom: 8,
    overflow: 'hidden',
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  accordionHeader: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 16,
    backgroundColor: '#f1f5f9',
  },
  accordionTitle: {
    fontSize: 16,
    fontWeight: '500',
    color: '#1e293b',
    flex: 1,
  },
  accordionIcon: {
    fontSize: 20,
    fontWeight: 'bold',
    color: '#64748b',
  },
  accordionContent: {
    padding: 16,
    backgroundColor: '#ffffff',
  },
  accordionContentText: {
    fontSize: 14,
    color: '#64748b',
    lineHeight: 20,
  },
  instructionsCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 16,
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  instructionsTitle: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 12,
  },
  instructionsText: {
    fontSize: 14,
    color: '#64748b',
    lineHeight: 22,
    marginBottom: 8,
  },
  configCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 16,
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  configTitle: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 12,
  },
  configOptions: {
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
  configButton: {
    backgroundColor: '#e2e8f0',
    paddingHorizontal: 12,
    paddingVertical: 8,
    borderRadius: 6,
    flex: 1,
    marginHorizontal: 4,
  },
  configButtonText: {
    fontSize: 12,
    color: '#1e293b',
    textAlign: 'center',
  },
  exampleCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 16,
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  exampleTitle: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 12,
  },
  exampleItems: {
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
  exampleItem: {
    backgroundColor: '#dbeafe',
    paddingHorizontal: 12,
    paddingVertical: 8,
    borderRadius: 6,
    flex: 1,
    marginHorizontal: 4,
  },
  exampleItemText: {
    fontSize: 12,
    color: '#1e3a8a',
    textAlign: 'center',
  },
  featuresCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    padding: 16,
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  featuresTitle: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 12,
  },
  featureItems: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    justifyContent: 'space-between',
  },
  featureItem: {
    flexDirection: 'row',
    alignItems: 'center',
    marginBottom: 8,
    width: '48%',
  },
  featureIcon: {
    fontSize: 18,
    marginRight: 8,
  },
  featureText: {
    fontSize: 14,
    color: '#1e293b',
  },
  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 AccordionComponent;

请添加图片描述


打包

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

在这里插入图片描述

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

在这里插入图片描述

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

请添加图片描述
本文详细解析了React Native手风琴组件的实现原理与跨端迁移方案。该组件采用类型化数据模型(AccordionItem)定义核心属性,通过useState管理展开状态,toggleAccordion函数实现单选模式交互。组件采用三层架构设计,包含条件渲染的内容区和视觉反馈机制。样式系统基于StyleSheet实现分层管理,支持圆角、阴影等视觉效果。文章重点阐述了该组件向鸿蒙ArkUI迁移的技术路径,包括数据模型复用、状态管理转换(useState→@State)、UI组件映射等核心环节,为移动端手风琴组件的跨平台开发提供了完整解决方案。

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

Logo

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

更多推荐