【HarmonyOS】DAY13:Flutter电商实战:从零开发注册页面(含密码验证、确认密码完整实现)

Flutter电商实战:从零开发注册页面(含密码验证、确认密码完整实现)


🌸你好呀!我是 lbb小魔仙
🌟 感谢陪伴~ 小白博主在线求友
🌿 跟着小白学Linux/Java/Python
📖 专栏汇总:
《Linux》专栏 | 《Java》专栏 | 《Python》专栏

前言

在电商应用中,注册页面是用户获取账号的第一步。一个设计简洁、体验流畅的注册页面能够有效提升用户注册转化率。本文将带你从零开始实现一个完整的Flutter注册页面,包含密码验证、确认密码、验证码倒计时等完整功能。

参考文章【开源鸿蒙跨平台开发先锋训练营】DAY15~DAY19为开源鸿蒙跨平台应用全面集成添加核心场景-注册页面

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

一、项目背景

本文基于一个Flutter跨平台电商项目,是登录功能的延伸,技术栈如下:

  • Flutter版本:3.x
  • 前置功能:登录页面(已完成)
  • 开发目标:实现完整的用户注册功能

二、功能需求分析

2.1 核心功能

功能模块 说明
手机号输入 支持格式验证,限制11位
验证码输入 6位数字验证码,60秒倒计时
密码输入 6-20位,必须包含字母和数字,支持显示/隐藏
确认密码 与密码一致验证
注册按钮 防重复点击,加载状态显示
协议勾选 必须勾选才能注册
已有账号 跳转到登录页面

2.2 开发流程

复制代码
需求分析 → 密码验证规则设计 → API接口封装 → 注册页面UI → 登录页面集成 → 测试

三、密码验证规则设计

3.1 密码强度要求

dart 复制代码
// 验证密码格式
bool _isValidPassword(String password) {
  // 密码长度6-20位,包含字母和数字
  return RegExp(r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,20}$')
      .hasMatch(password);
}

密码规则说明

  • 长度:6-20位
  • 必须包含:至少一个字母 + 至少一个数字
  • 不允许:特殊字符
密码示例 结果 原因
abc123 ✅ 通过 6位,含字母和数字
abcd1234 ✅ 通过 8位,含字母和数字
123456 ❌ 不通过 缺少字母
abcdef ❌ 不通过 缺少数字
abc ❌ 不通过 少于6位

四、API接口封装

4.1 注册相关接口

文件路径lib/api/register.dart

dart 复制代码
import 'package:harmonyos_day_four/utils/DioRequest.dart';

/// 获取注册验证码
Future<void> getRegisterCodeAPI(String phone) async {
  // 实际项目中调用真实API
  // await dioRequest.post('/auth/register/send-code', data: {'phone': phone});

  // 模拟请求延迟
  await Future.delayed(const Duration(milliseconds: 500));
}

/// 注册
/// phone: 手机号
/// code: 验证码
/// password: 密码
Future<void> registerAPI(String phone, String code, String password) async {
  // 实际项目中调用真实API
  // await dioRequest.post('/auth/register', data: {
  //   'phone': phone,
  //   'code': code,
  //   'password': password,
  // });

  // 模拟请求延迟
  await Future.delayed(const Duration(seconds: 1));
}

五、注册页面UI实现

5.1 页面结构

文件路径lib/pages/register/index.dart

页面布局结构:

复制代码
Scaffold
├── SafeArea
│   └── SingleChildScrollView
│       ├── 返回按钮
│       ├── Logo和标题
│       ├── 手机号输入框
│       ├── 验证码输入框(含倒计时按钮)
│       ├── 密码输入框(含显示/隐藏)
│       ├── 确认密码输入框(含显示/隐藏)
│       ├── 注册按钮
│       ├── 协议勾选
│       └── 已有账号跳转登录

5.2 状态管理

dart 复制代码
class _RegisterPageState extends State<RegisterPage> {
  final TextEditingController _phoneController = TextEditingController();
  final TextEditingController _codeController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  final TextEditingController _confirmPasswordController = TextEditingController();

  bool _agreeToTerms = false;         // 是否同意协议
  bool _isRegistering = false;        // 是否正在注册
  int _countdown = 0;                 // 验证码倒计时秒数
  bool _showPassword = false;         // 是否显示密码
  bool _showConfirmPassword = false;  // 是否显示确认密码

  final Color _primaryColor = const Color(0xFFFF6B00);
  // ...
}

5.3 返回按钮

dart 复制代码
Widget _buildBackButton() {
  return GestureDetector(
    onTap: () => Navigator.pop(context),
    child: Container(
      width: 40,
      height: 40,
      decoration: BoxDecoration(
        color: Colors.grey[100],
        shape: BoxShape.circle,
      ),
      child: const Icon(Icons.arrow_back, size: 20),
    ),
  );
}

5.4 密码输入框(含显示/隐藏)

dart 复制代码
Widget _buildPasswordInput() {
  return Container(
    decoration: BoxDecoration(
      color: Colors.grey[100],
      borderRadius: BorderRadius.circular(12),
    ),
    child: TextField(
      controller: _passwordController,
      obscureText: !_showPassword,  // 控制密码显示/隐藏
      decoration: InputDecoration(
        hintText: '请输入密码(6-20位,含字母和数字)',
        prefixIcon: const Icon(Icons.lock_outline),
        suffixIcon: GestureDetector(
          onTap: () {
            setState(() {
              _showPassword = !_showPassword;  // 切换显示状态
            });
          },
          child: Icon(
            _showPassword
                ? Icons.visibility_outlined    // 睁眼图标
                : Icons.visibility_off_outlined, // 闭眼图标
            color: Colors.grey[400],
          ),
        ),
        border: InputBorder.none,
        contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
      ),
    ),
  );
}

实现要点

  • 使用 obscureText 控制密码显示/隐藏
  • 使用 suffixIcon 添加眼睛图标
  • 点击图标切换 _showPassword 状态

5.5 确认密码输入框

dart 复制代码
Widget _buildConfirmPasswordInput() {
  return Container(
    decoration: BoxDecoration(
      color: Colors.grey[100],
      borderRadius: BorderRadius.circular(12),
    ),
    child: TextField(
      controller: _confirmPasswordController,
      obscureText: !_showConfirmPassword,
      decoration: InputDecoration(
        hintText: '请确认密码',
        prefixIcon: const Icon(Icons.lock_outline),
        suffixIcon: GestureDetector(
          onTap: () {
            setState(() {
              _showConfirmPassword = !_showConfirmPassword;
            });
          },
          child: Icon(
            _showConfirmPassword
                ? Icons.visibility_outlined
                : Icons.visibility_off_outlined,
            color: Colors.grey[400],
          ),
        ),
        border: InputBorder.none,
        contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
      ),
    ),
  );
}

5.6 注册验证逻辑

dart 复制代码
Future<void> _register() async {
  // 1. 验证手机号
  if (!_isValidPhone(_phoneController.text)) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('请输入正确的手机号')),
    );
    return;
  }

  // 2. 验证验证码
  if (_codeController.text.isEmpty) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('请输入验证码')),
    );
    return;
  }

  // 3. 验证密码
  if (_passwordController.text.isEmpty) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('请输入密码')),
    );
    return;
  }

  if (!_isValidPassword(_passwordController.text)) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('密码长度6-20位,必须包含字母和数字')),
    );
    return;
  }

  // 4. 验证确认密码
  if (_confirmPasswordController.text != _passwordController.text) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('两次密码输入不一致')),
    );
    return;
  }

  // 5. 验证协议
  if (!_agreeToTerms) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('请先同意用户协议和隐私政策')),
    );
    return;
  }

  // 6. 执行注册
  setState(() {
    _isRegistering = true;
  });

  try {
    await registerAPI(
      _phoneController.text,
      _codeController.text,
      _passwordController.text,
    );

    if (!mounted) return;

    // 注册成功,返回登录页面
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('注册成功,请登录')),
    );
    Navigator.pop(context);
  } catch (e) {
    if (!mounted) return;
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('注册失败: $e')),
    );
  } finally {
    if (mounted) {
      setState(() {
        _isRegistering = false;
      });
    }
  }
}

5.7 已有账号跳转

dart 复制代码
Widget _buildLoginLink() {
  return Row(
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
      Text(
        '已有账号?',
        style: TextStyle(fontSize: 14, color: Colors.grey[600]),
      ),
      GestureDetector(
        onTap: _goToLogin,  // 跳转到登录页面
        child: const Text(
          '立即登录',
          style: TextStyle(
            fontSize: 14,
            color: Color(0xFFFF6B00),
            fontWeight: FontWeight.w600,
          ),
        ),
      ),
    ],
  );
}

// 跳转到登录页面
void _goToLogin() {
  Navigator.pop(context);  // 返回登录页面
}

六、登录页面集成

6.1 添加注册入口

文件路径lib/pages/login/index.dart

dart 复制代码
// 添加导入
import 'package:harmonyos_day_four/pages/register/index.dart';

// 添加跳转方法
void _goToRegister() {
  Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => const RegisterPage()),
  );
}

// 修改欢迎文字
Row(
  children: [
    Text('还没有账号?', style: TextStyle(color: Colors.grey[600])),
    GestureDetector(
      onTap: _goToRegister,  // 点击跳转注册
      child: const Text(
        '去注册',
        style: TextStyle(
          color: Color(0xFFFF6B00),
          fontWeight: FontWeight.w600,
        ),
      ),
    ),
  ],
)

七、遇到的问题及解决方法

问题1:密码明文显示不够安全

问题描述

密码输入框默认明文显示,用户输入时容易被他人看到。

解决方法

dart 复制代码
TextField(
  obscureText: !_showPassword,  // 控制密码显示/隐藏
  decoration: InputDecoration(
    suffixIcon: GestureDetector(
      onTap: () {
        setState(() {
          _showPassword = !_showPassword;  // 切换状态
        });
      },
      child: Icon(
        _showPassword
            ? Icons.visibility_outlined    // 显示时:睁眼
            : Icons.visibility_off_outlined, // 隐藏时:闭眼
      ),
    ),
  ),
)

问题2:用户可能输错密码

问题描述

用户在输入密码时可能打错,导致无法登录。

解决方法

添加确认密码输入框,验证两次密码是否一致:

dart 复制代码
// 验证确认密码
if (_confirmPasswordController.text != _passwordController.text) {
  ScaffoldMessenger.of(context).showSnackBar(
    const SnackBar(content: Text('两次密码输入不一致')),
  );
  return;
}

问题3:密码提示不够清晰

问题描述

用户不知道密码格式要求,导致多次输入错误。

解决方法

在输入框的 hintText 中明确提示密码要求:

dart 复制代码
TextField(
  decoration: InputDecoration(
    hintText: '请输入密码(6-20位,含字母和数字)',
  ),
)

问题4:注册成功后直接进入应用

问题描述

用户注册成功后应该先登录,而不是直接进入应用。

解决方法

注册成功后返回登录页面:

dart 复制代码
// 注册成功
ScaffoldMessenger.of(context).showSnackBar(
  const SnackBar(content: Text('注册成功,请登录')),
);
Navigator.pop(context);  // 返回登录页面

问题5:注册页面没有返回按钮

问题描述

用户进入注册页面后无法返回登录页面。

解决方法

在注册页面顶部添加返回按钮:

dart 复制代码
Widget _buildBackButton() {
  return GestureDetector(
    onTap: () => Navigator.pop(context),  // 返回上一页
    child: Container(
      width: 40,
      height: 40,
      decoration: BoxDecoration(
        color: Colors.grey[100],
        shape: BoxShape.circle,
      ),
      child: const Icon(Icons.arrow_back, size: 20),
    ),
  );
}

八、页面配色方案

用途 颜色值 说明
主题色 #FF6B00 橙色,用于按钮、高亮
输入框背景 #F5F5F5 浅灰色
次要文本 #6B7280 中灰色
链接文字 #FF6B00 橙色,用于"去注册"、"立即登录"

九、项目结构

复制代码
lib/
├── api/
│   └── register.dart            # 注册API接口
├── pages/
│   ├── register/
│   │   └── index.dart            # 注册页面(新建)
│   └── login/
│       └── index.dart            # 登录页面(已修改)
└── viewmodels/
    └── user.dart                 # 用户数据模型

十、完整注册流程

复制代码
1. 用户在登录页面点击"去注册"
   ↓
2. 跳转到注册页面
   ↓
3. 输入手机号(格式验证)
   ↓
4. 点击"获取验证码"(60秒倒计时)
   ↓
5. 输入验证码
   ↓
6. 输入密码(6-20位,含字母和数字)
   ↓
7. 输入确认密码(与密码一致)
   ↓
8. 勾选协议
   ↓
9. 点击"注册"按钮
   ↓
10. 注册成功,返回登录页面
    ↓
11. 用户可以使用新账号登录

十一、与登录页面的对比

功能 登录页面 注册页面
手机号输入
验证码输入
密码输入
确认密码
协议勾选
第三方登录
已有账号入口 去注册 立即登录

十二、后续优化建议

优化项 说明
密码强度指示器 实时显示密码强度(弱/中/强)
手机号已注册检测 注册前检查手机号是否已注册
验证码自动填充 读取短信验证码自动填充
注册成功自动登录 注册成功后自动登录,无需手动登录
手机号一键登录 使用运营商一键登录功能
邀请码功能 添加邀请码输入框

十三、总结

本文实现了一个完整的Flutter电商注册页面,包含以下核心功能:

  1. 手机号验证 - 使用正则表达式验证手机号格式
  2. 密码强度验证 - 6-20位,必须包含字母和数字
  3. 确认密码验证 - 确保两次密码输入一致
  4. 密码显示/隐藏 - 保护用户隐私
  5. 验证码倒计时 - 60秒倒计时,防止重复获取
  6. 页面跳转 - 登录页面与注册页面互相跳转

关键点总结

  • 密码验证使用正则表达式 ^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,20}$
  • 使用 obscureText 控制密码显示/隐藏
  • 注册成功后返回登录页面,让用户完成登录
  • 在输入框提示中明确密码格式要求

十四、参考资料


如果本文对你有帮助,欢迎点赞、收藏、评论!
📕个人领域 :Linux/C++/java/AI

🚀 个人主页有点流鼻涕 · CSDN

💬 座右铭 : "向光而行,沐光而生。"

相关推荐
摘星编程2 小时前
React Native鸿蒙版:TextHTML内容渲染
react native·华为·harmonyos
晚霞的不甘2 小时前
Flutter for OpenHarmony 豪华抽奖应用:从粒子背景到彩带动画的全栈实现
前端·学习·flutter·microsoft·前端框架
铅笔侠_小龙虾2 小时前
浅谈 Vue & React & Flutter 框架
vue.js·flutter·react.js
日光倾2 小时前
【Vue.js 入门笔记】 状态管理器Vuex
vue.js·笔记·flutter
2501_921930834 小时前
基础入门 React Native 鸿蒙跨平台开发:react-native-button三方库适配
react native·react.js·harmonyos
一起养小猫12 小时前
Flutter for OpenHarmony 进阶:体育计分系统与数据持久化深度解析
flutter·harmonyos
ujainu13 小时前
Flutter + OpenHarmony 游戏开发进阶:主菜单架构与历史最高分持久化
flutter·游戏·架构·openharmony
铅笔侠_小龙虾14 小时前
Flutter Demo
开发语言·javascript·flutter
2501_9445255414 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 账户详情页面
android·java·开发语言·前端·javascript·flutter