本文介绍了一个基于React Native的"口腔护理·今日任务"移动端页面实现方案。该方案采用函数式组件设计,通过内联SVG图标、Flexbox布局和基础交互组件构建轻量级跨端应用。技术特点包括:使用SafeAreaView适配不同设备安全区域、SvgXml渲染Base64编码的SVG图标避免资源依赖、统一使用TouchableOpacity和Alert实现跨平台交互。文章还提供了鸿蒙设备上的适配建议,如简化阴影效果、使用百分比宽度布局等。组件结构采用单一文件设计,便于多端快速落地,展示了不依赖外部模块实现稳定跨端UI的工程实践方案。

这段代码实现了一个“口腔护理 · 今日任务”页面,采用 React Native 的函数式组件设计,在不引入额外依赖的前提下,通过内联 SVG 与基础交互构建出适合移动端的模块化体验。本文从跨端渲染原理、资源管理、布局系统与交互桥接等角度分析其技术实现,并给出在鸿蒙跨端场景下的工程化建议。

组件结构

组件使用函数式模式组织,仅在视图层展示静态数据与轻交互。所有 UI 都由单一组件内部构建,没有跨文件依赖,便于在多端环境中快速落地。交互入口统一通过 TouchableOpacityAlert 实现,保持“轻逻辑、重视图”的分层策略,有助于跨端兼容与预期一致的用户体验。

  • 使用 SafeAreaView 作为页面根容器,在 iOS 刘海屏、Android 与鸿蒙不同设备的系统栏区域自动预留安全间距,这一点对多端一致的视觉呈现尤为重要。
  • ScrollView 提供内容滚动能力,页面各分区通过 View 组合,形成若干独立的功能块:统计卡片行、物品网格、建议区、操作区。

跨端

图标通过 react-native-svgSvgXml 渲染 Base64 编码的 SVG 字符串,这种做法避免了外部静态资源打包和平台差异的图标适配问题。

  • Base64 + SvgXml 的组合让图标成为组件“内聚”的一部分,不依赖文件系统与额外打包流程;在鸿蒙场景下也不需要额外的资源注册或 HAP 资源打点。
  • 以内联形式管理图标集,减少了运行时 IO 和路径解析,为页面的“纯前端实现”提供了基础,尤其适合 Demo 验证或多主题模板快速复制。

布局系统

页面布局基于 Flexbox 与 StyleSheet 的静态样式,最终通过 RN 的 Yoga 引擎解析为原生视图树。不同分区样式策略各有侧重,既体现了层次结构,也确保了跨端的稳定渲染。

  • 统计卡片行使用 flexDirection: 'row' 配合等比分布,阴影与圆角在 iOS/Android 上有平台差异;在鸿蒙设备上阴影渲染取决于运行环境是否接近 AOSP,建议以“低强度阴影 + 清晰边框”作为兜底。
  • 网格布局采用 flexWrap: 'wrap' 与百分比宽度实现两列排布,适配各种屏宽;文字代码点表情如🪥、🦷直接作为内容渲染,避免图文垂直对齐与 baseline 差异引起的抖动。
  • gap、投影与圆角的组合在不同 RN 版本、不同端表现存在差异。若目标覆盖鸿蒙 NEXT 或更纯净的 ArkUI 渲染路径,建议对 gap 做版本级兜底(用 marginRight/marginBottom 代替),投影弱化处理或以描边替代。

交互

交互统一通过声明式事件与 React 状态驱动,具体在 RN 中通过 JavaScript→Native 的桥接完成动作触发和平台弹框渲染。

  • TouchableOpacity 负责点击态与按压反馈,事件处理器由 JS 线程调度,跨端稳定性高。
  • Alert.alert 映射到原生弹窗组件,符合移动端认知模型;在鸿蒙与 Android 的兼容运行环境中可复用相同实现。在更严格的鸿蒙 NEXT 场景,需确保 Alert 的桥接与 ArkUI 弹框行为一致,或以纯 JS 模态层实现一致性。

样式

StyleSheet.create 将样式常量化并交由 RN 内部做缓存与优化,减少重复创建带来的 GC 压力,同时提升跨端一致性。

  • 字体层级与颜色体系统一在组件内声明,卡片阴影采用轻度参数,既兼顾层次也避免性能压力。
  • 使用 borderRadius 与浅色背景搭配,确保在低端设备上也有良好表现;网格项的百分比宽度使其天然自适配,配合 flexWrap 实现排列稳定。

React Native 的运行时依赖

React Native 的运行时依赖具体环境。对于当前主流鸿蒙设备,Android 兼容层可使 RN 运行路径基本与 AOSP 一致;在更“纯”的鸿蒙栈(如 ArkUI/ArkTS)中,需评估 RN 引擎与桥接层的可用性与替代方案。

  • 推荐启用 Hermes 以降低 JS 引擎体积与启动时延;避免依赖未适配的 Native 模块,尽量用纯 JS 组件与社区通用库(本示例即采用纯 JS 的 react-native-svg)。
  • 尽量使用 RN 基础组件与通用 Flexbox 能力,规避平台差异大的样式属性(如高强度阴影、复杂混合模式)。
  • 弹框、手势与滚动等高频交互统一用 RN 官方组件,确保 ArkUI 或兼容层下也能稳定运行。

列表、详情、弹框、Tab 切换

当前模块已经包含列表、详情、弹框三类要素。若需要补充 Tab 切换,可以以最小改动引入本地状态与轻量 UI:

const [tab, setTab] = React.useState<'列表' | '详情' | '操作'>('列表');

<View style={styles.tabs}>
  <TouchableOpacity style={[styles.tabItem, tab === '列表' && styles.tabActive]} onPress={() => setTab('列表')}>
    <Text style={[styles.tabText, tab === '列表' && styles.tabTextActive]}>列表</Text>
  </TouchableOpacity>
  <TouchableOpacity style={[styles.tabItem, tab === '详情' && styles.tabActive]} onPress={() => setTab('详情')}>
    <Text style={[styles.tabText, tab === '详情' && styles.tabTextActive]}>详情</Text>
  </TouchableOpacity>
  <TouchableOpacity style={[styles.tabItem, tab === '操作' && styles.tabActive]} onPress={() => setTab('操作')}>
    <Text style={[styles.tabText, tab === '操作' && styles.tabTextActive]}>操作</Text>
  </TouchableOpacity>
</View>

{tab === '列表' && <ListSection />}
{tab === '详情' && <DetailSection />}
{tab === '操作' && <ActionSection />}

这种“状态驱动的可视区切换”不引入导航或路由库,能在各端保持一致,且几乎不增加工程复杂度;样式层面以浅色背景 + 文字加粗区分选中态,实现低成本但直观的交互反馈。

这个页面以 RN 的函数式组件为核心,结合内联 SVG 的资源管理策略与基础交互桥接,在不依赖外部模块的情况下完成了跨端稳定的 UI 构建。布局与样式遵循 Flexbox 和 StyleSheet 的最佳实践;弹窗与点击交互经由桥接层映射到原生,满足移动端交互的一致性诉求。对于鸿蒙跨端落地,示例通过“纯 JS + 零依赖图标”的可移植方案,规避了 Native 模块适配与资源打包的复杂度,为进一步扩展列表、详情、弹框以及 Tab 切换提供了清晰的工程化路径。


真实演示案例代码:

import React from 'react';
import { SafeAreaView, View, Text, StyleSheet, TouchableOpacity, ScrollView, Alert } from 'react-native';
import { SvgXml } from 'react-native-svg';
export const MINI_ICONS = {
  tooth: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTkgNWMtMiAwLTQgMi00IDQgMCAyIDIgNCA0IDQgMSAwIDEtMSAyLTIgMSAwIDEgMSAyIDIgMiAwIDIuNSAyLjUgNCA0IDIgMiAyLTQgNC00IDQgMCAyLTItNCA0LTRzLTEuNSAyLjUgMiAyLjVjMiAwIDItMiAyLTIgMCAwLTEuNSAyLjUtMiAyczIgMiAyIDIgMi0xIDItMiAwLTQtNC00LTQtNC0yLTQgMC0yIiBmaWxsPSIjM2I4MmY2Ii8+PC9zdmc+',
  pill: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+cmVjdCB4PSI1IiB5PSI1IiB3aWR0aD0iMTQiIGhlaWdodD0iOCIgcng9IjQiIGZpbGw9IiNmZDE5MjkiLzxyZWN0IHg9IjUiIHk9IjEzIiB3aWR0aD0iMTQiIGhlaWdodD0iNiIgcng9IjQiIGZpbGw9IiM5YmQyZmYiLzwv c3ZnPg==',
  cat: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSI5IiBmaWxsPSIjZmZjY2U3Ii8+Y2lyY2xlIGN4PSI5IiBjeT0iMTAiIHI9IjEiIGZpbGw9IiM0NDQ0NDQiLz5jaXJjbGUgY3g9IjE1IiBjeT0iMTAiIHI9IjEiIGZpbGw9IiM0NDQ0NDQiLzxnIGZpbGw9IiM0NDQ0NDQiPjxjaXJjbGUgY3g9IjEyIiBjeT0iMTYiIHI9IjIiLz48L2c+PC9zdmc+',
  calendar: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+cmVjdCB4PSI0IiB5PSI2IiB3aWR0aD0iMTYiIGhlaWdodD0iMTIiIHJ4PSIyIiBmaWxsPSIjZWRmMmY1Ii8+cmVjdCB4PSI0IiB5PSI0IiB3aWR0aD0iMTYiIGhlaWdodD0iMiIgZmlsbD0iIzNiODJmNiIvPjxjaXJjbGUgY3g9IjgiIGN5PSIxMCIgcj0iMSIgZmlsbD0iIzNiODJmNiIvPjxjaXJjbGUgY3g9IjEyIiBjeT0iMTAiIHI9IjEiIGZpbGw9IiMzYjgyZjYiLz48Y2lyY2xlIGN4PSIxNiIgY3k9IjEwIiByPSIxIiBmaWxsPSIjM2I4MmY2Ii8+PC9zdmc+',
  album: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+cmVjdCB4PSI0IiB5PSI0IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHJ4PSIyIiBmaWxsPSIjZjFmNWY5Ii8+Y2lyY2xlIGN4PSI5IiBjeT0iOSIgcj0iMiIgZmlsbD0iIzBlYTVlOSIvPjxwYXRoIGQ9Ik03IDE2bDMtM2wzIDNsMy0zIDMgNCIgZmlsbD0iIzNiODJmNiIvPjwvc3ZnPg==',
  wardrobe: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+cmVjdCB4PSI1IiB5PSI0IiB3aWR0aD0iMTQiIGhlaWdodD0iMTYiIHJ4PSIyIiBmaWxsPSIjZTJlNGYxIi8+cmVjdCB4PSIxMSIgeT0iNCIgd2lkdGg9IjIiIGhlaWdodD0iMTYiIGZpbGw9IiM5NDlhYjgiLz48Y2lyY2xlIGN4PSI5IiBjeT0iMTAiIHI9IjEiIGZpbGw9IiM5NDlhYjgiLz48Y2lyY2xlIGN4PSIxNSIgY3k9IjEwIiByPSIxIiBmaWxsPSIjOTQ5YWI4Ii8+PC9zdmc+',
  recycle: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSI5IiBmaWxsPSIjZWRmMmY1Ii8+ cGF0aCBkPSJNOSA5bDMgMS0xIDMgMy0xLTEtMyIgZmlsbD0iIzNiODJmNiIvPC9zdmc+',
  shirt: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+ cGF0aCBkPSJNOSA1bDMgMiAzaC0zbDMtMiAyIDMgMCAxMS0xMmgwIiBmaWxsPSIjM2I4MmY2Ii8+PC9zdmc+',
  dress: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+ cGF0aCBkPSJNNyA4bDIgMyAyIDMgMiA5aC0xNHoiIGZpbGw9IiNmZDE5MjkiLz48L3N2Zz4=',
  report: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+cmVjdCB4PSI3IiB5PSI0IiB3aWR0aD0iMTAiIGhlaWdodD0iMTYiIHJ4PSIyIiBmaWxsPSIjZmZmIiBzdHJva2U9IiM5NGJhYjgiIHN0cm9rZS13aWR0aD0iMSIvP3RleHQ+PC9zdmc+',
  family: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+Y2lyY2xlIGN4PSI5IiBjeT0iMTAiIHI9IjIiIGZpbGw9IiNmZDE5MjkiLz5jaXJjbGUgY3g9IjE1IiBjeT0iMTAiIHI9IjIiIGZpbGw9IiM5YmQyZmYiLz48Y2lyY2xlIGN4PSIxMiIgY3k9IjE2IiByPSIyIiBmaWxsPSIjM2I4MmY2Ii8+PC9zdmc+',
  heart: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+ cGF0aCBkPSJNMTIgMjBsLTktOGE0IDQgMCAxIDEgOCAwbDkgOGE0IDQgMCAxIDEtOCAwIiBmaWxsPSIjZWQ0MTQxIi8+PC9zdmc+',
  star: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+ cGF0aCBkPSJNMTIgNGwzIDZsNyAxLThsLTMgN2wyIDgtNy0zLTcgMyAyLThoLTJsLTctMyA3LTMtMi04IDMtN3oiIGZpbGw9IiNmYWQxMDQiLz48L3N2Zz4=',
  bell: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+ cGF0aCBkPSJNMTIgNGMtMyAyLTUgNS01IDd2NWgxM3YtNWMwLTItMi01LTUtN3oiIGZpbGw9IiM5NDlhYjgiLz48Y2lyY2xlIGN4PSIxMiIgY3k9IjIxIiByPSIxIiBmaWxsPSIjOTQ5YWI4Ii8+PC9zdmc+',
  check: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+ cGF0aCBkPSJNNyAxMmwzIDMgNy03IiBmaWxsPSIjM2I4MmY2Ii8+PC9zdmc+',
  info: 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSI5IiBmaWxsPSIjZWRmMmY1Ii8+ZyBmaWxsPSIjM2I4MmY2Ij48Y2lyY2xlIGN4PSIxMiIgY3k9IjkiIHI9IjEiLz48cmVjdCB4PSIxMSIgeT0iMTIiIHdpZHRoPSIyIiBoZWlnaHQ9IjYiLz48L2c+PC9zdmc+',
};

const OralCareTasks: React.FC = () => {
  const onDetail = () => {
    Alert.alert('今日任务', '口腔护理清单:刷牙2次、使用牙线1次、漱口1次');
  };

  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.header}>
        <Text style={styles.title}>口腔护理 · 今日任务</Text>
        <View style={styles.headerIcons}>
          <SvgXml xml={MINI_ICONS.tooth} width={24} height={24} />
          <Text style={styles.headerEmoji}>🪥</Text>
          <Text style={styles.headerEmoji}>🦷</Text>
        </View>
      </View>

      <ScrollView style={styles.content}>
        <View style={styles.statRow}>
          <View style={styles.statCard}>
            <Text style={styles.statTitle}>刷牙次数</Text>
            <Text style={styles.statValue}>2</Text>
            <Text style={styles.statDesc}>早晚各一次</Text>
          </View>
          <View style={[styles.statCard, styles.statCardAlt]}>
            <Text style={styles.statTitle}>牙线使用</Text>
            <Text style={styles.statValue}>1</Text>
            <Text style={styles.statDesc}>晚间清理</Text>
          </View>
        </View>

        <View style={styles.grid}>
          <View style={styles.gridItem}>
            <Text style={styles.gridIcon}>🪥</Text>
            <Text style={styles.gridTitle}>早间牙刷</Text>
            <Text style={styles.gridDesc}>柔软刷毛,2分钟</Text>
          </View>
          <View style={styles.gridItem}>
            <Text style={styles.gridIcon}>🧴</Text>
            <Text style={styles.gridTitle}>含氟牙膏</Text>
            <Text style={styles.gridDesc}>防蛀固齿</Text>
          </View>
          <View style={styles.gridItem}>
            <Text style={styles.gridIcon}>🦷</Text>
            <Text style={styles.gridTitle}>牙线护理</Text>
            <Text style={styles.gridDesc}>缝隙清洁</Text>
          </View>
          <View style={styles.gridItem}>
            <Text style={styles.gridIcon}>🫗</Text>
            <Text style={styles.gridTitle}>漱口水</Text>
            <Text style={styles.gridDesc}>清新口气</Text>
          </View>
        </View>

        <View style={styles.tipSection}>
          <Text style={styles.sectionTitle}>护理建议</Text>
          <View style={styles.tipCard}>
            <SvgXml xml={MINI_ICONS.pill} width={22} height={22} />
            <View style={styles.tipTextBox}>
              <Text style={styles.tipTitle}>轻柔刷牙</Text>
              <Text style={styles.tipText}>避免用力过猛,沿牙龈线小幅度移动。</Text>
            </View>
          </View>
          <View style={styles.tipCard}>
            <SvgXml xml={MINI_ICONS.pill} width={22} height={22} />
            <View style={styles.tipTextBox}>
              <Text style={styles.tipTitle}>定期更换</Text>
              <Text style={styles.tipText}>牙刷建议每3个月更换一次。</Text>
            </View>
          </View>
        </View>

        <View style={styles.actionBar}>
          <TouchableOpacity style={styles.actionBtn} onPress={onDetail}>
            <Text style={styles.actionIcon}>📋</Text>
            <Text style={styles.actionText}>查看详情</Text>
          </TouchableOpacity>
          <TouchableOpacity style={[styles.actionBtn, styles.actionBtnPrimary]} onPress={onDetail}>
            <Text style={styles.actionIcon}></Text>
            <Text style={styles.actionTextPrimary}>标记完成</Text>
          </TouchableOpacity>
        </View>
      </ScrollView>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: '#f7fbff' },
  header: {
    padding: 16,
    backgroundColor: '#ffffff',
    borderBottomWidth: 1,
    borderBottomColor: '#e6edf5',
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  title: { fontSize: 18, fontWeight: 'bold', color: '#0f172a' },
  headerIcons: { flexDirection: 'row', alignItems: 'center', gap: 8 },
  headerEmoji: { fontSize: 18, marginLeft: 8 },
  content: { padding: 16 },
  statRow: { flexDirection: 'row', gap: 12, marginBottom: 16 },
  statCard: {
    flex: 1,
    backgroundColor: '#eaf3ff',
    borderRadius: 12,
    padding: 14,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.08,
    shadowRadius: 2,
  },
  statCardAlt: { backgroundColor: '#f0f9ff' },
  statTitle: { fontSize: 12, color: '#475569' },
  statValue: { fontSize: 20, fontWeight: '600', color: '#1e293b', marginTop: 4 },
  statDesc: { fontSize: 12, color: '#64748b', marginTop: 6 },
  grid: { flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', gap: 12 },
  gridItem: {
    width: '48%',
    backgroundColor: '#ffffff',
    borderRadius: 12,
    padding: 12,
    marginTop: 12,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.08,
    shadowRadius: 2,
  },
  gridIcon: { fontSize: 22, marginBottom: 6 },
  gridTitle: { fontSize: 13, fontWeight: '600', color: '#0f172a' },
  gridDesc: { fontSize: 12, color: '#64748b', marginTop: 2 },
  tipSection: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    padding: 14,
    marginTop: 16,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.08,
    shadowRadius: 2,
  },
  sectionTitle: { fontSize: 16, fontWeight: 'bold', color: '#0f172a', marginBottom: 10 },
  tipCard: { flexDirection: 'row', alignItems: 'center', marginBottom: 10 },
  tipTextBox: { marginLeft: 10, flex: 1 },
  tipTitle: { fontSize: 13, fontWeight: '600', color: '#0f172a' },
  tipText: { fontSize: 12, color: '#475569', marginTop: 2 },
  actionBar: { flexDirection: 'row', justifyContent: 'space-between', marginTop: 18 },
  actionBtn: {
    flex: 1,
    backgroundColor: '#f1f5f9',
    borderRadius: 12,
    paddingVertical: 12,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    marginRight: 10,
  },
  actionBtnPrimary: { backgroundColor: '#3b82f6', marginRight: 0 },
  actionIcon: { fontSize: 16, marginRight: 6, color: '#334155' },
  actionText: { fontSize: 14, color: '#334155', fontWeight: '500' },
  actionTextPrimary: { fontSize: 14, color: '#ffffff', fontWeight: '600' },
});

export default OralCareTasks;

请添加图片描述


打包

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

在这里插入图片描述

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

在这里插入图片描述

最后运行效果图如下显示:
请添加图片描述

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

Logo

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

更多推荐