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


在移动应用开发领域,新闻资讯类应用因其信息密度高、交互频繁的特点,成为检验框架能力的重要场景。本文将深入解读一个基于 React Native 开发的新闻资讯应用代码片段,剖析其架构设计、组件化策略以及在鸿蒙系统上的跨端实现考量。

代码采用了清晰的组件化设计,将UI拆分为三个核心组件:NewsCardSearchBarCategoryTab。这种拆分不仅提高了代码的可维护性,更重要的是为跨端开发提供了便利。在鸿蒙系统的 ArkTS 环境中,组件化设计使得平台特定的代码修改可以被隔离在最小范围内,降低了跨端开发的复杂度。

// 新闻卡片组件
const NewsCard = ({
  title,
  summary,
  author,
  time,
  category,
  readTime,
  image,
  comments,
  likes,
  isBookmarked
}: {
  title: string;
  summary: string;
  author: string;
  time: string;
  category: string;
  readTime: string;
  image: string;
  comments: number;
  likes: number;
  isBookmarked: boolean;
}) => {
  // 组件内部逻辑
};

NewsCard 组件的设计尤为值得关注,它通过 props 接收所有必要的数据,并使用内部状态管理收藏状态。这种设计模式使得组件既可以响应外部数据变化,又能管理自身的交互状态,非常适合新闻卡片这种需要独立交互的场景。

状态管理

应用采用了 React Hooks 中的 useState 进行状态管理,这是 React Native 开发中的标准实践。在 NewsCard 组件中,使用 useState 管理收藏状态:

const [bookmarked, setBookmarked] = useState(isBookmarked);

const handleBookmark = () => {
  setBookmarked(!bookmarked);
  Alert.alert('提示', `${bookmarked ? '取消收藏' : '收藏'}此文章`);
};

在主组件 NewsPage 中,使用 useState 管理当前选中的分类:

const [selectedCategory, setSelectedCategory] = useState(0);

这种状态管理策略在跨端场景下表现出色,因为它不依赖于特定平台的状态管理方案,而是使用了 React 生态的标准 API,确保了在 React Native 和鸿蒙系统上的一致性表现。


响应式

代码通过 Dimensions.get('window') 获取屏幕宽度,为后续的响应式布局提供了基础:

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

这种方式在 React Native 中非常常见,但在鸿蒙系统的跨端开发中,需要特别注意不同设备尺寸的适配。鸿蒙系统的自适应布局能力虽然强大,但与 React Native 的布局模型存在差异,因此在实际开发中需要进行针对性调整。

应用使用了 React Native 内置的 StyleSheet 进行样式管理,这是一种性能优化的最佳实践。通过 StyleSheet.create 创建的样式对象,会被 React Native 转换为原生样式,提高渲染性能。

在鸿蒙系统的跨端开发中,样式系统的转换是一个关键点。鸿蒙的 ArkTS 样式系统与 React Native 的 StyleSheet 存在语法差异,因此需要通过跨端框架(如 HarmonyOS React Native)进行转换。这种转换过程中的性能损耗和样式一致性,是开发中需要重点关注的问题。

滚动视图

代码使用了 ScrollView 实现分类标签的水平滚动和新闻列表的垂直滚动:

<ScrollView
  horizontal
  showsHorizontalScrollIndicator={false}
  style={styles.categoryScrollView}
  contentContainerStyle={styles.categoryScrollContent}
>
  {/* 分类标签 */}
</ScrollView>

在鸿蒙系统上,ScrollView 的滚动性能需要特别关注。由于鸿蒙系统对原生组件的渲染速度较快,但对 JavaScript 执行的性能要求较高,因此应尽量减少 ScrollView 中的复杂计算,确保滚动的流畅性。


事件处理机制

应用实现了丰富的交互功能,如新闻收藏、点赞、评论等。在 NewsCard 组件中,收藏功能的实现如下:

const handleBookmark = () => {
  setBookmarked(!bookmarked);
  Alert.alert('提示', `${bookmarked ? '取消收藏' : '收藏'}此文章`);
};

这种基于回调函数的事件处理方式,在 React Native 和鸿蒙系统中都能很好地工作。但需要注意的是,在鸿蒙系统中,事件响应的优先级和处理机制可能与 React Native 有所不同,需要进行适当的调整以确保用户体验的一致性。

代码中采用了以下性能优化策略:

  1. 组件拆分:将UI拆分为多个可复用组件,减少单个组件的复杂度,提高渲染性能。

  2. 合理使用 ScrollView:对于分类标签使用水平 ScrollView,对于新闻列表使用垂直 ScrollView,避免一次性渲染过多内容。

  3. 条件渲染:通过 isBookmarked 状态控制收藏图标的显示,避免不必要的渲染。

  4. 样式复用:使用 StyleSheet 创建样式对象,减少运行时的样式计算。

在鸿蒙系统上,这些优化策略同样适用,但需要根据鸿蒙系统的性能特点进行适当调整。例如,鸿蒙系统对原生组件的渲染速度较快,但对 JavaScript 执行的性能要求较高,因此应尽量减少 JavaScript 线程的计算负担。


组件

React Native 的核心组件(如 ViewTextImageTouchableOpacity 等)在鸿蒙系统上都有对应的实现,但在某些属性和行为上可能存在差异。例如,Image 组件的加载策略、TouchableOpacity 的点击反馈等,都需要在鸿蒙系统上进行测试和优化。

图片加载

代码中使用了网络图片加载:

<Image source={{ uri: image }} style={styles.newsImage} />

在鸿蒙系统上,图片加载的性能和缓存策略可能与 React Native 有所不同。为了确保良好的用户体验,应考虑以下几点:

  1. 图片缓存:实现图片的本地缓存,减少网络请求次数。

  2. 图片压缩:根据设备屏幕尺寸,加载合适大小的图片,减少内存消耗。

  3. 懒加载:实现图片的懒加载,提高页面加载速度。

在鸿蒙系统上,React Native 应用的性能优化需要考虑以下几点:

  1. 渲染性能:鸿蒙系统对原生组件的渲染速度较快,但对 JavaScript 执行的性能要求较高。因此,应尽量减少 JavaScript 线程的计算负担,将复杂的计算逻辑移至原生层。

  2. 内存管理:新闻应用通常会加载大量图片,内存消耗较大。在鸿蒙系统上,需要特别注意内存的分配和释放,避免内存泄漏。

  3. 网络请求:新闻应用的网络请求频繁,应合理使用缓存策略,减少网络请求次数,提高应用响应速度。


类型安全

代码使用了 TypeScript 进行类型定义,这不仅提高了代码的可读性,也为跨端开发提供了类型安全保障。在鸿蒙系统的 ArkTS 环境中,类型系统的一致性尤为重要,它确保了数据在不同平台间传递时的准确性。

模块化

应用的代码结构清晰,将数据、组件逻辑、样式等分离,便于维护和扩展。这种模块化设计在跨端开发中尤为重要,因为它使得平台特定的代码修改可以被隔离在最小范围内。

错误处理

代码中使用了 Alert.alert 进行用户反馈,这是一种简单有效的错误处理方式。在实际开发中,还应考虑添加更全面的错误处理机制,如网络请求错误、图片加载失败等,以提高应用的稳定性。


代码展示了组件化开发的最佳实践:

  1. 单一职责原则:每个组件只负责一个特定的功能,如 NewsCard 只负责新闻卡片的展示和交互。

  2. props 传递:通过 props 传递数据,使得组件之间的通信清晰明了。

  3. 内部状态管理:对于组件内部的状态(如收藏状态),使用 useState 进行管理,避免状态提升带来的复杂性。

响应式设计

代码通过 Dimensions.get('window') 获取屏幕宽度,为响应式布局提供了基础。在实际开发中,还可以考虑使用 Flexbox 布局模型,进一步提高应用的响应能力。

  1. 使用核心组件:优先使用 React Native 的核心组件,这些组件在鸿蒙系统上有较好的兼容性。

  2. 避免平台特定代码:尽量避免使用平台特定的 API,如需要使用,应通过条件判断进行隔离。

  3. 性能优化:针对不同平台的性能特点,进行有针对性的优化。

  4. 用户体验:确保在不同平台上的用户体验一致性,包括交互方式、视觉效果等。

通过对这个 React Native 新闻资讯应用代码片段的深入解读,我们可以看到,一个优秀的跨端应用需要在架构设计、组件化策略、性能优化等多个方面进行精心考量。特别是在 React Native 与鸿蒙系统的跨端开发中,需要充分了解两个平台的特性,才能开发出性能优异、用户体验一致的应用。

随着移动应用开发技术的不断演进,跨端开发已成为一种趋势。React Native 作为一种成熟的跨端开发框架,在鸿蒙系统上的应用前景广阔。通过不断优化代码结构、提高性能表现、确保用户体验一致性,我们可以开发出更加优秀的跨端应用,为用户带来更好的使用体验。

在未来的开发中,我们还可以探索更多技术方案,如使用 Redux 或 MobX 进行状态管理、使用 React Navigation 进行路由管理、使用 Expo 进行快速开发等,进一步提高开发效率和应用质量。同时,也需要密切关注鸿蒙系统的发展动态,及时调整开发策略,以适应新的技术要求。


新闻资讯类应用是内容消费场景的典型代表,其包含的组件化拆分、流式列表渲染、分类标签交互、状态驱动UI变化等核心能力,是跨端开发中高频且关键的技术场景。本文以一个完整的 React Native 新闻资讯页面为例,拆解其工程化实现逻辑,并深入探讨该页面向鸿蒙(HarmonyOS)生态迁移的技术要点,为跨端内容类应用开发提供可落地的实践参考。

该新闻资讯页面采用 React Native 主流的组件化开发范式,融合了纯函数组件设计、Props 类型约束、多层级 Flex 布局、局部状态管理等核心技术点,完全贴合内容类应用的开发特性。

1. 组件化设计:

页面采用精细化的组件拆分策略,将 UI 拆分为 NewsCardSearchBarCategoryTab 三个独立组件 + 主页面容器,这种设计是跨端复用的核心基础:

  • 原子级组件封装SearchBar 封装搜索栏UI,CategoryTab 封装分类标签的样式与交互逻辑,NewsCard 封装单条新闻的完整展示与交互(点赞、评论、收藏)。每个组件仅关注自身职责,通过 Props 接收外部数据,这种“单一职责”的组件设计在鸿蒙端可直接映射为自定义组件(@Component 装饰的 struct),实现组件级别的跨端复用。
  • Props 类型强约束NewsCard 组件通过 TypeScript 明确定义入参类型(如 title: stringisBookmarked: boolean),避免运行时类型错误,这种类型约束在鸿蒙 ArkTS 中可通过接口(interface)无缝复用,仅需将 React 的 Props 传递方式改为鸿蒙的参数传递,核心类型定义完全一致。
  • 组件内部状态自治NewsCard 内部通过 useState 管理收藏状态(bookmarked),收藏交互逻辑(handleBookmark)也内聚在组件内部,这种“状态自治”的设计让组件具备独立复用能力,迁移至鸿蒙时仅需将 useState 替换为 @State,交互逻辑无需修改。

2. 布局体系:

新闻页面的布局完全基于 React Native 的 Flex 布局体系实现,而 Flex 是 React Native 与鸿蒙 ArkUI 共有的核心布局模型,为跨端迁移提供了天然优势:

  • 响应式容器设计:通过 Dimensions.get('window') 获取屏幕宽度,结合 flex: 1width: '100%' 等属性实现页面容器的自适应,新闻图片设置 height: 180 保证固定视觉高度,这种布局策略在鸿蒙端可通过 screen.getScreenSize() 获取屏幕尺寸后,结合 width: '100%'height: 180vp 实现等价适配,无需为不同设备编写差异化布局。
  • 多层级 Flex 嵌套newsCard 内部通过垂直 Flex 布局实现图片+内容的上下排列;newsHeader 借助 justifyContent: 'space-between' 实现分类标签与阅读时长的两端对齐;newsFooter 通过 Flex 实现作者信息与操作按钮的左右分栏。整个布局逻辑完全基于 Flex 实现,迁移至鸿蒙时仅需调整属性命名规范(如 flexDirection: 'row'flexDirection: FlexDirection.Row),核心逻辑无需重构。
  • 视觉层次构建:通过 elevation(Android 阴影)、borderRadiusoverflow: 'hidden' 等样式属性构建新闻卡片的视觉层次感,分类标签通过 backgroundColor: '#dbeafe' + borderRadius: 12 实现胶囊样式,这种视觉交互的实现方式在鸿蒙端可通过 shadowborderRadiusbackgroundColor 属性无缝替换,保证跨端视觉体验一致。

3. 列表与滚动:

新闻页面包含横向滚动的分类标签和纵向滚动的新闻列表,两种滚动场景的实现体现了 React Native 滚动交互的工程化思路,也为跨端迁移提供了清晰的映射方案:

  • 横向分类标签:采用 ScrollView horizontal 实现横向滚动,配置 showsHorizontalScrollIndicator={false} 隐藏滚动指示器优化体验,contentContainerStyle 配置内边距保证交互合理性。这种横向滚动布局在鸿蒙端可通过 Scroll 组件 + FlexDirection.Row 实现,核心属性(如隐藏滚动条、内容容器样式)均可等价映射。
  • 纵向新闻列表:采用基础 ScrollView 渲染新闻卡片列表(数据量较小场景),若后续数据量增大,可无缝切换为 FlatList 实现虚拟化列表,这种“按需选择滚动组件”的思路在跨端开发中同样适用——少量静态数据用 ScrollView,大量动态数据用虚拟化列表(React Native 的 FlatList / 鸿蒙的 List)。

4. 状态与交互:

页面采用 React 内置的 useState 管理局部状态,结合 TouchableOpacity 实现交互逻辑,符合内容类应用的轻量状态管理最佳实践:

  • 主页面通过 useState 管理选中的分类标签(selectedCategory),点击分类标签时更新状态并触发 UI 重渲染,这种状态驱动 UI 变化的逻辑在鸿蒙端可通过 @State 装饰器实现,状态更新逻辑(setSelectedCategory(index)this.selectedCategory = index)完全一致。
  • NewsCard 组件内部的收藏交互、点赞/评论的弹窗反馈(Alert.alert),均为纯业务逻辑,与 UI 框架解耦,迁移至鸿蒙时仅需将 Alert.alert 替换为 promptAction.showDialog,核心交互逻辑无需修改。

将该新闻页面迁移至鸿蒙端,核心是“组件复用、布局等价、交互一致”,以下从技术维度拆解关键适配点:

1. 语法适配:

鸿蒙端基于 ArkTS(TypeScript 超集)开发,与 React Native 的 TypeScript 语法高度兼容,核心差异集中在组件定义与状态管理:

  • 组件定义:React Native 的函数式组件(如 const NewsCard = ({ ...props }) => {})对应鸿蒙的自定义组件(@Component struct NewsCard {}),React 的 Props 入参对应鸿蒙的组件参数,例如 NewsCard 组件的入参类型可直接复用,仅需将函数返回 JSX 的方式改为鸿蒙的 build 方法返回 UI 结构。
  • 状态管理:React 的 useState 对应鸿蒙的 @State 装饰器,例如 const [bookmarked, setBookmarked] = useState(isBookmarked) 可改写为 @State bookmarked: boolean = isBookmarked,状态更新逻辑从 setBookmarked(!bookmarked) 改为 this.bookmarked = !this.bookmarked,逻辑完全一致。
  • 事件处理:React Native 的 onPress 对应鸿蒙的 onClick,事件绑定方式从 onPress={handleBookmark} 改为 onClick={() => this.handleBookmark()},事件处理函数的内部逻辑无需修改。

2. 核心组件:

React Native 原生组件与鸿蒙 ArkUI 组件存在清晰的映射关系,是跨端迁移的核心落地环节:

React Native 组件 鸿蒙 ArkUI 组件 适配核心说明
SafeAreaView SafeArea 均用于适配刘海屏/底部安全区,属性一致
View Column/Row/Stack 鸿蒙通过布局组件替代通用容器,Flex 布局逻辑复用
Text Text 样式属性(fontSize/color等)仅命名规范差异
TouchableOpacity Button/Text(带点击态) 鸿蒙无直接等价组件,可通过 Button 去除默认样式实现,或自定义 Text 的点击态
ScrollView (horizontal) Scroll + Row 鸿蒙 Scroll 组件结合 FlexDirection.Row 实现横向滚动
Image Image 图片加载方式从 source={{ uri: image }} 改为 src: image,resizeMode 对应 objectFit
Alert promptAction 鸿蒙 promptAction.showDialog/showToast 实现弹窗/提示,参数结构需适配

以核心的 NewsCard 组件为例,React Native 实现与鸿蒙 ArkTS 实现的核心映射:

// React Native NewsCard 核心逻辑
const NewsCard = ({ isBookmarked, ...props }) => {
  const [bookmarked, setBookmarked] = useState(isBookmarked);
  const handleBookmark = () => {
    setBookmarked(!bookmarked);
    Alert.alert('提示', `已${bookmarked ? '取消收藏' : '收藏'}此文章`);
  };
  // JSX 渲染逻辑...
};

// 鸿蒙 ArkTS NewsCard 等价实现
@Component
struct NewsCard {
  @Prop isBookmarked: boolean;
  @State bookmarked: boolean = this.isBookmarked;
  // 其他 Props 定义...
  
  handleBookmark() {
    this.bookmarked = !this.bookmarked;
    promptAction.showToast({
      message: `已${this.bookmarked ? '取消收藏' : '收藏'}此文章`
    });
  }
  
  build() {
    // ArkUI 渲染逻辑(复用 Flex 布局)...
  }
}

React Native 的 StyleSheet.create 封装样式的方式,在鸿蒙端可通过 @Styles/@Extend 装饰器实现等价封装,核心样式属性的适配规则如下:

  • 布局属性flex/flexDirection/justifyContent/alignItems 等 Flex 核心属性完全复用,仅鸿蒙需将字符串值改为枚举值(如 justifyContent: 'space-between'justifyContent: FlexAlign.SpaceBetween)。
  • 尺寸与间距:React Native 的 padding: 16 对应鸿蒙的 padding: 16vpwidth: '100%' 对应 width: '100%'height: 180 对应 height: 180vp,单位适配无成本。
  • 视觉样式borderRadius 完全复用;elevation(Android 阴影)对应鸿蒙的 shadow 属性(shadowColor/shadowRadius/shadowOffset);overflow: 'hidden' 对应鸿蒙的 overflow: Overflow.Hidden,视觉效果完全一致。
  • 条件样式:React Native 的 [styles.categoryTab, isSelected && styles.selectedCategoryTab] 条件样式,在鸿蒙端可通过三元表达式实现:style={this.isSelected ? this.selectedCategoryTab() : this.categoryTab()},样式切换逻辑完全复用。

新闻资讯类应用对滚动流畅度、图片加载体验要求较高,跨端迁移需重点保证两端体验的一致性:

  • 滚动性能:React Native 的 ScrollView 和鸿蒙的 Scroll 组件均为原生滚动实现,鸿蒙端可通过 cachedCount 配置滚动缓存项数量,优化大量新闻数据的滚动流畅度;若后续切换为虚拟化列表(FlatList/List),需保证鸿蒙 List 开启虚拟化能力(默认开启)。
  • 图片加载:React Native 的 Image 组件与鸿蒙的 Image 组件均支持网络图片加载,鸿蒙端可结合 @ohos.image 模块实现图片懒加载、缓存等优化,提升新闻图片的加载体验。
  • 交互反馈:React Native 的 TouchableOpacity 点击透明度变化反馈,在鸿蒙端可通过 Button 组件的 stateEffect 属性实现,或自定义 Text 组件的 backgroundColor 点击态切换,保证分类标签、新闻操作按钮的交互反馈一致性。
  • 分布式适配:鸿蒙特有的分布式能力可作为跨端增强点,例如该新闻页面可通过鸿蒙的 @ohos.distributedData 实现多设备收藏同步,或通过 @ohos.window 适配平板/智慧屏的大屏布局(如新闻卡片双列展示、分类标签横向平铺),提升鸿蒙端的原生体验。

从该 React Native 新闻页面的鸿蒙适配过程中,可提炼出内容类应用跨端开发的通用方法论:

1. 组件化拆分

该页面将 UI 拆分为 NewsCardSearchBarCategoryTab 等独立组件,每个组件职责单一、状态自治,这种设计让跨端迁移可实现“组件级复用”,而非整体代码移植,大幅降低适配成本。在跨端开发初期,应优先完成组件化拆分,明确组件的 Props 类型和内部状态,为后续跨端适配奠定基础。

2. Flex 布局

React Native 与鸿蒙 ArkUI 均基于 Flex 布局体系,这是跨端布局适配的最大优势。在开发时应优先使用 Flex 布局而非固定尺寸布局,减少不同设备、不同平台的适配工作量,核心布局逻辑可 100% 复用。

3. 状态与逻辑层

页面的业务逻辑(如收藏状态切换、分类选中逻辑)与 UI 渲染解耦,仅通过状态驱动 UI 变化,这种设计让核心业务逻辑可完全跨端复用,仅需适配 UI 层的组件和样式,是跨端开发效率最大化的关键。


若将该新闻页面落地到鸿蒙端,建议分阶段实施:

  1. 组件迁移:首先迁移 SearchBarCategoryTab 等简单组件,验证组件定义、Props 传递、样式适配的可行性,再迁移核心的 NewsCard 组件。
  2. 逻辑复用:直接复用 TypeScript 类型定义和业务逻辑函数(如收藏状态切换、分类选中逻辑),仅修改状态管理和弹窗反馈的 API 调用方式。
  3. 体验优化:针对鸿蒙端特性做体验增强,例如利用鸿蒙的 List 组件实现新闻列表的下拉刷新/上拉加载,利用 Image 组件的加载状态优化新闻图片的展示体验。

从性能优化角度,React Native 端可将新闻列表从 ScrollView 改为 FlatList 实现虚拟化渲染,鸿蒙端可通过 List 组件的 lazyLoad 特性优化大量新闻数据的加载性能。

该 React Native 新闻资讯页面的实现,充分体现了现代跨端开发的工程化思想:组件化拆分提升复用性,Flex 布局实现多端适配,TypeScript 保证类型安全,轻量状态管理降低复杂度。向鸿蒙端迁移时,核心业务逻辑和布局逻辑可完全复用,仅需适配组件语法、样式属性和原生 API 调用,适配成本可控制在 20%-30% 以内。

对于内容类跨端应用开发,无需追求“一行代码多端运行”,而是通过“组件复用 + 布局等价 + 逻辑解耦”的方式,平衡开发效率与原生体验。React Native 与鸿蒙 ArkTS 均基于 TypeScript 生态,Flex 布局体系一致,这为跨端开发提供了天然的技术基础,也是未来移动跨端开发的主流方向。


真实演示案例代码:

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

// 图标库
const ICONS = {
  home: '🏠',
  news: '📰',
  like: '👍',
  comment: '💬',
  share: '📤',
  bookmark: '🔖',
  user: '👤',
  search: '🔍',
};

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

// 新闻卡片组件
const NewsCard = ({ 
  title, 
  summary, 
  author, 
  time, 
  category, 
  readTime, 
  image, 
  comments, 
  likes,
  isBookmarked
}: { 
  title: string; 
  summary: string; 
  author: string; 
  time: string; 
  category: string; 
  readTime: string; 
  image: string; 
  comments: number; 
  likes: number;
  isBookmarked: boolean;
}) => {
  const [bookmarked, setBookmarked] = useState(isBookmarked);
  
  const handleBookmark = () => {
    setBookmarked(!bookmarked);
    Alert.alert('提示', `${bookmarked ? '取消收藏' : '收藏'}此文章`);
  };

  return (
    <View style={styles.newsCard}>
      <Image source={{ uri: image }} style={styles.newsImage} />
      
      <View style={styles.newsContent}>
        <View style={styles.newsHeader}>
          <Text style={styles.categoryTag}>{category}</Text>
          <Text style={styles.readTime}>{readTime}</Text>
        </View>
        
        <Text style={styles.newsTitle}>{title}</Text>
        <Text style={styles.newsSummary}>{summary}</Text>
        
        <View style={styles.newsFooter}>
          <View style={styles.authorInfo}>
            <Text style={styles.author}>{author}</Text>
            <Text style={styles.time}>{time}</Text>
          </View>
          
          <View style={styles.newsActions}>
            <TouchableOpacity style={styles.actionButton} onPress={() => Alert.alert('点赞')}>
              <Text style={styles.actionText}>{ICONS.like} {likes}</Text>
            </TouchableOpacity>
            <TouchableOpacity style={styles.actionButton} onPress={() => Alert.alert('评论')}>
              <Text style={styles.actionText}>{ICONS.comment} {comments}</Text>
            </TouchableOpacity>
            <TouchableOpacity style={styles.actionButton} onPress={handleBookmark}>
              <Text style={styles.actionText}>{bookmarked ? '★' : '☆'}</Text>
            </TouchableOpacity>
          </View>
        </View>
      </View>
    </View>
  );
};

// 搜索栏组件
const SearchBar = () => {
  return (
    <View style={styles.searchBar}>
      <Text style={styles.searchIcon}>{ICONS.search}</Text>
      <Text style={styles.searchPlaceholder}>搜索新闻...</Text>
    </View>
  );
};

// 分类标签组件
const CategoryTab = ({ 
  title, 
  isSelected, 
  onPress 
}: { 
  title: string; 
  isSelected: boolean; 
  onPress: () => void 
}) => {
  return (
    <TouchableOpacity 
      style={[styles.categoryTab, isSelected && styles.selectedCategoryTab]} 
      onPress={onPress}
    >
      <Text style={[styles.categoryText, isSelected && styles.selectedCategoryText]}>{title}</Text>
    </TouchableOpacity>
  );
};

const NewsPage: React.FC = () => {
  const [selectedCategory, setSelectedCategory] = useState(0);
  
  // 分类数据
  const categories = ['推荐', '热点', '科技', '财经', '体育', '娱乐'];
  
  // 新闻数据
  const newsData = [
    {
      id: 1,
      title: '人工智能技术在医疗领域的突破性进展',
      summary: 'AI技术正在帮助医生诊断疾病,提高治疗效率,为患者带来更好的医疗服务体验。',
      author: '科技日报',
      time: '2小时前',
      category: '科技',
      readTime: '5分钟',
      image: 'https://picsum.photos/300/200?random=1',
      comments: 24,
      likes: 128,
      isBookmarked: true,
    },
    {
      id: 2,
      title: '全球股市迎来新一轮上涨行情',
      summary: '受多重利好消息影响,全球主要股指普遍上涨,投资者信心显著增强。',
      author: '财经周刊',
      time: '4小时前',
      category: '财经',
      readTime: '3分钟',
      image: 'https://picsum.photos/300/200?random=2',
      comments: 18,
      likes: 96,
      isBookmarked: false,
    },
    {
      id: 3,
      title: '世界杯预选赛精彩瞬间回顾',
      summary: '昨晚的比赛可谓精彩纷呈,多场关键战役决定了出线形势。',
      author: '体育时报',
      time: '6小时前',
      category: '体育',
      readTime: '4分钟',
      image: 'https://picsum.photos/300/200?random=3',
      comments: 32,
      likes: 210,
      isBookmarked: true,
    },
    {
      id: 4,
      title: '知名演员新电影票房破纪录',
      summary: '该影片上映首周即打破多项票房记录,观众口碑持续走高。',
      author: '娱乐新闻',
      time: '8小时前',
      category: '娱乐',
      readTime: '2分钟',
      image: 'https://picsum.photos/300/200?random=4',
      comments: 15,
      likes: 78,
      isBookmarked: false,
    },
    {
      id: 5,
      title: '新能源汽车市场持续增长',
      summary: '随着环保意识提升和技术进步,新能源汽车销量再创新高。',
      author: '汽车杂志',
      time: '10小时前',
      category: '科技',
      readTime: '6分钟',
      image: 'https://picsum.photos/300/200?random=5',
      comments: 27,
      likes: 156,
      isBookmarked: true,
    },
  ];

  return (
    <SafeAreaView style={styles.container}>
      {/* 头部 */}
      <View style={styles.header}>
        <Text style={styles.title}>新闻资讯</Text>
        <Text style={styles.subtitle}>每日精选,及时获取最新资讯</Text>
      </View>

      {/* 搜索栏 */}
      <SearchBar />

      {/* 分类标签 */}
      <ScrollView 
        horizontal 
        showsHorizontalScrollIndicator={false}
        style={styles.categoryScrollView}
        contentContainerStyle={styles.categoryScrollContent}
      >
        {categories.map((category, index) => (
          <CategoryTab
            key={index}
            title={category}
            isSelected={selectedCategory === index}
            onPress={() => setSelectedCategory(index)}
          />
        ))}
      </ScrollView>

      {/* 新闻列表 */}
      <ScrollView style={styles.newsList}>
        {newsData.map(news => (
          <NewsCard
            key={news.id}
            title={news.title}
            summary={news.summary}
            author={news.author}
            time={news.time}
            category={news.category}
            readTime={news.readTime}
            image={news.image}
            comments={news.comments}
            likes={news.likes}
            isBookmarked={news.isBookmarked}
          />
        ))}
      </ScrollView>

      {/* 底部导航 */}
      <View style={styles.bottomNav}>
        <TouchableOpacity style={styles.navItem}>
          <Text style={[styles.navIcon, styles.activeNavIcon]}>{ICONS.home}</Text>
          <Text style={[styles.navText, styles.activeNavText]}>首页</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.navItem}>
          <Text style={styles.navIcon}>{ICONS.news}</Text>
          <Text style={styles.navText}>新闻</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.navItem}>
          <Text style={styles.navIcon}>{ICONS.bookmark}</Text>
          <Text style={styles.navText}>收藏</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.navItem}>
          <Text style={styles.navIcon}>{ICONS.user}</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: 24,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 4,
  },
  subtitle: {
    fontSize: 14,
    color: '#64748b',
  },
  searchBar: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#ffffff',
    margin: 16,
    paddingHorizontal: 16,
    paddingVertical: 12,
    borderRadius: 8,
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  searchIcon: {
    fontSize: 18,
    color: '#94a3b8',
    marginRight: 10,
  },
  searchPlaceholder: {
    fontSize: 16,
    color: '#94a3b8',
    flex: 1,
  },
  categoryScrollView: {
    backgroundColor: '#ffffff',
    paddingVertical: 12,
    paddingLeft: 16,
  },
  categoryScrollContent: {
    paddingRight: 16,
  },
  categoryTab: {
    paddingHorizontal: 16,
    paddingVertical: 8,
    borderRadius: 20,
    backgroundColor: '#f1f5f9',
    marginRight: 10,
  },
  selectedCategoryTab: {
    backgroundColor: '#3b82f6',
  },
  categoryText: {
    fontSize: 14,
    color: '#64748b',
    fontWeight: '500',
  },
  selectedCategoryText: {
    color: '#ffffff',
  },
  newsList: {
    flex: 1,
    padding: 16,
  },
  newsCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    marginBottom: 16,
    overflow: 'hidden',
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  newsImage: {
    width: '100%',
    height: 180,
    resizeMode: 'cover',
  },
  newsContent: {
    padding: 16,
  },
  newsHeader: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    marginBottom: 8,
  },
  categoryTag: {
    backgroundColor: '#dbeafe',
    color: '#1d4ed8',
    fontSize: 12,
    fontWeight: '500',
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 12,
  },
  readTime: {
    fontSize: 12,
    color: '#94a3b8',
  },
  newsTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 8,
    lineHeight: 24,
  },
  newsSummary: {
    fontSize: 14,
    color: '#64748b',
    lineHeight: 20,
    marginBottom: 12,
  },
  newsFooter: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  authorInfo: {
    flex: 1,
  },
  author: {
    fontSize: 14,
    color: '#334155',
    fontWeight: '500',
  },
  time: {
    fontSize: 12,
    color: '#94a3b8',
  },
  newsActions: {
    flexDirection: 'row',
  },
  actionButton: {
    marginLeft: 16,
  },
  actionText: {
    fontSize: 14,
    color: '#64748b',
  },
  bottomNav: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    backgroundColor: '#ffffff',
    borderTopWidth: 1,
    borderTopColor: '#e2e8f0',
    paddingVertical: 12,
  },
  navItem: {
    alignItems: 'center',
  },
  activeNavItem: {
    paddingBottom: 2,
    borderBottomWidth: 2,
    borderBottomColor: '#3b82f6',
  },
  navIcon: {
    fontSize: 20,
    color: '#94a3b8',
    marginBottom: 4,
  },
  activeNavIcon: {
    color: '#3b82f6',
  },
  navText: {
    fontSize: 12,
    color: '#94a3b8',
  },
  activeNavText: {
    color: '#3b82f6',
    fontWeight: '500',
  },
});

export default NewsPage;

请添加图片描述


打包

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

在这里插入图片描述

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

在这里插入图片描述

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

请添加图片描述
本文分析了一个基于React Native开发的新闻资讯应用,重点探讨其组件化架构、状态管理和跨平台实现。应用采用清晰的组件拆分(NewsCard、SearchBar等),通过React Hooks管理状态,并使用响应式设计适配不同屏幕。文章特别关注了该应用在鸿蒙系统上的跨端适配策略,包括性能优化、事件处理和图片加载等关键问题。案例展示了如何在保持代码可维护性的同时实现跨平台一致性,为类似应用开发提供了参考方案。

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

Logo

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

更多推荐