这个狗狗投票应用采用了清晰的组件化架构,通过职责分离实现了代码的复用性和可维护性。核心组件 VotingPage 作为主容器,负责状态管理和整体布局,而 VoteCard 作为展示单元,专注于单个狗狗投票项的渲染和交互。

可复用 VoteCard 组件

const VoteCard: React.FC<{ 
  dog: any, 
  onVote: (id: number) => void, 
  voted: boolean 
}> = ({ dog, onVote, voted }) => {
  // 组件实现...
};

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

数据结构

const VOTES_DATA = [
  {
    id: 1,
    name: '金毛寻回犬',
    image: 'https://picsum.photos/300/200?random=1',
    votes: 128,
    percentage: 32,
    description: '温顺友善,是最受欢迎的家庭犬之一',
    breed: '大型犬',
    age: '3岁',
    owner: '李女士',
  },
  // 更多狗狗...
];

数据结构设计全面而详细,包含了狗狗的基本信息、图片、投票数据、描述和主人信息等。这种结构化的数据设计为后续的功能扩展和数据管理提供了便利,同时也使得投票功能的实现变得简单直接。


状态管理实现

const [votes, setVotes] = useState(VOTES_DATA);
const [votedDogs, setVotedDogs] = useState<number[]>([]);
const [totalVotes, setTotalVotes] = useState(400); // 初始总票数

使用 useState Hook 管理三个状态:

  1. votes:狗狗投票数据,初始值为模拟数据 VOTES_DATA
  2. votedDogs:已投票的狗狗ID数组,初始值为空数组
  3. totalVotes:总票数,初始值为 400

这种状态管理方式清晰明了,适合处理用户投票产生的状态变化。

投票功能

const handleVote = (id: number) => {
  if (votedDogs.includes(id)) {
    Alert.alert('提示', '您已经为这只狗狗投过票了!');
    return;
  }

  setVotes(votes.map(dog =>
    dog.id === id
      ? { ...dog, votes: dog.votes + 1, percentage: Math.round((dog.votes + 1) / (totalVotes + 1) * 100) }
      : { ...dog, percentage: Math.round(dog.votes / (totalVotes + 1) * 100) }
  ));
  
  setVotedDogs([...votedDogs, id]);
  setTotalVotes(totalVotes + 1);
  
  Alert.alert('投票成功', '感谢您为可爱的狗狗投票!');
};

投票功能实现了以下逻辑:

  1. 检查用户是否已经为该狗狗投过票,如果是则显示提示信息
  2. 更新狗狗的票数和百分比,以及其他狗狗的百分比
  3. 将狗狗ID添加到已投票数组中
  4. 增加总票数
  5. 显示投票成功的提示信息

这种实现方式确保了投票数据的一致性和准确性,同时提供了清晰的用户反馈。

今日之星

const getTopDog = () => {
  return votes.reduce((top, dog) => dog.votes > top.votes ? dog : top, votes[0]);
};

const topDog = getTopDog();

今日之星功能通过 reduce 方法实现,从投票数据中找出得票最高的狗狗。这种实现方式简洁高效,能够实时反映当前的投票情况。


页面布局

<SafeAreaView style={styles.container}>
  {/* 头部 */}
  <View style={styles.header}>
    <Text style={styles.title}>狗狗投票榜</Text>
    <Text style={styles.totalVotes}>总票数: {totalVotes}</Text>
  </View>

  {/* 今日之星 */}
  <View style={styles.featuredCard}>
    {/* 今日之星内容 */}
  </View>

  {/* 投票列表 */}
  <ScrollView style={styles.content}>
    {/* 投票列表内容 */}
  </ScrollView>

  {/* 底部导航 */}
  <View style={styles.bottomNav}>
    {/* 底部导航内容 */}
  </View>
</SafeAreaView>

页面布局采用了分层设计:

  • 头部:包含标题和总票数
  • 今日之星卡片:展示得票最高的狗狗
  • 投票列表:展示所有狗狗,支持滚动查看
  • 底部导航栏:提供导航功能

这种布局设计清晰明了,用户可以直观地理解和使用应用的功能。

投票进度条

<View style={styles.progressBar}>
  <View 
    style={[ 
      styles.progressFill, 
      { width: `${dog.percentage}%`, backgroundColor: dog.percentage > 20 ? '#3b82f6' : '#8b5cf6' } 
    ]} 
  />
</View>

投票进度条使用两个 View 实现,外层 View 作为进度条的容器,内层 View 作为进度条的填充部分。根据狗狗的得票百分比动态计算填充部分的宽度,并根据百分比值设置不同的颜色,提供了直观的视觉反馈。

视觉层次感

样式定义中注重了视觉层次感的营造:

  • 卡片使用白色背景、圆角和阴影效果,与浅灰色的页面背景形成对比
  • 标题使用较大的字体和加粗效果,突出页面的主题
  • 狗狗信息使用不同大小和颜色的字体,区分重要性
  • 投票按钮根据投票状态显示不同的样式,提供清晰的视觉反馈
  • 进度条根据百分比显示不同的颜色,增强了视觉识别度

这种视觉层次感的设计不仅提升了页面的美观度,也增强了用户对页面结构的理解。


  1. 组件映射
    • SafeAreaViewSafeAreaFlex 容器
    • ViewFlex 容器
    • TextText 组件
    • TouchableOpacityButtonText + 手势事件
    • ImageImage 组件
    • ScrollViewScroll 组件
    • AlertDialog 组件

这个狗狗投票应用展示了 React Native 跨端开发的核心技术要点,通过合理的组件设计、清晰的状态管理、直观的用户界面和完整的功能实现,为用户提供了一个功能齐全、体验良好的投票工具。在鸿蒙系统适配方面,通过组件映射、样式适配和功能重实现,可以快速实现跨端迁移,保持功能和视觉效果的一致性。


全程采用React Native原生组件与React核心特性开发,遵循组件化复用状态驱动视图跨端通用样式的设计原则,所有API、组件、样式均为React Native与鸿蒙平台的通用能力,借助React Native for HarmonyOS桥接层可无缝编译为鸿蒙原生组件,Android、iOS、鸿蒙三端共用一套核心逻辑,实现原生级的交互与视觉体验。本文将从鸿蒙跨端友好的技术基底组件化拆分与复用设计状态驱动的实时投票体系跨端兼容的布局与视觉规范鸿蒙跨端落地与生产级拓展等维度,深度解读该实现的技术细节,为各类跨端投票、评选、榜单类页面开发提供可直接复用的工程化方案。

本项目的技术选型围绕投票榜页面的产品特性鸿蒙跨端兼容性两大核心原则,全程使用React Native原生核心组件与API完成开发,未引入任何第三方依赖或平台专属特性,所有实现均遵循“跨端通用、原生渲染、轻量高效”的设计思路,为鸿蒙跨端落地奠定极简工程基础,同时贴合投票榜页面“交互即时、数据实时、布局规整、操作清晰”的产品诉求,核心技术基底设计如下:

1. 核心原生组件:

选用SafeAreaViewViewTextTouchableOpacityScrollViewImageAlert等React Native核心原生组件,这类组件均完成React Native for HarmonyOS的深度桥接,底层会被编译为对应平台的原生组件(鸿蒙Component、Android View、iOS UIView),基于原生渲染引擎执行,彻底规避WebView渲染的性能损耗。其中针对投票榜场景的核心适配亮点:

  • ScrollView的惯性滚动、滚动条样式在鸿蒙平台自动适配,当狗狗投票卡片过多时,滚动体验流畅无卡顿,且支持鸿蒙折叠屏、平板的大屏滚动适配;
  • TouchableOpacity的触摸反馈桥接为鸿蒙原生的按压效果(淡入淡出),投票按钮的点击体验与鸿蒙原生应用完全一致,无交互延迟,贴合投票操作的即时性诉求;
  • Image的远程URI加载、固定宽高渲染在鸿蒙平台原生支持,狗狗图片无拉伸、无加载异常,且支持鸿蒙的图片缓存策略,重复进入页面无需重新加载图片;
  • Alert的弹窗提示桥接为鸿蒙AlertDialog原生弹窗,投票成功、重复投票的提示弹窗层级、动画均为鸿蒙原生效果,提示信息展示清晰;
  • SafeAreaView自动桥接鸿蒙的安全区域适配能力,兼容鸿蒙设备的刘海屏、底部导航栏,保证投票榜的核心内容(投票按钮、票数统计)不被系统控件遮挡;
  • 所有组件的使用方式均为React Native标准用法,无任何鸿蒙平台专属配置,前端开发者基于现有React Native技术积累即可开发,跨端学习成本为零。

2. 核心能力:

依托React Native原生能力实现所有投票业务功能,核心能力均为JavaScript/React通用特性,在鸿蒙平台的JS引擎中可直接执行,无需任何适配修改,完美贴合投票榜“状态实时更新、数据动态计算”的核心诉求:

  • 状态管理:采用useState轻量管理投票数据、已投票狗狗ID、总票数三大核心状态,遵循React状态不可变原则,状态更新驱动视图的局部重渲染,与鸿蒙ArkUI的@State状态管理理念高度同源;
  • 组件化开发:将投票卡片拆分为独立的VoteCard子组件,通过Props实现父组件向子组件的数据传递事件回调,组件化设计让代码结构清晰,复用性强,且React的组件化语法在鸿蒙平台可直接解析执行;
  • 条件渲染与样式动态绑定:基于已投票状态实现投票按钮的“可点击/不可点击”状态切换、样式动态变化,基于票数占比实现进度条的宽度与颜色动态调整,所有动态逻辑均为React通用语法,鸿蒙平台无兼容成本;
  • 数组操作与数据计算:采用JavaScript数组的mapreduceincludes等通用方法实现投票数据遍历、今日之星评选、重复投票判断,所有数据计算逻辑在鸿蒙平台的JS引擎中可直接执行,计算效率无损耗;
  • 样式渲染:基于StyleSheet.create()实现模块化样式管理,支持Flex弹性布局、圆角、阴影、动态样式拼接等所有通用样式属性,在鸿蒙平台桥接为ArkUI的原生样式。

三状态分离的设计方式让状态的更新与维护更精准:投票数据的更新仅触发投票卡片与今日之星的重渲染,已投票状态的更新仅触发对应投票按钮的样式重渲染,总票数的更新仅触发头部总票统计与票数占比的重渲染,遵循React的最小重渲染原则,提升页面性能,且这种状态设计在鸿蒙平台无任何兼容问题,setVotessetVotedDogssetTotalVotes的状态更新逻辑会被桥接为ArkUI的状态更新,触发视图的高效重渲染。

2. 核心投票逻辑:

投票操作的核心逻辑在handleVote方法中实现,该方法接收子组件传递的狗狗ID,完成重复投票判断投票数据更新已投票状态更新总票数更新操作反馈等全链路逻辑,严格遵循React状态不可变原则,不直接修改原状态值,仅通过setState方法实现状态的浅拷贝更新,保证状态的可追踪性与稳定性,核心逻辑拆解:

(1)重复投票判断:

通过JavaScript数组的includes方法判断当前狗狗ID是否存在于votedDogs数组中,若存在则弹出提示弹窗并终止后续逻辑,实现重复投票防重,核心代码:

if (votedDogs.includes(id)) {
  Alert.alert('提示', '您已经为这只狗狗投过票了!');
  return;
}

该判断逻辑为JavaScript通用能力,在鸿蒙平台的JS引擎中可直接执行,判断效率无损耗,且Alert弹窗桥接为鸿蒙原生AlertDialog,提示效果与鸿蒙原生应用一致。

(2)投票数据更新:票数与占比实时计算

通过数组的map方法遍历投票数据,对当前投票的狗狗实现票数+1,并基于更新后的总票数(totalVotes + 1)重新计算所有狗狗的票数占比(保留整数),核心代码:

setVotes(votes.map(dog => 
  dog.id === id 
    ? { ...dog, votes: dog.votes + 1, percentage: Math.round((dog.votes + 1) / (totalVotes + 1) * 100) } 
    : { ...dog, percentage: Math.round(dog.votes / (totalVotes + 1) * 100) }
));

其中采用对象浅拷贝{ ...dog })的方式更新狗狗数据,严格遵循React状态不可变原则,避免直接修改原数组中的对象导致的状态混乱。票数占比的计算公式为(当前狗狗票数 / 总票数) * 100,投票后总票数加1,因此所有狗狗的占比均需重新计算,保证占比的准确性。

(3)状态与总票数更新:

将当前狗狗ID添加到votedDogs数组中,实现已投票状态的更新;将总票数加1,实现总票数的实时更新,核心代码:

setVotedDogs([...votedDogs, id]);
setTotalVotes(totalVotes + 1);

其中[...votedDogs, id]为数组的浅拷贝方式,保证不直接修改原数组,符合React状态不可变原则。

(4)操作反馈:

投票成功后弹出提示弹窗,告知用户投票结果,核心代码:

Alert.alert('投票成功', '感谢您为可爱的狗狗投票!');

弹窗为鸿蒙原生AlertDialog,提示信息展示清晰,无交互延迟,贴合投票操作的即时性诉求。

3. 今日之星评选:

通过JavaScript数组的reduce方法实现今日之星的自动评选,核心逻辑为遍历投票数据,筛选出票数最高的狗狗,作为今日之星展示在页面顶部的推荐区域,核心代码:

const getTopDog = () => {
  return votes.reduce((top, dog) => dog.votes > top.votes ? dog : top, votes[0]);
};
const topDog = getTopDog();

该方法在组件渲染时自动执行,当投票数据更新(votes状态变化)时,topDog会自动重新计算,实现今日之星的实时更新。若多个狗狗票数相同,默认选择数组中靠前的狗狗,生产环境可根据需求优化为“票数相同则并列展示”。所有数组操作均为JavaScript通用能力,在鸿蒙平台无任何兼容成本,计算效率无损耗。

4. 状态联动:

整个投票体系遵循状态驱动视图的核心思想,实现“用户投票操作 → 状态更新 → 数据重新计算 → 视图实时重渲染”的全链路联动,核心联动流程:

  1. 用户点击某只狗狗的投票按钮 → 子组件VoteCard通过onVote回调将狗狗ID传递给父组件;
  2. 父组件VotingPagehandleVote方法中完成重复投票判断,若未重复则更新votes(票数+1、占比重算)、votedDogs(添加狗狗ID)、totalVotes(+1)三大状态;
  3. 状态更新后,React自动检测到状态变化,触发相关视图的重渲染:
    • votes状态变化 → 投票卡片的票数、占比、进度条重渲染,今日之星topDog重新计算并重渲染;
    • votedDogs状态变化 → 对应投票卡片的按钮样式、文字、禁用状态重渲染;
    • totalVotes状态变化 → 页面头部的总票数统计重渲染。

整个联动流程无任何人工干预,完全由React的状态管理机制驱动,所有逻辑均为React通用能力,在鸿蒙平台可直接解析执行,无任何跨端适配成本,保证了投票操作的即时性与数据的实时准确性。


本次解析的狗狗投票榜实战项目,是一套基于React Native组件化与状态驱动思想开发的跨端榜单类页面工程化实现,核心依托React原生的useState三状态管理、Props组件双向通信,实现了实时投票计数、重复投票防重、票数占比动态计算、今日之星自动评选等核心功能,同时将投票卡片拆分为独立的可复用组件,打造了“头部总票统计-今日之星推荐-滚动投票列表-底部导航”的标准化页面架构。项目全程基于React Native跨平台原生API开发,遵循鸿蒙跨端友好的开发原则,所有实现均无平台专属特性,依托React Native for HarmonyOS可实现鸿蒙跨端的无缝落地,零业务代码修改。

该项目的技术价值不仅在于完成了狗狗投票榜的核心开发,更在于为跨端投票、评选、榜单、排行榜等常见页面提供了可复用的工程化开发范式:

  1. 采用**useState多状态分离管理**,实现投票数据、操作状态、统计数据的精细化管理,状态更新驱动视图实时重渲染,与鸿蒙ArkUI的状态管理理念高度同源,保证了跨端状态逻辑的一致性;
  2. 遵循React组件化思想,将核心视觉单元拆分为独立的可复用组件,通过Props实现父组件与子组件的双向通信,让代码结构清晰、复用性强,且组件化语法在鸿蒙平台无兼容成本;
  3. 依托Flex弹性布局动态样式绑定,实现所有模块的跨端自适应布局与精细化的视觉动态反馈,进度条、投票按钮的样式随状态实时变化,让用户操作感知更直观,三端视觉效果高度统一;
  4. 打造标准化的榜单页面架构完整的投票交互体系,贴合移动端用户的交互与视觉习惯,可快速迁移至各类跨端榜单、投票、评选类页面开发;
  5. 预留丰富的生产级拓展入口,可快速接入真实的后端投票系统、用户系统、WebSocket实时推送,同时支持鸿蒙原子化服务、分布式数据管理等专属能力的适配,工程拓展性强。

真实演示案例代码:



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

// 图标库
const ICONS = {
  home: '🏠',
  vote: '🗳️',
  dog: '🐕',
  heart: '❤️',
  star: '⭐',
  like: '👍',
  share: '🔗',
  user: '👤',
};

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

// 模拟投票数据
const VOTES_DATA = [
  {
    id: 1,
    name: '金毛寻回犬',
    image: 'https://picsum.photos/300/200?random=1',
    votes: 128,
    percentage: 32,
    description: '温顺友善,是最受欢迎的家庭犬之一',
    breed: '大型犬',
    age: '3岁',
    owner: '李女士',
  },
  {
    id: 2,
    name: '边境牧羊犬',
    image: 'https://picsum.photos/300/200?random=2',
    votes: 96,
    percentage: 24,
    description: '聪明机智,被誉为最聪明的犬种',
    breed: '中型犬',
    age: '2岁',
    owner: '张先生',
  },
  {
    id: 3,
    name: '哈士奇',
    image: 'https://picsum.photos/300/200?random=3',
    votes: 78,
    percentage: 19,
    description: '活泼好动,有着独特的蓝色眼睛',
    breed: '大型犬',
    age: '4岁',
    owner: '王小姐',
  },
  {
    id: 4,
    name: '柯基犬',
    image: 'https://picsum.photos/300/200?random=4',
    votes: 65,
    percentage: 16,
    description: '短腿长身,性格开朗活泼',
    breed: '小型犬',
    age: '1岁',
    owner: '刘先生',
  },
  {
    id: 5,
    name: '柴犬',
    image: 'https://picsum.photos/300/200?random=5',
    votes: 33,
    percentage: 9,
    description: '日本本土犬种,表情丰富可爱',
    breed: '中型犬',
    age: '2岁',
    owner: '陈女士',
  },
];

const VoteCard: React.FC<{ 
  dog: any, 
  onVote: (id: number) => void,
  voted: boolean
}> = ({ dog, onVote, voted }) => {
  return (
    <View style={styles.voteCard}>
      <Image source={{ uri: dog.image }} style={styles.dogImage} />
      <View style={styles.dogInfo}>
        <View style={styles.dogHeader}>
          <Text style={styles.dogName}>{dog.name}</Text>
          <Text style={styles.breed}>{dog.breed}</Text>
        </View>
        <Text style={styles.description}>{dog.description}</Text>
        <View style={styles.dogDetails}>
          <Text style={styles.detail}>{dog.age}{dog.owner}</Text>
          <View style={styles.votesContainer}>
            <Text style={styles.votes}>{dog.votes}</Text>
            <Text style={styles.percentage}>{dog.percentage}%</Text>
          </View>
        </View>
        <View style={styles.progressBar}>
          <View 
            style={[
              styles.progressFill, 
              { width: `${dog.percentage}%`, backgroundColor: dog.percentage > 20 ? '#3b82f6' : '#8b5cf6' }
            ]} 
          />
        </View>
        <TouchableOpacity 
          style={[styles.voteButton, voted && styles.votedButton]} 
          onPress={() => onVote(dog.id)}
          disabled={voted}
        >
          <Text style={[styles.voteButtonText, voted && styles.votedButtonText]}>
            {voted ? '已投票 ✓' : `${ICONS.star} 投票`}
          </Text>
        </TouchableOpacity>
      </View>
    </View>
  );
};

const VotingPage: React.FC = () => {
  const [votes, setVotes] = useState(VOTES_DATA);
  const [votedDogs, setVotedDogs] = useState<number[]>([]);
  const [totalVotes, setTotalVotes] = useState(400); // 初始总票数

  const handleVote = (id: number) => {
    if (votedDogs.includes(id)) {
      Alert.alert('提示', '您已经为这只狗狗投过票了!');
      return;
    }

    setVotes(votes.map(dog => 
      dog.id === id 
        ? { ...dog, votes: dog.votes + 1, percentage: Math.round((dog.votes + 1) / (totalVotes + 1) * 100) } 
        : { ...dog, percentage: Math.round(dog.votes / (totalVotes + 1) * 100) }
    ));
    
    setVotedDogs([...votedDogs, id]);
    setTotalVotes(totalVotes + 1);
    
    Alert.alert('投票成功', '感谢您为可爱的狗狗投票!');
  };

  const getTopDog = () => {
    return votes.reduce((top, dog) => dog.votes > top.votes ? dog : top, votes[0]);
  };

  const topDog = getTopDog();

  return (
    <SafeAreaView style={styles.container}>
      {/* 头部 */}
      <View style={styles.header}>
        <Text style={styles.title}>狗狗投票榜</Text>
        <Text style={styles.totalVotes}>总票数: {totalVotes}</Text>
      </View>

      {/* 今日之星 */}
      <View style={styles.featuredCard}>
        <Text style={styles.featuredTitle}>🏆 今日之星</Text>
        <View style={styles.featuredDog}>
          <Image source={{ uri: topDog.image }} style={styles.featuredImage} />
          <View style={styles.featuredInfo}>
            <Text style={styles.featuredName}>{topDog.name}</Text>
            <Text style={styles.featuredVotes}>{topDog.votes}</Text>
            <Text style={styles.featuredBreed}>{topDog.breed}</Text>
          </View>
        </View>
      </View>

      {/* 投票列表 */}
      <ScrollView style={styles.content}>
        <Text style={styles.sectionTitle}>参与投票</Text>
        <Text style={styles.sectionSubtitle}>为您喜爱的狗狗投上一票</Text>
        
        {votes.map(dog => (
          <VoteCard 
            key={dog.id}
            dog={dog}
            onVote={handleVote}
            voted={votedDogs.includes(dog.id)}
          />
        ))}
      </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.vote}</Text>
          <Text style={styles.navText}>投票</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.navItem}>
          <Text style={styles.navIcon}>{ICONS.dog}</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: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 20,
    backgroundColor: '#ffffff',
    borderBottomWidth: 1,
    borderBottomColor: '#e2e8f0',
  },
  title: {
    fontSize: 20,
    fontWeight: 'bold',
    color: '#1e293b',
  },
  totalVotes: {
    fontSize: 14,
    color: '#64748b',
  },
  featuredCard: {
    backgroundColor: '#ffffff',
    margin: 16,
    borderRadius: 12,
    padding: 16,
    elevation: 3,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
  },
  featuredTitle: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#f59e0b',
    marginBottom: 12,
  },
  featuredDog: {
    flexDirection: 'row',
  },
  featuredImage: {
    width: 80,
    height: 80,
    borderRadius: 12,
    marginRight: 12,
  },
  featuredInfo: {
    flex: 1,
    justifyContent: 'center',
  },
  featuredName: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 4,
  },
  featuredVotes: {
    fontSize: 16,
    color: '#3b82f6',
    fontWeight: '600',
    marginBottom: 4,
  },
  featuredBreed: {
    fontSize: 14,
    color: '#64748b',
  },
  content: {
    flex: 1,
    padding: 16,
  },
  sectionTitle: {
    fontSize: 22,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 4,
  },
  sectionSubtitle: {
    fontSize: 14,
    color: '#64748b',
    marginBottom: 20,
  },
  voteCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    marginBottom: 16,
    overflow: 'hidden',
    elevation: 3,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
  },
  dogImage: {
    width: '100%',
    height: 160,
  },
  dogInfo: {
    padding: 16,
  },
  dogHeader: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: 8,
  },
  dogName: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#1e293b',
  },
  breed: {
    fontSize: 14,
    color: '#64748b',
    backgroundColor: '#f1f5f9',
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 12,
  },
  description: {
    fontSize: 14,
    color: '#64748b',
    marginBottom: 12,
    lineHeight: 18,
  },
  dogDetails: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: 12,
  },
  detail: {
    fontSize: 12,
    color: '#94a3b8',
  },
  votesContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  votes: {
    fontSize: 14,
    color: '#3b82f6',
    fontWeight: '600',
    marginRight: 8,
  },
  percentage: {
    fontSize: 14,
    color: '#64748b',
  },
  progressBar: {
    height: 6,
    backgroundColor: '#e2e8f0',
    borderRadius: 3,
    marginBottom: 12,
    overflow: 'hidden',
  },
  progressFill: {
    height: '100%',
    borderRadius: 3,
  },
  voteButton: {
    backgroundColor: '#3b82f6',
    paddingVertical: 12,
    borderRadius: 8,
    alignItems: 'center',
  },
  votedButton: {
    backgroundColor: '#cbd5e1',
  },
  voteButtonText: {
    fontSize: 16,
    color: '#ffffff',
    fontWeight: '500',
  },
  votedButtonText: {
    color: '#64748b',
  },
  bottomNav: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    backgroundColor: '#ffffff',
    borderTopWidth: 1,
    borderTopColor: '#e2e8f0',
    paddingVertical: 12,
  },
  navItem: {
    alignItems: 'center',
  },
  navIcon: {
    fontSize: 20,
    color: '#94a3b8',
    marginBottom: 4,
  },
  activeNavIcon: {
    color: '#3b82f6',
  },
  navText: {
    fontSize: 12,
    color: '#94a3b8',
  },
  activeNavText: {
    color: '#3b82f6',
  },
});

export default VotingPage;

请添加图片描述


打包

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

在这里插入图片描述

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

在这里插入图片描述

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

请添加图片描述
本文介绍了一个基于React Native开发的跨平台狗狗投票应用,采用组件化架构设计,核心包含VotingPage容器和可复用的VoteCard组件。应用通过useState管理投票数据、已投票记录和总票数状态,实现实时投票功能并防止重复投票。界面采用分层布局,包含头部、今日之星展示、投票列表和底部导航,通过进度条等视觉元素增强交互体验。该实现完全基于React Native原生组件和API,未使用平台专属特性,可无缝适配鸿蒙系统,保持三端一致的功能和视觉效果,为跨端投票类应用开发提供了可复用的工程化方案。

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

Logo

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

更多推荐