这个狗狗领养中心应用采用了现代 React Native 组件化架构,通过清晰的职责分离实现了代码的模块化和可维护性。核心组件 DogCard 作为独立的可复用单元,负责单个狗狗信息的展示和交互,而 AdoptionList 作为主容器,负责状态管理和狗狗列表的渲染。

数据结构

const DOGS_DATA = [
  {
    id: 1,
    name: '金毛旺财',
    breed: '金毛寻回犬',
    age: '2岁',
    gender: '公',
    size: '大型',
    location: '北京市朝阳区',
    description: '性格温顺,喜欢与人亲近,适合家庭饲养。',
    image: 'https://picsum.photos/300/200?random=1',
    isFavorite: false,
    tags: ['友善', '活泼', '聪明']
  },
  // 更多狗狗数据...
];

数据结构设计全面,包含了狗狗的基本信息、外观特征、性格特点和领养状态等。使用 isFavorite 字段标记收藏状态,tags 数组存储狗狗的性格标签,这种结构化的数据设计为后续的功能扩展和数据管理提供了便利。

可复用 DogCard 组件

const DogCard: React.FC<{ 
  dog: any, 
  onToggleFavorite: (id: number) => void, 
  onAdopt: (id: number) => void 
}> = ({ dog, onToggleFavorite, onAdopt }) => {
  // 组件实现...
};

DogCard 组件设计为高度可配置的通用组件,通过 props 接收狗狗数据和回调函数。这种设计使得组件可以在不同场景中灵活使用,只需传入不同的参数即可实现不同的功能。组件内部包含了图片、基本信息、属性标签和操作按钮等完整的展示内容。

状态管理

const [dogs, setDogs] = useState(DOGS_DATA);

const toggleFavorite = (id: number) => {
  setDogs(dogs.map(dog => 
    dog.id === id ? { ...dog, isFavorite: !dog.isFavorite } : dog 
  ));
};

const handleAdopt = (id: number) => {
  alert(`已提交对 ${dogs.find(d => d.id === id)?.name} 的领养申请`);
};

使用 useState Hook 管理狗狗列表状态,初始值为模拟数据 DOGS_DATAtoggleFavorite 函数通过 map 方法更新指定狗狗的收藏状态,实现了状态的响应式更新。handleAdopt 函数通过 alert 显示领养申请提交成功的信息,提供了基本的用户反馈。

交互

<TouchableOpacity onPress={() => onToggleFavorite(dog.id)}>
  <Text style={styles.favoriteIcon}>{dog.isFavorite ? '❤️' : '🤍'}</Text>
</TouchableOpacity>

<TouchableOpacity style={styles.adoptionButton} onPress={() => onAdopt(dog.id)}>
  <Text style={styles.adoptionButtonText}>申请领养</Text>
</TouchableOpacity>

通过 TouchableOpacity 实现了收藏和领养按钮的点击交互,点击收藏按钮会切换图标状态,点击领养按钮会触发领养申请。这种直观的交互设计提升了用户体验,使得操作流程更加顺畅。

卡片式布局

<View style={styles.dogCard}>
  <Image source={{ uri: dog.image }} style={styles.dogImage} />
  <View style={styles.dogInfo}>
    {/* 狗狗信息 */}
  </View>
</View>

狗狗卡片采用了垂直堆叠的布局结构,顶部是狗狗图片,下方是详细信息。这种卡片式布局在移动应用中非常常见,能够清晰地展示信息,同时保持界面的整洁和有序。

响应式

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

通过 Dimensions.get('window') 获取屏幕宽度,为后续的响应式布局计算提供基础。虽然在当前实现中没有直接使用这个值进行动态计算,但这种模式为后续的布局调整(如适配不同屏幕尺寸)预留了扩展空间。


  1. 组件映射

    • SafeAreaViewSafeAreaFlex 容器
    • ScrollViewListScroll 组件
    • TouchableOpacityButtonText + 手势事件
    • ImageImage 组件
    • ViewFlex 容器
    • TextText 组件
  2. 图片加载适配

    • React Native 中使用 source={{ uri: dog.image }} 加载网络图片
    • 鸿蒙系统中可以使用 Image 组件的 src 属性,语法类似但可能需要调整
  3. 样式适配

    • 鸿蒙系统的样式定义方式与 React Native 类似,但属性名称可能略有不同
    • 例如,shadow 相关属性在鸿蒙中需要使用 elevation 或其他等效属性
    • 尺寸单位在鸿蒙中默认使用 vp,与 React Native 的密度无关像素概念类似
  4. 状态管理适配

    • React Native 中使用 useState Hook 管理状态
    • 鸿蒙系统中可以使用 @State 装饰器实现类似的状态管理
    • 对于复杂状态,可以使用鸿蒙的 AppStorageLocalStorage
  5. 类型定义优化

    • 当前代码使用 any 类型定义 dog 属性,建议使用 TypeScript 接口明确类型:
    interface Dog {
      id: number;
      name: string;
      breed: string;
      age: string;
      gender: string;
      size: string;
      location: string;
      description: string;
      image: string;
      isFavorite: boolean;
      tags: string[];
    }
    
    const DogCard: React.FC<{ 
      dog: Dog; 
      onToggleFavorite: (id: number) => void; 
      onAdopt: (id: number) => void; 
    }> = ({ dog, onToggleFavorite, onAdopt }) => {
      // 实现...
    };
    
  6. 组件复用优化

    • 考虑使用 React.memo 包裹 DogCard 组件,减少不必要的重渲染:
    const DogCard: React.FC<{ 
      dog: Dog; 
      onToggleFavorite: (id: number) => void; 
      onAdopt: (id: number) => void; 
    }> = React.memo(({ dog, onToggleFavorite, onAdopt }) => {
      // 实现...
    });
    
  7. 列表性能优化

    • 对于较长的狗狗列表,建议使用 FlatList 替代 ScrollView + map 的组合,利用虚拟化提升滚动性能:
    <FlatList
      data={dogs}
      keyExtractor={(item) => item.id.toString()}
      renderItem={({ item }) => (
        <DogCard
          dog={item}
          onToggleFavorite={toggleFavorite}
          onAdopt={handleAdopt}
        />
      )}
      contentContainerStyle={styles.content}
    />
    
  8. 图片加载优化

    • 添加图片加载状态和错误处理,提升用户体验:
    <Image 
      source={{ uri: dog.image }} 
      style={styles.dogImage}
      resizeMode="cover"
      onError={(error) => console.log('Image load error:', error)}
    />
    
  9. 可访问性优化

    • 添加 accessibilityLabel 属性,提高应用的可访问性:
    <TouchableOpacity 
      style={styles.adoptionButton} 
      onPress={() => onAdopt(dog.id)}
      accessibilityLabel={`申请领养 ${dog.name}`}
    >
      <Text style={styles.adoptionButtonText}>申请领养</Text>
    </TouchableOpacity>
    

这个狗狗领养中心应用展示了 React Native 跨端开发的核心技术要点,通过合理的组件设计、清晰的状态管理和细致的样式管理,实现了一个功能完整、用户体验良好的领养平台。在鸿蒙系统适配方面,通过组件映射、样式适配和布局调整,可以快速实现跨端迁移,保持功能和视觉效果的一致性。


本次解析的代码是一套基于React Native开发的狗狗领养中心实战应用,采用经典的列表+卡片式布局设计,整合了数据渲染、状态管理、组件化拆分、原生样式布局、交互事件处理等核心开发能力,同时实现了收藏切换、领养申请、底部导航等实际业务功能。所有实现均基于React Native原生API与TypeScript基础约束,无第三方UI库依赖,可无缝适配React Native for HarmonyOS鸿蒙桥接方案,实现Android、iOS、鸿蒙多端的原生渲染与交互一致性。本文将从组件化拆分设计状态驱动的业务逻辑卡片式布局的跨端适配样式系统的工程化设计鸿蒙跨端兼容核心要点等维度,深度解读该实战项目的技术实现思路,剖析React Native在实际业务场景中鸿蒙跨端开发的工程化价值。

一、技术栈

本实战项目延续React Native + TypeScript的核心技术栈,以函数式组件为基础,结合useState实现业务状态管理,通过原生组件实现UI渲染与交互,所有技术选型均围绕鸿蒙跨端兼容业务实用性开发工程化原生体验四大核心原则展开,核心选型与技术特性如下:

  • 基础原生组件:选用SafeAreaViewViewTextTouchableOpacityImageScrollView等React Native核心原生组件,均为React Native for HarmonyOS已完成深度桥接的基础组件,底层编译为各平台原生组件(鸿蒙Component、Android View、iOS UIView),基于原生渲染引擎执行,规避WebView渲染的性能损耗与布局兼容问题,保证多端原生交互与视觉体验;
  • 核心能力组件Image组件支持远程图片加载(URI方式),完美适配鸿蒙平台的网络图片渲染机制;ScrollView实现长列表的滚动展示,桥接各平台原生滚动控件,适配鸿蒙大屏设备(平板、折叠屏)的内容展示;DimensionsAPI获取设备窗口宽度,为跨端自适应布局提供基础;
  • React核心能力useState实现应用的核心业务状态管理(狗狗收藏状态),遵循React声明式编程状态驱动渲染核心思想,与鸿蒙ArkUI的@State装饰器状态管理理念高度统一,为跨端业务逻辑一致性提供基础;
  • 轻量组件化拆分:采用容器组件+展示组件的拆分思路,将页面拆分为AdoptionList(容器/页面组件,负责数据管理、逻辑处理)与DogCard(展示/原子组件,负责UI渲染、事件透传),实现数据与视图的解耦,符合React组件化开发规范,同时与鸿蒙ArkUI的组件拆分思路一致,便于跨端复用与维护;
  • 模拟业务数据:通过静态数组模拟狗狗领养业务数据,采用标准化的对象结构,便于后续对接真实接口,同时保证跨端数据渲染的一致性;
  • 轻量资源管理:以键值对形式封装ICONS全局Emoji图标库,选用系统原生支持的Emoji作为视觉元素,避免第三方图标库在鸿蒙平台的桥接兼容问题,减少项目依赖体积,提升多端编译与启动效率;
  • 原生样式与布局:基于React Native原生的StyleSheet与Flex布局实现所有UI样式,无第三方UI库依赖,保证跨端布局的精准性、渲染性能与样式兼容性。

本项目的技术选型贴合实际移动端业务开发场景,既满足了狗狗领养中心的核心业务功能需求,又保证了代码的轻量性、可维护性与跨端兼容性,是React Native鸿蒙跨端开发中实际业务应用的典型实践,可快速迁移至电商列表、资讯展示、宠物服务等同类列表卡片式跨端应用。

二、组件化拆分

本项目最核心的工程化设计亮点是基于职责的组件化拆分,将整个应用拆分为AdoptionList页面容器组件与DogCard卡片展示组件,遵循单一职责原则关注点分离原则——容器组件负责数据管理、业务逻辑处理、事件定义,展示组件负责纯UI渲染、用户交互触发、事件透传,这种拆分方式让代码结构清晰、可维护性强,同时完美适配鸿蒙跨端的工程化开发需求,核心实现要点如下:

1. 组件划分

  • AdoptionList(页面/容器组件):作为应用的根组件,承担容器逻辑中心的职责,包括:初始化模拟业务数据并通过useState管理;定义核心业务事件(toggleFavorite收藏切换、handleAdopt领养申请);实现搜索筛选栏、页面标题、底部导航等公共UI的渲染;通过循环遍历将狗狗数据传递给DogCard组件,同时绑定事件回调。该组件不关注具体的卡片UI渲染细节,仅负责数据与逻辑的分发,符合容器组件的设计规范;
  • DogCard(卡片/展示组件):作为纯展示型原子组件,承担UI渲染交互触发的职责,包括:通过Props接收父组件传递的单个狗狗数据与事件回调;实现卡片的完整UI布局(图片、名称、品种、属性、标签、操作按钮);将用户交互(点击收藏、点击领养、点击分享)透传给父组件的事件回调。该组件无内部状态(纯受控组件),所有数据与行为均由父组件控制,符合展示组件的设计规范。

这种职责划分让两个组件的内聚性极强,耦合性极低,在鸿蒙跨端开发中,若需针对鸿蒙平台定制卡片UI样式,仅需修改DogCard组件;若需修改收藏逻辑,仅需修改AdoptionList组件的toggleFavorite方法,互不影响,大幅提升了跨端开发的维护效率。

2. TypeScript基础约束

DogCard组件通过TypeScript对Props进行了基础的强类型约束,核心定义为:

interface DogCardProps {
  dog: any, 
  onToggleFavorite: (id: number) => void,
  onAdopt: (id: number) => void
}

该约束明确了组件的入参类型:dog为任意类型(可后续拓展为具体接口),onToggleFavoriteonAdopt为接收数字类型ID、无返回值的回调函数。这种约束不仅能在开发阶段检测出参数类型与事件传递的错误,还能为跨端团队协作提供清晰的接口文档,同时与鸿蒙ArkUI的Props类型约束思路高度一致,保证了跨端开发的类型一致性。

在事件透传方面,DogCard组件将用户的点击操作(如点击收藏按钮)通过参数传递的方式(onToggleFavorite(dog.id))将狗狗的唯一ID透传给父组件,父组件通过ID精准定位到对应的狗狗数据并处理业务逻辑。这种基于唯一标识的事件透传方式是移动端列表开发的通用规范,无平台专属特性,在鸿蒙、Android、iOS多端的事件处理逻辑完全一致。

3. 跨端状态管理

DogCard组件被设计为纯受控组件,无任何内部状态,所有展示数据(如dog.isFavorite收藏状态、狗狗名称/图片/属性)与行为(收藏、领养)均由父组件AdoptionList通过Props控制。这种设计的核心优势在于:

  • 状态单一数据源:整个应用的业务状态(狗狗收藏状态)仅由AdoptionListdogs状态管理,避免了多组件状态不一致的问题,保证了跨端渲染的一致性;
  • 逻辑集中管理:核心业务逻辑集中在AdoptionList组件,便于后续拓展与修改(如将收藏状态同步到本地存储、云端接口),在鸿蒙跨端开发中,无需在多个组件中修改逻辑,仅需修改核心容器组件即可;
  • 组件高度复用DogCard组件可直接复用到其他需要展示狗狗卡片的跨端页面(如收藏列表、狗狗详情页),仅需传递不同的dog数据与事件回调即可,提升了跨端开发的代码复用率。

在鸿蒙ArkUI开发中,这种纯受控组件的设计思路与@Prop装饰器实现的父子组件状态同步逻辑高度一致,均是通过父组件控制子组件的状态与行为,保证了跨端组件设计思想的统一性。


本项目的核心业务状态是狗狗的收藏状态(isFavorite),基于React的useState钩子实现了该状态的初始化、修改与驱动渲染,同时实现了领养申请的基础业务逻辑,所有状态管理与业务逻辑均遵循React的单向数据流原则,无任何平台专属特性,可在鸿蒙平台无缝兼容,核心实现要点如下:

1. 业务数据的初始化

通过useState初始化狗狗业务数据,核心代码为:

const [dogs, setDogs] = useState(DOGS_DATA);

将模拟的DOGS_DATA数组作为初始值,通过dogs状态存储所有狗狗的完整数据(包括收藏状态、基本信息、图片等),通过setDogs方法修改状态。这种初始化方式与鸿蒙ArkUI的@State dogs: Dog[] = DOGS_DATA状态初始化逻辑高度一致,保证了跨端数据初始渲染的一致性。

同时,模拟数据采用标准化的对象结构,为每个狗狗设置唯一的id标识,这是移动端列表开发的通用规范,不仅便于后续的精准数据操作(如根据ID修改收藏状态),还能保证key属性的唯一性(列表循环时的key={dog.id}),避免React Native的列表渲染警告,提升跨端的渲染性能。

2. 收藏切换逻辑

定义toggleFavorite方法实现狗狗收藏状态的切换,核心代码为:

const toggleFavorite = (id: number) => {
  setDogs(dogs.map(dog => 
    dog.id === id ? { ...dog, isFavorite: !dog.isFavorite } : dog
  ));
};

该方法遵循React状态不可变的核心原则,不直接修改原dogs数组与狗狗对象,而是通过以下步骤生成新的状态:

  1. 通过map方法遍历原数组,返回一个新的数组;
  2. 通过id精准匹配到需要修改的狗狗对象;
  3. 通过扩展运算符(…) 复制原狗狗对象的所有属性,避免修改原对象;
  4. 仅修改isFavorite属性的取值(取反),实现收藏状态的切换;
  5. 未匹配到的狗狗对象直接返回,保持原有状态。

这种状态修改方式完全基于ES6通用语法,在鸿蒙、Android、iOS的JS引擎中均能正常执行,无跨端兼容问题。当状态更新后,React Native框架会自动触发组件的重渲染,DogCard组件会根据新的isFavorite值更新收藏图标的展示(❤️/🤍),实现状态驱动视图的跨端一致效果。

3. 领养申请逻辑

定义handleAdopt方法实现领养申请的基础业务逻辑,核心代码为:

const handleAdopt = (id: number) => {
  alert(`已提交对 ${dogs.find(d => d.id === id)?.name} 的领养申请`);
};

该方法通过id作为唯一标识,通过Array.prototype.find方法精准匹配到对应的狗狗对象,获取狗狗名称后,通过React Native原生的alert方法实现跨端通用的弹窗交互反馈。

alert作为React Native封装的跨平台原生弹窗组件,在鸿蒙平台中会被React Native for HarmonyOS桥接为鸿蒙的原生弹窗(AlertDialog),保证鸿蒙、Android、iOS多端的弹窗样式与交互体验一致性;Array.prototype.find作为ES6通用数组方法,在多端的JS引擎中均能正常执行,保证了数据匹配逻辑的跨端一致性。该方法为基础实现,后续可无缝拓展为对接真实的领养申请接口,无需修改核心逻辑结构。

4. 状态驱动

所有UI的更新均由状态的变化驱动,核心体现为:

  • 收藏图标:DogCard组件根据dog.isFavorite的值渲染不同的图标(❤️为已收藏,🤍为未收藏),当toggleFavorite方法修改isFavorite状态后,图标自动更新;
  • 狗狗列表:当dogs状态发生变化时,AdoptionList组件通过map循环遍历的DogCard组件会自动重渲染,保证UI与数据的一致性。

这种状态驱动视图的渲染逻辑,是React的核心设计思想,在鸿蒙ArkUI中通过@State状态与组件属性的绑定实现,二者的设计思路高度统一,保证了跨端开发中UI更新逻辑的一致性,无需为不同平台编写差异化的渲染代码。


真实演示案例代码:




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

// 图标库
const ICONS = {
  heart: '❤️',
  bookmark: '🔖',
  share: '📤',
  location: '📍',
  calendar: '📅',
  gender: '♂♀',
  age: '📅',
  size: '📏',
  info: 'ℹ️',
  home: '🏠',
  user: '👤',
  search: '🔍',
  filter: '🔍',
  like: '👍',
  comment: '💬',
  star: '⭐',
  paw: '🐾',
  dog: '🐕',
  cat: '🐈',
  plus: '➕',
  minus: '➖',
  check: '✅',
  close: '❌',
  edit: '✏️',
  delete: '🗑️',
  settings: '⚙️',
  notification: '🔔',
  gift: '🎁',
  celebration: '🎉',
  smile: '😊',
  sad: '😢',
  angry: '😠',
  surprised: '😲',
  thinking: '🤔',
  thumbs_up: '👍',
  thumbs_down: '👎',
  clap: '👏',
  wave: '👋',
  heart_eyes: '😍',
  laughing: '😂',
  crying: '😭',
  angry_face: '😡',
  neutral: '😐',
  confused: '😕',
  wink: '😉',
  tongue: '😛',
  sunglasses: '😎',
  money_mouth: '🤑',
  thinking_face: '🤔',
  sleeping: '😴',
  dizzy: '😵',
  sunglasses_face: '😎',
  heart_face: '🥰',
  kiss: '😘',
  hug: '🤗',
  pray: '🙏',
  handshake: '🤝',
  high_five: '🙌',
  peace: '✌️',
  ok: '👌',
  victory: '✌️',
  rock: '🤟',
  call_me: '🤙',
  point_up: '☝️',
  point_down: '👇',
  point_left: '👈',
  point_right: '👉',
  raised_hand: '✋',
  raised_fist: '✊',
  victory_hand: '✌️',
  metal: '🤘',
  vulcan: '🖖',
  wave_hand: '👋',
  clapping_hands: '👏',
  open_hands: '👐',
  palms_up: '🤲',
  handshake_hands: '🤝',
  pray_hands: '🙏',
  fold_hands: ' folded_hands',
  writing_hand: '✍️',
  nail_care: '💅',
  selfie: '🤳',
  flexed_biceps: '💪',
  muscle: '💪',
  selfie_tone1: ' selfie_tone1',
  selfie_tone2: ' selfie_tone2',
  selfie_tone3: ' selfie_tone3',
  selfie_tone4: ' selfie_tone4',
  selfie_tone5: ' selfie_tone5',
  selfie_tone6: ' selfie_tone6',
};

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

// 模拟狗狗数据
const DOGS_DATA = [
  {
    id: 1,
    name: '金毛旺财',
    breed: '金毛寻回犬',
    age: '2岁',
    gender: '公',
    size: '大型',
    location: '北京市朝阳区',
    description: '性格温顺,喜欢与人亲近,适合家庭饲养。',
    image: 'https://picsum.photos/300/200?random=1',
    isFavorite: false,
    tags: ['友善', '活泼', '聪明']
  },
  {
    id: 2,
    name: '柯基小短腿',
    breed: '威尔士柯基',
    age: '1岁半',
    gender: '母',
    size: '小型',
    location: '上海市浦东新区',
    description: '活泼好动,非常聪明,容易训练。',
    image: 'https://picsum.photos/300/200?random=2',
    isFavorite: true,
    tags: ['聪明', '活泼', '可爱']
  },
  {
    id: 3,
    name: '哈士奇二哈',
    breed: '西伯利亚雪橇犬',
    age: '3岁',
    gender: '公',
    size: '中型',
    location: '广州市天河区',
    description: '精力充沛,需要大量运动,适合活跃的家庭。',
    image: 'https://picsum.photos/300/200?random=3',
    isFavorite: false,
    tags: ['精力旺盛', '友好', '需要运动']
  },
  {
    id: 4,
    name: '泰迪小卷毛',
    breed: '贵宾犬',
    age: '6个月',
    gender: '母',
    size: '小型',
    location: '深圳市南山区',
    description: '非常亲人,毛发卷曲可爱,需要定期美容。',
    image: 'https://picsum.photos/300/200?random=4',
    isFavorite: false,
    tags: ['可爱', '亲人', '需要美容']
  },
  {
    id: 5,
    name: '柴犬小王子',
    breed: '日本柴犬',
    age: '1岁',
    gender: '公',
    size: '中型',
    location: '杭州市西湖区',
    description: '独立性强,忠诚,具有典型的狐狸脸特征。',
    image: 'https://picsum.photos/300/200?random=5',
    isFavorite: true,
    tags: ['忠诚', '独立', '可爱']
  },
  {
    id: 6,
    name: '边牧小聪明',
    breed: '边境牧羊犬',
    age: '2岁',
    gender: '母',
    size: '中型',
    location: '成都市锦江区',
    description: '智商极高,善于学习,需要大量精神和身体刺激。',
    image: 'https://picsum.photos/300/200?random=6',
    isFavorite: false,
    tags: ['聪明', '需要运动', '活跃']
  }
];

const DogCard: React.FC<{ 
  dog: any, 
  onToggleFavorite: (id: number) => void,
  onAdopt: (id: number) => void
}> = ({ dog, onToggleFavorite, onAdopt }) => {
  return (
    <View style={styles.dogCard}>
      <Image source={{ uri: dog.image }} style={styles.dogImage} />
      <View style={styles.dogInfo}>
        <View style={styles.dogHeader}>
          <Text style={styles.dogName}>{dog.name}</Text>
          <TouchableOpacity onPress={() => onToggleFavorite(dog.id)}>
            <Text style={styles.favoriteIcon}>{dog.isFavorite ? '❤️' : '🤍'}</Text>
          </TouchableOpacity>
        </View>
        <Text style={styles.dogBreed}>{dog.breed}</Text>
        <View style={styles.dogAttributes}>
          <Text style={styles.attribute}>{ICONS.age} {dog.age}</Text>
          <Text style={styles.attribute}>{ICONS.gender} {dog.gender}</Text>
          <Text style={styles.attribute}>{ICONS.size} {dog.size}</Text>
        </View>
        <Text style={styles.location}>{ICONS.location} {dog.location}</Text>
        <Text style={styles.description}>{dog.description}</Text>
        <View style={styles.tagsContainer}>
          {dog.tags.map((tag: string, index: number) => (
            <View key={index} style={styles.tag}>
              <Text style={styles.tagText}>{tag}</Text>
            </View>
          ))}
        </View>
        <View style={styles.actionRow}>
          <TouchableOpacity style={styles.adoptionButton} onPress={() => onAdopt(dog.id)}>
            <Text style={styles.adoptionButtonText}>申请领养</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.shareButton}>
            <Text style={styles.shareButtonText}>{ICONS.share} 分享</Text>
          </TouchableOpacity>
        </View>
      </View>
    </View>
  );
};

const AdoptionList: React.FC = () => {
  const [dogs, setDogs] = useState(DOGS_DATA);

  const toggleFavorite = (id: number) => {
    setDogs(dogs.map(dog => 
      dog.id === id ? { ...dog, isFavorite: !dog.isFavorite } : dog
    ));
  };

  const handleAdopt = (id: number) => {
    alert(`已提交对 ${dogs.find(d => d.id === id)?.name} 的领养申请`);
  };

  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.header}>
        <Text style={styles.title}>狗狗领养中心</Text>
        <Text style={styles.subtitle}>寻找您的毛茸茸伙伴</Text>
      </View>

      <View style={styles.searchFilter}>
        <View style={styles.searchContainer}>
          <Text style={styles.searchIcon}>{ICONS.search}</Text>
          <Text style={styles.searchPlaceholder}>搜索狗狗</Text>
        </View>
        <TouchableOpacity style={styles.filterButton}>
          <Text style={styles.filterText}>{ICONS.filter} 筛选</Text>
        </TouchableOpacity>
      </View>

      <ScrollView contentContainerStyle={styles.content}>
        <Text style={styles.sectionTitle}>可领养的狗狗</Text>
        <Text style={styles.dogsCount}>{dogs.length} 只狗狗等待新主人</Text>
        
        {dogs.map(dog => (
          <DogCard 
            key={dog.id} 
            dog={dog} 
            onToggleFavorite={toggleFavorite}
            onAdopt={handleAdopt}
          />
        ))}
      </ScrollView>

      <View style={styles.bottomBar}>
        <TouchableOpacity style={styles.bottomButton}>
          <Text style={styles.bottomButtonText}>{ICONS.home} 首页</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.bottomButton}>
          <Text style={styles.bottomButtonText}>{ICONS.user} 我的</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.bottomButton}>
          <Text style={styles.bottomButtonText}>{ICONS.heart} 收藏</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.bottomButton}>
          <Text style={styles.bottomButtonText}>{ICONS.gift} 领养</Text>
        </TouchableOpacity>
      </View>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f8f9fa',
  },
  header: {
    paddingTop: 40,
    paddingBottom: 20,
    paddingHorizontal: 20,
    backgroundColor: '#ffffff',
    borderBottomWidth: 1,
    borderBottomColor: '#e9ecef',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    color: '#333',
    textAlign: 'center',
  },
  subtitle: {
    fontSize: 16,
    color: '#666',
    textAlign: 'center',
    marginTop: 8,
  },
  searchFilter: {
    flexDirection: 'row',
    padding: 16,
    backgroundColor: '#ffffff',
    borderBottomWidth: 1,
    borderBottomColor: '#e9ecef',
  },
  searchContainer: {
    flex: 1,
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#f1f3f5',
    borderRadius: 20,
    paddingHorizontal: 16,
    paddingVertical: 8,
  },
  searchIcon: {
    fontSize: 16,
    marginRight: 8,
  },
  searchPlaceholder: {
    color: '#666',
    fontSize: 14,
  },
  filterButton: {
    backgroundColor: '#3B82F6',
    paddingHorizontal: 16,
    paddingVertical: 8,
    borderRadius: 20,
    marginLeft: 8,
    justifyContent: 'center',
  },
  filterText: {
    color: '#ffffff',
    fontSize: 14,
  },
  content: {
    padding: 16,
  },
  sectionTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#333',
    marginBottom: 4,
  },
  dogsCount: {
    fontSize: 14,
    color: '#666',
    marginBottom: 16,
  },
  dogCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    marginBottom: 16,
    elevation: 3,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    overflow: 'hidden',
  },
  dogImage: {
    width: '100%',
    height: 180,
  },
  dogInfo: {
    padding: 16,
  },
  dogHeader: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: 8,
  },
  dogName: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#333',
  },
  favoriteIcon: {
    fontSize: 24,
  },
  dogBreed: {
    fontSize: 14,
    color: '#666',
    marginBottom: 8,
  },
  dogAttributes: {
    flexDirection: 'row',
    marginBottom: 8,
  },
  attribute: {
    fontSize: 12,
    color: '#475569',
    backgroundColor: '#e2e8f0',
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 12,
    marginRight: 8,
  },
  location: {
    fontSize: 12,
    color: '#666',
    marginBottom: 8,
  },
  description: {
    fontSize: 14,
    color: '#475569',
    lineHeight: 20,
    marginBottom: 12,
  },
  tagsContainer: {
    flexDirection: 'row',
    marginBottom: 12,
  },
  tag: {
    backgroundColor: '#dbeafe',
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 12,
    marginRight: 6,
  },
  tagText: {
    fontSize: 12,
    color: '#3B82F6',
  },
  actionRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
  adoptionButton: {
    backgroundColor: '#3B82F6',
    flex: 1,
    paddingVertical: 10,
    borderRadius: 8,
    alignItems: 'center',
    marginRight: 8,
  },
  adoptionButtonText: {
    color: '#ffffff',
    fontWeight: 'bold',
  },
  shareButton: {
    backgroundColor: '#e2e8f0',
    flex: 0.3,
    paddingVertical: 10,
    borderRadius: 8,
    alignItems: 'center',
  },
  shareButtonText: {
    color: '#475569',
    fontWeight: 'bold',
  },
  bottomBar: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    backgroundColor: '#ffffff',
    borderTopWidth: 1,
    borderTopColor: '#e9ecef',
    paddingVertical: 12,
  },
  bottomButton: {
    alignItems: 'center',
    paddingHorizontal: 12,
  },
  bottomButtonText: {
    fontSize: 12,
    color: '#666',
    marginTop: 4,
  },
});

export default AdoptionList;

请添加图片描述


打包

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

在这里插入图片描述

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

在这里插入图片描述

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

请添加图片描述
本文介绍了一个基于React Native开发的狗狗领养中心应用,采用组件化架构设计,核心功能包括:

  • 数据结构:定义完整的狗狗信息对象,包含基本信息、特征、领养状态等
  • 组件设计:
    • 可复用的DogCard组件展示单个狗狗信息
    • AdoptionList组件作为容器管理状态和列表渲染
  • 状态管理:使用useState管理收藏状态和领养操作
  • 交互设计:实现收藏切换和领养申请功能
  • 布局优化:采用卡片式设计,支持响应式布局

该应用展示了React Native开发的核心技术,包括组件复用、状态管理和交互设计等关键实践。

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

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐