一、核心知识点:登录页记住密码+深色模式适配 核心用法

1、核心内置 API 介绍
本次实现用到的所有能力均为 RN 原生自带,无需任何额外引入,完美适配鸿蒙端的“记住密码逻辑+深色模式切换”,无兼容修改,零基础易理解复用:

核心 API/Hook 作用说明 核心特性
useState() 管理登录页核心状态(账号、密码、记住密码勾选状态) 响应式更新,输入/勾选操作实时同步 UI,鸿蒙端无延迟
useEffect() 处理页面初始化(读取存储数据)、主题切换监听 组件挂载/更新时自动执行,鸿蒙端性能友好,无内存泄漏风险
useColorScheme() 获取当前系统配色方案(light/dark),实现深色模式适配 响应式监听,鸿蒙系统切换主题时自动触发组件重渲染,样式无缝切换
TextInput/Switch/TouchableOpacity 登录页基础交互组件(输入框、记住密码开关、登录按钮) RN 原生组件,鸿蒙端完美兼容,交互逻辑与系统行为一致
内存临时存储(核心包替代方案) 替代独立存储包,实现登录信息运行期临时保存(核心包无AsyncStorage时用) 组件内全局变量,运行期有效,适配鸿蒙 RN 核心包限制

2、鸿蒙端登录页“记住密码+深色模式”实现原则
基于 RN 原生能力实现鸿蒙端登录页的双需求,核心遵循「配色统一、状态分离、逻辑闭环、响应式适配」四大原则,是企业级鸿蒙 RN 项目的标准开发规范,零基础可直接套用:

  • 抽离全局主题配色:将浅色/深色模式的登录页配色(背景、输入框、按钮、文字色)抽离为常量对象,集中管理,一处修改全局生效;
  • 状态与存储分离:登录信息(账号、密码)的状态管理与存储逻辑解耦,状态用useState响应式绑定,存储用独立工具类封装;
  • 动态样式绑定:通过useColorScheme获取当前主题,将主题配色绑定到组件style,实现深浅模式样式自动切换;
  • 响应式逻辑闭环:记住密码的“存储/回显”与主题切换的“样式更新”联动,系统操作后自动触发 UI 同步,无手动刷新操作。

3、鸿蒙端登录页官方设计规范
遵循鸿蒙系统的深浅模式设计规范开发登录页,避免“样式违和、交互割裂”问题,完美贴合鸿蒙系统视觉体验,核心规范如下:

  • 浅色模式(light):页面背景用浅灰白(#f7f8fa),输入框背景为白色(#ffffff),文字色为深灰(#333333),登录按钮用鸿蒙主题蓝(#007DFF),边框色为浅灰(#e5e5e5);
  • 深色模式(dark):页面背景用深黑(#181818),输入框背景为深灰(#242424),文字色为浅灰(#E5E5E5),登录按钮保持主题蓝不变,边框色为深灰(#333333);
  • 交互规范:记住密码开关的“勾选态”颜色与主题蓝一致,输入框清空按钮在深浅模式下自动匹配文字色,保证交互识别性。

二、实战:基础极简版 - 记住密码+自动跟随鸿蒙深色模式

import React, { useState, useEffect } from 'react';
import { View, Text, TextInput, Switch, TouchableOpacity, Alert, StyleSheet, SafeAreaView, useColorScheme } from 'react-native';

// 浅色模式配色
const LIGHT_THEME = {
  pageBg: '#f7f8fa',       // 页面背景
  cardBg: '#ffffff',       // 登录卡片背景
  inputBg: '#ffffff',      // 输入框背景
  textMain: '#333333',     // 主文字色
  textSub: '#666666',      // 次要文字色
  borderColor: '#e5e5e5',  // 边框色
  primaryColor: '#007DFF', // 鸿蒙主题蓝(固定)
  switchTrack: '#e5e5e5',  // 开关未勾选轨道色
};
// 深色模式配色
const DARK_THEME = {
  pageBg: '#181818',       // 页面背景(鸿蒙标准深色)
  cardBg: '#242424',       // 登录卡片背景
  inputBg: '#242424',      // 输入框背景
  textMain: '#E5E5E5',     // 主文字色
  textSub: '#999999',      // 次要文字色
  borderColor: '#333333',  // 边框色
  primaryColor: '#007DFF', // 鸿蒙主题蓝(固定)
  switchTrack: '#333333',  // 开关未勾选轨道色
};

const loginTempStorage = {
  account: '',
  password: ''
};
const TempStorageUtil = {
  save: (account: string, password: string) => {
    loginTempStorage.account = account;
    loginTempStorage.password = password;
  },
  get: () => ({ ...loginTempStorage }),
  clear: () => {
    loginTempStorage.account = '';
    loginTempStorage.password = '';
  }
};

const LoginPageWithDarkMode = () => {
  // 登录页状态
  const [account, setAccount] = useState<string>('');
  const [password, setPassword] = useState<string>('');
  const [isRememberPwd, setIsRememberPwd] = useState<boolean>(false);
  // 获取当前主题模式
  const colorScheme = useColorScheme();
  const theme = colorScheme === 'dark' ? DARK_THEME : LIGHT_THEME;

  // 页面初始化:读取存储回显账号密码
  useEffect(() => {
    const { account: savedAcc, password: savedPwd } = TempStorageUtil.get();
    if (savedAcc && savedPwd) {
      setAccount(savedAcc);
      setPassword(savedPwd);
      setIsRememberPwd(true);
    }
  }, []);

  // 登录按钮逻辑
  const handleLogin = () => {
    const trimAcc = account.trim();
    const trimPwd = password.trim();

    // 非空校验
    if (!trimAcc) {
      Alert.alert('提示', '请输入账号');
      return;
    }
    if (!trimPwd) {
      Alert.alert('提示', '请输入密码');
      return;
    }

    // 记住密码逻辑:勾选则保存,否则清空
    isRememberPwd ? TempStorageUtil.save(trimAcc, trimPwd) : TempStorageUtil.clear();

    Alert.alert('登录成功', `账号:${trimAcc}\n当前模式:${colorScheme === 'dark' ? '深色' : '浅色'}`);
  };

  return (
    <SafeAreaView style={[styles.page, { backgroundColor: theme.pageBg }]}>
      <View style={[styles.loginCard, { backgroundColor: theme.cardBg, borderColor: theme.borderColor }]}>
        <Text style={[styles.title, { color: theme.textMain }]}>用户登录</Text>

        {/* 账号输入框 */}
        <TextInput
          style={[styles.input, { backgroundColor: theme.inputBg, borderColor: theme.borderColor, color: theme.textMain }]}
          placeholder="请输入账号/手机号"
          placeholderTextColor={theme.textSub}
          value={account}
          onChangeText={setAccount}
          clearButtonMode="while-editing"
        />

        {/* 密码输入框 */}
        <TextInput
          style={[styles.input, { backgroundColor: theme.inputBg, borderColor: theme.borderColor, color: theme.textMain }]}
          placeholder="请输入密码"
          placeholderTextColor={theme.textSub}
          value={password}
          onChangeText={setPassword}
          secureTextEntry
          clearButtonMode="while-editing"
        />

        {/* 记住密码开关 */}
        <View style={styles.rememberBox}>
          <Switch
            value={isRememberPwd}
            onValueChange={setIsRememberPwd}
            trackColor={{ false: theme.switchTrack, true: theme.primaryColor }}
            thumbColor="#ffffff"
          />
          <Text style={[styles.rememberText, { color: theme.textSub }]}>记住密码</Text>
        </View>

        {/* 登录按钮 */}
        <TouchableOpacity style={[styles.loginBtn, { backgroundColor: theme.primaryColor }]} onPress={handleLogin}>
          <Text style={styles.loginBtnText}>立即登录</Text>
        </TouchableOpacity>
      </View>
    </SafeAreaView>
  );
};

// 基础固定样式
const styles = StyleSheet.create({
  page: {
    flex: 1,
    paddingHorizontal: 24,
    justifyContent: 'center',
  },
  loginCard: {
    padding: 22,
    borderRadius: 12,
    borderWidth: 1,
    shadowOpacity: 0.06,
    shadowRadius: 6,
    elevation: 2,
  },
  title: {
    fontSize: 22,
    fontWeight: 'bold',
    textAlign: 'center',
    marginBottom: 30,
  },
  input: {
    height: 48,
    borderWidth: 1,
    borderRadius: 8,
    paddingHorizontal: 16,
    fontSize: 16,
    marginBottom: 18,
  },
  rememberBox: {
    flexDirection: 'row',
    alignItems: 'center',
    marginBottom: 26,
  },
  rememberText: {
    fontSize: 14,
    marginLeft: 8,
  },
  loginBtn: {
    height: 50,
    borderRadius: 8,
    justifyContent: 'center',
    alignItems: 'center',
  },
  loginBtnText: {
    color: '#ffffff',
    fontSize: 16,
    fontWeight: '500',
  },
});

export default LoginPageWithDarkMode;

在这里插入图片描述

三、鸿蒙端登录页“记住密码+深色模式”避坑指南

以下是鸿蒙 RN 开发中该功能的高频踩坑点,按出现频率排序,解决方案均为鸿蒙端专属最优解,真机实测验证通过:

问题现象 问题原因 鸿蒙端最优解决方案
主题切换后输入框文字看不清 输入框文字色与背景色对比度不足,未遵循鸿蒙配色规范 严格绑定主题的textMain/inputBg,确保深浅模式下对比度≥4.5:1
记住密码数据重启后丢失 用了内存临时存储,未引入独立存储包 生产环境引入@react-native-async-storage/async-storage,鸿蒙 RN4Harmony 兼容
主题切换时页面样式闪烁 主题配色计算写在渲染逻辑中,未抽离常量 将主题配色抽离为全局常量,渲染时直接匹配,避免动态计算
开关组件在深色模式下无辨识度 开关轨道色未绑定主题,浅色轨道在深色背景下不明显 开关trackColor绑定主题的switchTrack,勾选态用鸿蒙主题蓝
输入框清空按钮颜色不匹配 清空按钮颜色未跟随主题,硬编码为固定色 输入框clearButtonMode自动适配文字色,确保与textColor一致
组件卸载后存储逻辑仍执行 useEffect未清理异步操作,导致内存泄漏 存储操作包裹在useEffect中,组件卸载时用返回函数终止未完成的操作

四、扩展用法:登录页“记住密码+深色模式”高频进阶技巧

基于本次基础实现,结合 RN 原生能力,可轻松实现鸿蒙端高频进阶需求,全部纯内置 API 实现:

  • 扩展 1:全局主题+存储 Provider 封装将主题配色、存储工具封装到Context.Provider中,根组件包裹后,所有子组件通过useContext获取主题/存储方法,无需层层传参,企业级项目标准方案。
  • 扩展 2:登录组件抽离为 ThemedLogin
    将登录页的输入框、按钮抽离为ThemedInputThemedButton自定义组件,内部自动绑定主题配色,业务页直接调用,避免重复编写样式绑定逻辑。
  • 扩展 3:自动登录+主题同步
    useEffect中读取存储后,若“记住密码+自动登录”均勾选,直接调用handleLogin,同时同步主题样式,实现“启动即登录+主题适配”。
  • 扩展 4:图片资源的深浅模式适配 登录页的 Logo 等资源,通过source={colorScheme === 'dark' ? darkLogo : lightLogo}动态加载,实现图片与主题的视觉统一。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

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

更多推荐