登录注册模块是移动端应用的核心入口,承担着用户身份验证、账户体系构建的关键作用。这份 React Native 认证应用代码,以表单状态管理为核心,结合响应式布局、交互式表单设计、多场景适配的思路,完整实现了现代移动端登录注册的全流程体验,同时具备清晰的跨端适配架构。本文将从 React Native 原生技术实现认证表单核心交互设计鸿蒙(HarmonyOS)跨端适配全方案 三个维度,深度拆解这款认证应用的技术内核,并提供可落地的鸿蒙迁移实践指南。


1. 表单管理

认证模块的核心是表单状态的精准控制,应用基于 TypeScript 定义 FormState 接口,规范登录/注册表单的所有字段(手机号、邮箱、密码、确认密码、验证码),这种强类型约束不仅在编码阶段规避字段名拼写错误,更让表单状态的流转逻辑清晰可追溯。

状态管理层面,应用采用 useState 实现分层的状态控制:

  • formState:管理表单核心数据,通过 handleInputChange 函数实现字段的精准更新,利用 ES6 扩展运算符(...prev)保证状态的不可变更新,避免直接修改原对象导致的渲染异常;
  • isLogin:控制登录/注册模式切换,是整个界面动态渲染的核心开关,所有条件渲染的 UI 元素(确认密码、验证码、记住我选项)均基于该状态展开;
  • showPassword:管理密码显示/隐藏状态,提升密码输入的用户体验;
  • rememberMe:管理登录场景的“记住我”选项,符合认证场景的通用交互习惯。

handleInputChange 函数采用泛型约束(field: keyof FormState),确保仅能更新 FormState 中定义的字段,从类型层面杜绝无效的状态更新,这是 TypeScript 在表单管理中的典型最佳实践。

2. 交互式表单

认证表单的用户体验直接影响用户留存率,这款应用在表单交互设计上体现了极致的用户体验思维:

(1)动态表单

基于 isLogin 状态实现登录/注册表单的动态切换:

  • 登录模式:仅展示手机号/邮箱、密码、记住我选项,简化登录流程;
  • 注册模式:额外展示确认密码、验证码字段,满足注册场景的完整性;
  • 所有动态渲染的字段均采用条件渲染({!isLogin && (...) }),而非重复编写两套表单结构,大幅减少代码冗余。
(2)精细化表单

表单提交前的校验逻辑按场景拆分,兼顾完整性和友好性:

  • 通用校验:登录/注册均校验手机号/邮箱和密码的非空性;
  • 注册专属校验:额外校验确认密码与密码的一致性,避免用户输入错误;
  • 验证码发送校验:校验手机号/邮箱的非空性,避免无效的验证码发送操作;
  • 所有校验失败均通过 Alert.alert 给出明确的错误提示,提示文案精准指向问题字段,提升用户纠错效率。
(3)密码交互

密码输入框集成了显示/隐藏功能:

  • 通过 secureTextEntry={!showPassword} 控制密码的可见性;
  • 右侧的“显示/隐藏”按钮采用绝对定位,不占用输入框宽度,保证布局的紧凑性;
  • 按钮文本动态切换,视觉反馈清晰,符合移动端密码输入的交互规范。

3. 响应式布局

认证页面作为应用的“第一道门”,视觉体验和适配性至关重要,应用在布局设计上体现了以下技术亮点:

(1)自适应表单

通过 Flex 弹性布局实现全设备适配:

  • 表单容器采用卡片式设计(白色背景 + 圆角 + 阴影),提升视觉层次感,elevation/shadow 双配置兼顾安卓/iOS 平台的阴影效果;
  • 验证码输入框与“获取验证码”按钮采用 flexDirection: 'row' 布局,输入框占满剩余宽度(flex: 1),按钮固定最小宽度,保证在不同屏幕宽度下的布局合理性;
  • 第三方登录按钮采用均分宽度(width: '22%'),配合 flexWrap: 'wrap' 实现小屏设备的自动换行,兼顾展示效率和适配性;
  • 所有输入框采用统一的内边距和圆角,保证视觉一致性,backgroundColor: '#f8fafc' 区分输入区域与表单背景,提升输入体验。
(2)交互反馈
  • 按钮状态设计:提交按钮采用主色调(#3b82f6)填充,第三方登录按钮采用边框式设计,视觉权重区分明显,引导用户优先使用账号密码登录;
  • 复选框设计:自定义复选框替代原生组件,选中状态的背景色与主色调一致,勾选标记居中显示,视觉反馈强烈;
  • 分割线设计:“其他登录方式”区域采用左右横线 + 中间文本的分割样式,通过 flex: 1 实现横线的自适应宽度,视觉效果优雅;
  • 链接文本设计:“忘记密码”、“立即注册/立即登录”等链接文本采用主色调,与普通文本形成视觉对比,引导用户操作。
(3)滚动容器

整个页面采用 ScrollView 包裹,避免小屏设备上表单内容超出屏幕高度导致的截断问题,同时 SafeAreaView 保证内容不被状态栏/导航栏遮挡,适配全面屏设备的安全区域。

4. 第三方登录

应用在核心认证功能之外,扩展了第三方登录和特色服务模块,提升认证场景的完整性:

(1)第三方登录

第三方登录按钮采用统一的组件结构,通过 handleThirdPartyLogin 函数接收登录渠道参数,实现登录逻辑的复用:

  • 按钮布局统一(图标 + 文本),视觉风格一致;
  • 点击事件传递渠道名称(微信/QQ/Google/Apple),核心登录逻辑封装在统一函数中,便于后续接入真实的第三方登录 SDK。
(2)附加信息

特色服务和安全提示模块采用卡片式设计,与表单容器风格统一:

  • 特色服务模块采用两列网格布局,图标 + 文本的组合提升可读性;
  • 安全提示模块采用列表式布局,通过项目符号(?)区分不同的提示项,强化用户的安全意识。

将 React Native 认证应用迁移至鸿蒙平台,核心是基于 ArkTS + ArkUI 实现表单状态管理、表单组件、交互逻辑、样式系统的对等还原,以下是关键适配技术点:

1. 表单状态

RN 的 TypeScript 类型定义可无缝迁移至鸿蒙 ArkTS,仅需将 type 替换为 interface,核心字段完全复用:

// RN 类型定义
type FormState = {
  phone: string;
  email: string;
  password: string;
  confirmPassword: string;
  verificationCode: string;
};

// 鸿蒙 ArkTS 适配
interface FormState {
  phone: string;
  email: string;
  password: string;
  confirmPassword: string;
  verificationCode: string;
}

状态管理层面,RN 的 useState 对应鸿蒙的 @State 装饰器,核心状态迁移方案:

// RN 状态定义
const [formState, setFormState] = useState<FormState>({/* 初始值 */});
const [isLogin, setIsLogin] = useState<boolean>(true);
const [showPassword, setShowPassword] = useState<boolean>(false);
const [rememberMe, setRememberMe] = useState<boolean>(true);

// 鸿蒙 ArkTS 适配
@Entry
@Component
struct AuthApp {
  // 核心表单状态
  @State formState: FormState = {
    phone: '',
    email: '',
    password: '',
    confirmPassword: '',
    verificationCode: ''
  };
  @State isLogin: boolean = true;
  @State showPassword: boolean = false;
  @State rememberMe: boolean = true;
  
  // 输入变更处理函数(逻辑完全复用)
  handleInputChange(field: keyof FormState, value: string) {
    this.formState[field] = value;
  }
  
  // 表单提交函数(逻辑完全复用,仅调整弹窗 API)
  handleSubmit() {
    if (this.isLogin) {
      if (!this.formState.phone && !this.formState.email) {
        AlertDialog.show({
          title: '错误',
          message: '请输入手机号或邮箱',
          confirm: { text: '确定' }
        });
        return;
      }
      // 其他登录校验逻辑...
    } else {
      // 注册校验逻辑...
    }
  }
  
  // 其他交互函数(sendVerificationCode/handleThirdPartyLogin)完全复用...
}

适配亮点

  • 状态更新逻辑简化:ArkTS 支持直接修改 @State 装饰的对象属性(this.formState[field] = value),无需像 RN 那样使用扩展运算符复制整个对象;
  • 弹窗反馈适配:将 RN 的 Alert.alert 替换为鸿蒙 AlertDialog.show,参数结构基本一致,仅需调整配置格式;
  • 类型约束复用:keyof FormState 泛型约束在 ArkTS 中完全生效,保证输入字段的合法性。

2. 核心表单

ArkUI 提供了完善的表单组件体系,与 RN 表单组件高度对齐,核心组件映射关系及适配方案:

RN 组件/特性 鸿蒙 ArkUI 对应实现 适配关键说明
TextInput TextInput 输入框核心属性完全等效,secureTextEntrytype: InputType.Password
TouchableOpacity Button().stateEffect(true) 点击反馈通过 stateEffect 实现
View Column/Row/Stack 根据布局方向选择,Flex 布局属性完全兼容
Text Text 文本样式、对齐方式完全复用
StyleSheet 链式样式 + @Styles 样式封装与复用,语法更简洁
条件渲染 if/else 语句 替代 RN 的三元表达式,实现登录/注册表单切换
绝对定位 Stack + Position 实现密码显示/隐藏按钮的绝对定位

(1)密码输入框
// RN 密码输入框
<View style={styles.passwordInputContainer}>
  <TextInput
    style={[styles.input, styles.passwordInput]}
    placeholder="请输入密码"
    secureTextEntry={!showPassword}
    value={formState.password}
    onChangeText={(value) => handleInputChange('password', value)}
  />
  <TouchableOpacity 
    style={styles.passwordToggle}
    onPress={() => setShowPassword(!showPassword)}
  >
    <Text style={styles.passwordToggleText}>
      {showPassword ? '隐藏' : '显示'}
    </Text>
  </TouchableOpacity>
</View>

// 鸿蒙密码输入框适配
Stack() {
  TextInput({
    placeholder: '请输入密码',
    text: this.formState.password,
    type: this.showPassword ? InputType.Normal : InputType.Password
  })
    .width('100%')
    .paddingVertical(12)
    .paddingHorizontal(16)
    .fontSize(16)
    .backgroundColor('#f8fafc')
    .borderWidth(1)
    .borderColor('#e2e8f0')
    .borderRadius(10)
    .onChange((value) => {
      this.handleInputChange('password', value);
    });
  
  // 显示/隐藏按钮绝对定位
  Button(this.showPassword ? '隐藏' : '显示')
    .fontSize(12)
    .fontColor('#3b82f6')
    .backgroundColor(Color.Transparent)
    .padding(8)
    .position({ x: '85%', y: '50%' })
    .onClick(() => {
      this.showPassword = !this.showPassword;
    });
}
(2)验证码输入框
// RN 验证码输入框
<View style={styles.verificationContainer}>
  <TextInput
    style={[styles.input, styles.verificationInput]}
    placeholder="请输入验证码"
    value={formState.verificationCode}
    onChangeText={(value) => handleInputChange('verificationCode', value)}
  />
  <TouchableOpacity 
    style={styles.verificationButton}
    onPress={sendVerificationCode}
  >
    <Text style={styles.verificationButtonText}>获取验证码</Text>
  </TouchableOpacity>
</View>

// 鸿蒙验证码输入框适配
Row({ space: 10 }) {
  TextInput({
    placeholder: '请输入验证码',
    text: this.formState.verificationCode
  })
    .flex(1)
    .paddingVertical(12)
    .paddingHorizontal(16)
    .fontSize(16)
    .backgroundColor('#f8fafc')
    .borderWidth(1)
    .borderColor('#e2e8f0')
    .borderRadius(10)
    .onChange((value) => {
      this.handleInputChange('verificationCode', value);
    });
  
  Button('获取验证码')
    .backgroundColor('#3b82f6')
    .paddingVertical(12)
    .paddingHorizontal(16)
    .borderRadius(10)
    .minWidth(100)
    .fontSize(12)
    .fontColor('#ffffff')
    .fontWeight(FontWeight.Medium)
    .onClick(() => {
      this.sendVerificationCode();
    });
}
(3)自定义复选框
// RN 自定义复选框
<TouchableOpacity 
  style={styles.checkboxContainer}
  onPress={() => setRememberMe(!rememberMe)}
>
  <View style={[styles.checkbox, rememberMe && styles.checkboxChecked]}>
    {rememberMe && <Text style={styles.checkboxCheck}>?</Text>}
  </View>
  <Text style={styles.checkboxLabel}>记住我</Text>
</TouchableOpacity>

// 鸿蒙自定义复选框适配
Row({ alignItems: ItemAlign.Center }) {
  Button()
    .width(18)
    .height(18)
    .borderRadius(9)
    .borderWidth(1)
    .borderColor(this.rememberMe ? '#3b82f6' : '#cbd5e1')
    .backgroundColor(this.rememberMe ? '#3b82f6' : Color.Transparent)
    .onClick(() => {
      this.rememberMe = !this.rememberMe;
    })
    .stateEffect(false)
    .child(
      this.rememberMe ? Text('?')
        .fontSize(12)
        .fontWeight(FontWeight.Bold)
        .fontColor('#ffffff') : null
    );
  
  Text('记住我')
    .fontSize(14)
    .fontColor('#475569')
    .marginLeft(8);
}

3. 样式

RN 的 StyleSheet 样式在鸿蒙中通过链式样式 + @Styles 装饰器实现复用,核心适配规则:

// RN 样式定义
const styles = StyleSheet.create({
  formContainer: {
    backgroundColor: '#ffffff',
    borderRadius: 16,
    padding: 20,
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.05,
    shadowRadius: 4,
  },
  input: {
    borderWidth: 1,
    borderColor: '#e2e8f0',
    borderRadius: 10,
    paddingVertical: 12,
    paddingHorizontal: 16,
    fontSize: 16,
    backgroundColor: '#f8fafc',
  },
});

// 鸿蒙样式适配
@Entry
@Component
struct AuthApp {
  // 通用表单容器样式
  @Styles formContainerStyle() {
    .backgroundColor('#ffffff')
    .borderRadius(16)
    .padding(20)
    .shadow({ // 统一阴影配置,无需区分平台
      color: '#000',
      offsetX: 0,
      offsetY: 2,
      opacity: 0.05,
      radius: 4
    });
  }
  
  // 通用输入框样式
  @Styles inputStyle() {
    .borderWidth(1)
    .borderColor('#e2e8f0')
    .borderRadius(10)
    .paddingVertical(12)
    .paddingHorizontal(16)
    .fontSize(16)
    .backgroundColor('#f8fafc');
  }
  
  build() {
    Column() {
      // 表单容器使用通用样式
      Column()
        .formContainerStyle() {
          // 输入框使用通用样式
          TextInput()
            .inputStyle();
        }
    }
  }
}

适配亮点

  • 基础样式完全复用:颜色、间距、圆角、字体大小等属性直接迁移,仅调整语法格式;
  • 阴影效果统一:鸿蒙的 shadow 配置替代 RN 的 elevation/shadow 双配置,一次配置兼顾所有平台;
  • 文本样式适配:fontWeight: 'bold'fontWeight(FontWeight.Bold),语义完全一致;
  • 条件样式适配:通过三元表达式实现动态样式,如复选框的选中/未选中状态切换,逻辑与 RN 完全一致。

1. 核心

  • 表单状态优先复用:表单字段、状态更新逻辑完全复用,仅调整状态管理语法,保证两端表单逻辑一致;
  • 交互逻辑零修改:表单校验、密码显示/隐藏、验证码发送等核心交互逻辑,仅需调整 API 调用方式,业务逻辑无需重构;
  • 视觉体验统一:复用相同的色值、间距、圆角、字体,保证两端认证页面的视觉体验一致;
  • 原生能力增强:鸿蒙端可利用原生 API 增强认证功能,如通过 Preferences 存储“记住我”状态,通过系统 API 实现验证码自动填充。

2. 扩展

  • 持久化存储:RN 端使用 AsyncStorage,鸿蒙端使用 Preferences,实现“记住我”状态和用户凭证的持久化存储;
  • 验证码集成:接入鸿蒙短信验证码 SDK,替换模拟的验证码发送逻辑;
  • 第三方登录集成:接入鸿蒙的 OAuth 服务,实现微信/QQ/Google/Apple 等第三方登录的真实对接;
  • 密码强度校验:利用鸿蒙的正则表达式 API,实现密码强度的实时校验;
  • 生物识别登录:接入鸿蒙的指纹/人脸认证 API,增强登录安全性;
  • 多语言适配:基于鸿蒙的国际化能力,实现认证页面的多语言支持。

这款 React Native 认证应用的跨端适配实践,验证了 ArkTS 与 React 技术体系的高度兼容性。对于登录注册这类表单密集型场景,核心的状态管理、表单校验、UI 渲染均可实现 90% 以上的代码复用,仅需适配 UI 组件和原生 API 调用,是跨端开发的高效路径。


在移动应用开发中,认证系统是用户与应用交互的第一道门槛,其设计质量直接影响用户体验和应用安全性。本文将深入分析一个基于 React Native 实现的认证系统,探讨其架构设计、技术实现以及鸿蒙跨端适配策略。

状态管理

该认证系统采用了 React Hooks 中的 useState 进行轻量级状态管理,构建了清晰的状态模型:

const [formState, setFormState] = useState<FormState>({
  phone: '',
  email: '',
  password: '',
  confirmPassword: '',
  verificationCode: ''
});
const [isLogin, setIsLogin] = useState<boolean>(true);
const [showPassword, setShowPassword] = useState<boolean>(false);
const [rememberMe, setRememberMe] = useState<boolean>(true);

这种状态管理方式具有以下优势:

  • 类型安全:通过 TypeScript 接口 FormState 确保状态结构一致性
  • 模块化:将表单状态、UI 状态和用户偏好分离管理
  • 响应式:状态变更自动触发组件重渲染
  • 跨端兼容:React Hooks 在鸿蒙系统的 React Native 实现中通常都有良好支持

表单处理

表单处理是认证系统的核心,该实现采用了集中式的状态更新策略:

const handleInputChange = (field: keyof FormState, value: string) => {
  setFormState(prev => ({
    ...prev,
    [field]: value
  }));
};

这种方式通过函数式状态更新确保了状态的一致性,同时使用 TypeScript 的 keyof 操作符提供了类型安全的字段访问。

登录/注册模式

系统支持登录和注册模式的无缝切换:

const toggleAuthMode = () => {
  setIsLogin(!isLogin);
};

这种模式切换通过条件渲染实现不同的表单界面,避免了创建多个页面组件,提高了代码复用性。


基础架构

该实现采用了 React Native 核心组件库,确保了在鸿蒙系统上的基本兼容性:

  • SafeAreaView:适配刘海屏等异形屏
  • ScrollView:处理键盘弹出时的内容滚动
  • TextInput:提供文本输入功能
  • Alert:系统级弹窗提示

Base64 图标

系统使用 Base64 编码的图标库:

const ICONS_BASE64 = {
  login: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  // 其他图标...
};

这种处理方式在跨端开发中尤为重要:

  • 避免了不同平台对资源文件格式的兼容性问题
  • 减少了网络请求,提高了加载速度
  • 简化了构建流程,无需处理多平台资源文件

屏幕尺寸

系统通过 Dimensions API 获取屏幕尺寸:

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

这种方式确保了在不同屏幕尺寸的设备上都能获得一致的布局体验,为后续的响应式布局调整做准备。


系统实现了基本的表单验证:

const handleSubmit = () => {
  if (isLogin) {
    // 登录验证
    if (!formState.phone && !formState.email) {
      Alert.alert('错误', '请输入手机号或邮箱');
      return;
    }
    if (!formState.password) {
      Alert.alert('错误', '请输入密码');
      return;
    }
    // 登录成功
  } else {
    // 注册验证
    // ...验证逻辑
  }
};

这种验证方式确保了用户输入的有效性,同时通过 Alert 提供了清晰的错误反馈。

第三方登录

系统支持多种第三方登录方式:

const handleThirdPartyLogin = (provider: string) => {
  Alert.alert('第三方登录', `${provider} 登录成功!`);
};

这种设计为用户提供了更多登录选择,提高了用户体验的灵活性。


API 兼容性

在鸿蒙系统上使用 React Native 时,应注意以下 API 兼容性问题:

  1. TextInput API:鸿蒙系统的 TextInput 实现可能与 React Native 有所差异,建议测试确认输入行为
  2. Alert API:鸿蒙系统的 Alert 实现可能与 React Native 有所差异,建议测试确认弹窗行为
  3. 键盘处理:鸿蒙系统的键盘弹出/收起行为可能不同,需要测试确保表单滚动正常

  1. 类型定义

    // 更详细的表单状态类型
    interface FormState {
      phone: string;
      email: string;
      password: string;
      confirmPassword: string;
      verificationCode: string;
    }
    
    // 第三方登录提供商类型
    type ThirdPartyProvider = 'wechat' | 'qq' | 'google' | 'apple';
    
  2. 表单验证

    // 更健壮的表单验证
    const validateForm = (): boolean => {
      if (!formState.phone && !formState.email) {
        Alert.alert('错误', '请输入手机号或邮箱');
        return false;
      }
      
      if (!formState.password) {
        Alert.alert('错误', '请输入密码');
        return false;
      }
      
      if (!isLogin) {
        if (formState.password !== formState.confirmPassword) {
          Alert.alert('错误', '两次输入的密码不一致');
          return false;
        }
        
        if (!formState.verificationCode) {
          Alert.alert('错误', '请输入验证码');
          return false;
        }
      }
      
      return true;
    };
    
  3. 状态管理

    // 使用 useReducer 管理复杂状态
    const [state, dispatch] = useReducer(authReducer, initialState);
    
    // 操作函数
    const handleInputChange = (field: keyof FormState, value: string) => {
      dispatch({ type: 'UPDATE_FIELD', payload: { field, value } });
    };
    
  4. 错误处理

    // 添加网络错误处理
    const handleSubmit = async () => {
      if (!validateForm()) return;
      
      try {
        // 模拟 API 调用
        await new Promise(resolve => setTimeout(resolve, 1000));
        Alert.alert('成功', isLogin ? '登录成功!' : '注册成功!');
      } catch (error) {
        Alert.alert('错误', '网络请求失败,请稍后重试');
      }
    };
    
  5. 可访问性

    // 添加可访问性标签
    <TextInput
      accessible={true}
      accessibilityLabel="手机号输入"
      // 其他属性
    />
    

本认证系统实现了一个功能完整、用户友好的登录注册流程,通过合理的架构设计和代码组织,为用户提供了良好的首次使用体验。在跨端开发场景下,该实现充分考虑了 React Native 和鸿蒙系统的兼容性需求,为后续的功能扩展和性能优化预留了空间。


真实演示案例代码:





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

// Base64 图标库
const ICONS_BASE64 = {
  login: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  register: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  phone: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  email: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  wechat: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  qq: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  google: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  apple: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
};

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

// 登录/注册表单状态类型
type FormState = {
  phone: string;
  email: string;
  password: string;
  confirmPassword: string;
  verificationCode: string;
};

// 认证应用组件
const AuthApp: React.FC = () => {
  const [formState, setFormState] = useState<FormState>({
    phone: '',
    email: '',
    password: '',
    confirmPassword: '',
    verificationCode: ''
  });
  const [isLogin, setIsLogin] = useState<boolean>(true);
  const [showPassword, setShowPassword] = useState<boolean>(false);
  const [rememberMe, setRememberMe] = useState<boolean>(true);

  // 切换登录/注册模式
  const toggleAuthMode = () => {
    setIsLogin(!isLogin);
  };

  // 处理输入变化
  const handleInputChange = (field: keyof FormState, value: string) => {
    setFormState(prev => ({
      ...prev,
      [field]: value
    }));
  };

  // 发送验证码
  const sendVerificationCode = () => {
    if (!formState.phone && !formState.email) {
      Alert.alert('提示', '请输入手机号或邮箱');
      return;
    }
    
    Alert.alert('验证码', '验证码已发送到您的手机或邮箱');
  };

  // 提交表单
  const handleSubmit = () => {
    if (isLogin) {
      // 执行登录逻辑
      if (!formState.phone && !formState.email) {
        Alert.alert('错误', '请输入手机号或邮箱');
        return;
      }
      if (!formState.password) {
        Alert.alert('错误', '请输入密码');
        return;
      }
      Alert.alert('登录', '登录成功!');
    } else {
      // 执行注册逻辑
      if (!formState.phone && !formState.email) {
        Alert.alert('错误', '请输入手机号或邮箱');
        return;
      }
      if (!formState.password) {
        Alert.alert('错误', '请输入密码');
        return;
      }
      if (formState.password !== formState.confirmPassword) {
        Alert.alert('错误', '两次输入的密码不一致');
        return;
      }
      Alert.alert('注册', '注册成功!');
    }
  };

  // 第三方登录
  const handleThirdPartyLogin = (provider: string) => {
    Alert.alert('第三方登录', `${provider} 登录成功!`);
  };

  return (
    <SafeAreaView style={styles.container}>
      <ScrollView style={styles.content}>
        {/* 标题区域 */}
        <View style={styles.header}>
          <Text style={styles.title}>{isLogin ? '用户登录' : '用户注册'}</Text>
          <Text style={styles.subtitle}>
            {isLogin 
              ? '欢迎回来,请输入您的账号信息' 
              : '创建新账户,开启精彩体验'}
          </Text>
        </View>

        {/* 表单区域 */}
        <View style={styles.formContainer}>
          {/* 手机号输入 */}
          <View style={styles.inputGroup}>
            <Text style={styles.label}>手机号</Text>
            <TextInput
              style={styles.input}
              placeholder="请输入手机号"
              keyboardType="phone-pad"
              value={formState.phone}
              onChangeText={(value) => handleInputChange('phone', value)}
            />
          </View>

          {/* 邮箱输入 */}
          <View style={styles.inputGroup}>
            <Text style={styles.label}>邮箱</Text>
            <TextInput
              style={styles.input}
              placeholder="请输入邮箱地址"
              keyboardType="email-address"
              autoCapitalize="none"
              value={formState.email}
              onChangeText={(value) => handleInputChange('email', value)}
            />
          </View>

          {/* 密码输入 */}
          <View style={styles.inputGroup}>
            <Text style={styles.label}>密码</Text>
            <View style={styles.passwordInputContainer}>
              <TextInput
                style={[styles.input, styles.passwordInput]}
                placeholder="请输入密码"
                secureTextEntry={!showPassword}
                value={formState.password}
                onChangeText={(value) => handleInputChange('password', value)}
              />
              <TouchableOpacity 
                style={styles.passwordToggle}
                onPress={() => setShowPassword(!showPassword)}
              >
                <Text style={styles.passwordToggleText}>
                  {showPassword ? '隐藏' : '显示'}
                </Text>
              </TouchableOpacity>
            </View>
          </View>

          {!isLogin && (
            <>
              {/* 确认密码输入 */}
              <View style={styles.inputGroup}>
                <Text style={styles.label}>确认密码</Text>
                <TextInput
                  style={styles.input}
                  placeholder="请再次输入密码"
                  secureTextEntry
                  value={formState.confirmPassword}
                  onChangeText={(value) => handleInputChange('confirmPassword', value)}
                />
              </View>

              {/* 验证码输入 */}
              <View style={styles.inputGroup}>
                <Text style={styles.label}>验证码</Text>
                <View style={styles.verificationContainer}>
                  <TextInput
                    style={[styles.input, styles.verificationInput]}
                    placeholder="请输入验证码"
                    value={formState.verificationCode}
                    onChangeText={(value) => handleInputChange('verificationCode', value)}
                  />
                  <TouchableOpacity 
                    style={styles.verificationButton}
                    onPress={sendVerificationCode}
                  >
                    <Text style={styles.verificationButtonText}>获取验证码</Text>
                  </TouchableOpacity>
                </View>
              </View>
            </>
          )}

          {/* 记住我选项 */}
          {isLogin && (
            <View style={styles.optionRow}>
              <TouchableOpacity 
                style={styles.checkboxContainer}
                onPress={() => setRememberMe(!rememberMe)}
              >
                <View style={[styles.checkbox, rememberMe && styles.checkboxChecked]}>
                  {rememberMe && <Text style={styles.checkboxCheck}></Text>}
                </View>
                <Text style={styles.checkboxLabel}>记住我</Text>
              </TouchableOpacity>
              
              <TouchableOpacity>
                <Text style={styles.linkText}>忘记密码?</Text>
              </TouchableOpacity>
            </View>
          )}

          {/* 提交按钮 */}
          <TouchableOpacity 
            style={styles.submitButton}
            onPress={handleSubmit}
          >
            <Text style={styles.submitButtonText}>
              {isLogin ? '登录' : '注册'}
            </Text>
          </TouchableOpacity>

          {/* 切换模式 */}
          <View style={styles.switchContainer}>
            <Text style={styles.switchText}>
              {isLogin ? '还没有账户?' : '已有账户?'}
            </Text>
            <TouchableOpacity onPress={toggleAuthMode}>
              <Text style={styles.switchLink}>
                {isLogin ? '立即注册' : '立即登录'}
              </Text>
            </TouchableOpacity>
          </View>
        </View>

        {/* 第三方登录 */}
        <View style={styles.thirdPartyContainer}>
          <View style={styles.dividerContainer}>
            <View style={styles.divider} />
            <Text style={styles.dividerText}>其他登录方式</Text>
            <View style={styles.divider} />
          </View>

          <View style={styles.socialLoginContainer}>
            <TouchableOpacity 
              style={styles.socialButton}
              onPress={() => handleThirdPartyLogin('微信')}
            >
              <Text style={styles.socialIcon}>WeChat</Text>
              <Text style={styles.socialText}>微信</Text>
            </TouchableOpacity>

            <TouchableOpacity 
              style={styles.socialButton}
              onPress={() => handleThirdPartyLogin('QQ')}
            >
              <Text style={styles.socialIcon}>QQ</Text>
              <Text style={styles.socialText}>QQ</Text>
            </TouchableOpacity>

            <TouchableOpacity 
              style={styles.socialButton}
              onPress={() => handleThirdPartyLogin('Google')}
            >
              <Text style={styles.socialIcon}>G</Text>
              <Text style={styles.socialText}>Google</Text>
            </TouchableOpacity>

            <TouchableOpacity 
              style={styles.socialButton}
              onPress={() => handleThirdPartyLogin('Apple')}
            >
              <Text style={styles.socialIcon}>A</Text>
              <Text style={styles.socialText}>Apple</Text>
            </TouchableOpacity>
          </View>
        </View>

        {/* 特色服务 */}
        <View style={styles.servicesContainer}>
          <Text style={styles.servicesTitle}>特色服务</Text>
          <View style={styles.servicesGrid}>
            <View style={styles.serviceItem}>
              <Text style={styles.serviceIcon}>🔒</Text>
              <Text style={styles.serviceText}>安全可靠</Text>
            </View>
            <View style={styles.serviceItem}>
              <Text style={styles.serviceIcon}></Text>
              <Text style={styles.serviceText}>快速便捷</Text>
            </View>
            <View style={styles.serviceItem}>
              <Text style={styles.serviceIcon}>👥</Text>
              <Text style={styles.serviceText}>社交分享</Text>
            </View>
            <View style={styles.serviceItem}>
              <Text style={styles.serviceIcon}>🎁</Text>
              <Text style={styles.serviceText}>专属福利</Text>
            </View>
          </View>
        </View>

        {/* 安全提示 */}
        <View style={styles.securityNote}>
          <Text style={styles.securityTitle}>安全提示</Text>
          <Text style={styles.securityText}>• 请妥善保管您的账户信息</Text>
          <Text style={styles.securityText}>• 不要在公共网络环境下登录</Text>
          <Text style={styles.securityText}>• 定期更换密码以保障安全</Text>
        </View>
      </ScrollView>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f0f4f8',
  },
  content: {
    flex: 1,
    padding: 20,
  },
  header: {
    alignItems: 'center',
    marginBottom: 30,
    marginTop: 20,
  },
  title: {
    fontSize: 28,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 8,
  },
  subtitle: {
    fontSize: 14,
    color: '#64748b',
    textAlign: 'center',
    lineHeight: 20,
  },
  formContainer: {
    backgroundColor: '#ffffff',
    borderRadius: 16,
    padding: 20,
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.05,
    shadowRadius: 4,
  },
  inputGroup: {
    marginBottom: 20,
  },
  label: {
    fontSize: 14,
    color: '#475569',
    marginBottom: 8,
    fontWeight: '500',
  },
  input: {
    borderWidth: 1,
    borderColor: '#e2e8f0',
    borderRadius: 10,
    paddingVertical: 12,
    paddingHorizontal: 16,
    fontSize: 16,
    backgroundColor: '#f8fafc',
  },
  passwordInputContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  passwordInput: {
    flex: 1,
  },
  passwordToggle: {
    position: 'absolute',
    right: 16,
    padding: 8,
  },
  passwordToggleText: {
    fontSize: 12,
    color: '#3b82f6',
  },
  verificationContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  verificationInput: {
    flex: 1,
    marginRight: 10,
  },
  verificationButton: {
    backgroundColor: '#3b82f6',
    paddingVertical: 12,
    paddingHorizontal: 16,
    borderRadius: 10,
    minWidth: 100,
  },
  verificationButtonText: {
    color: '#ffffff',
    fontSize: 12,
    fontWeight: '500',
    textAlign: 'center',
  },
  optionRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: 20,
  },
  checkboxContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  checkbox: {
    width: 18,
    height: 18,
    borderRadius: 9,
    borderWidth: 1,
    borderColor: '#cbd5e1',
    alignItems: 'center',
    justifyContent: 'center',
    marginRight: 8,
  },
  checkboxChecked: {
    backgroundColor: '#3b82f6',
    borderColor: '#3b82f6',
  },
  checkboxCheck: {
    color: '#ffffff',
    fontSize: 12,
    fontWeight: 'bold',
  },
  checkboxLabel: {
    fontSize: 14,
    color: '#475569',
  },
  linkText: {
    fontSize: 14,
    color: '#3b82f6',
  },
  submitButton: {
    backgroundColor: '#3b82f6',
    paddingVertical: 16,
    borderRadius: 10,
    alignItems: 'center',
    marginBottom: 16,
  },
  submitButtonText: {
    color: '#ffffff',
    fontSize: 16,
    fontWeight: '600',
  },
  switchContainer: {
    flexDirection: 'row',
    justifyContent: 'center',
  },
  switchText: {
    fontSize: 14,
    color: '#64748b',
  },
  switchLink: {
    fontSize: 14,
    color: '#3b82f6',
    fontWeight: '500',
    marginLeft: 4,
  },
  thirdPartyContainer: {
    marginTop: 20,
  },
  dividerContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    marginVertical: 20,
  },
  divider: {
    flex: 1,
    height: 1,
    backgroundColor: '#e2e8f0',
  },
  dividerText: {
    paddingHorizontal: 16,
    color: '#94a3b8',
    fontSize: 14,
  },
  socialLoginContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    marginBottom: 20,
  },
  socialButton: {
    alignItems: 'center',
    width: '22%',
    paddingVertical: 12,
    borderWidth: 1,
    borderColor: '#e2e8f0',
    borderRadius: 10,
    backgroundColor: '#ffffff',
  },
  socialIcon: {
    fontSize: 18,
    marginBottom: 4,
  },
  socialText: {
    fontSize: 12,
    color: '#475569',
  },
  servicesContainer: {
    backgroundColor: '#ffffff',
    borderRadius: 16,
    padding: 20,
    marginTop: 10,
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.05,
    shadowRadius: 4,
  },
  servicesTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 16,
  },
  servicesGrid: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    flexWrap: 'wrap',
  },
  serviceItem: {
    width: '48%',
    alignItems: 'center',
    marginBottom: 16,
  },
  serviceIcon: {
    fontSize: 24,
    marginBottom: 8,
  },
  serviceText: {
    fontSize: 14,
    color: '#475569',
    textAlign: 'center',
  },
  securityNote: {
    backgroundColor: '#ffffff',
    borderRadius: 16,
    padding: 20,
    marginTop: 10,
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.05,
    shadowRadius: 4,
  },
  securityTitle: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#1e293b',
    marginBottom: 12,
  },
  securityText: {
    fontSize: 14,
    color: '#64748b',
    lineHeight: 22,
    marginBottom: 8,
  },
});

export default AuthApp;


请添加图片描述


打包

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

在这里插入图片描述

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

在这里插入图片描述

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

请添加图片描述

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

Logo

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

更多推荐