【慧游鲁博】【6】小程序端·登录注册·功能完善

本次更新

小程序完整实现登录注册功能,且与后端完成接口对接,包括:

  1. 双模式表单的设计与实现
  2. 全面的前端验证机制
  3. 网络请求的封装与拦截器设计
  4. 用户状态的管理与持久化
  5. 完善的错误处理机制
  6. 用户体验的优化措施

在这里插入图片描述

关键代码解析

主要涉及到以下三个代码文件

在这里插入图片描述

一、整体架构分析

用户操作
API调用
返回数据
更新状态
同步数据
持久化
前端界面层
网络请求层
后端服务
状态管理层
本地存储

技术栈关联性:

层级主要技术关联组件
界面层Vue3 + Uni-applogin.vue模板/样式
网络层Uni.request + 拦截器http.ts封装
状态层Pinia + 持久化插件member.ts store定义
桥梁组合式API各层间数据传递
架构组件详解
1. 前端界面层 (UI Layer)
Login.vue
双模式表单
登录表单
注册表单
实时验证
状态切换
装饰元素
  • 核心文件login.vue
  • 功能模块
    • 响应式双模式表单(登录/注册一键切换)
    • 基于正则表达式的实时输入验证
    • 中国风UI设计(渐变线条/传统配色)
    • 加载状态管理(按钮禁用/loading动画)
2. 网络请求层 (Network Layer)
http.ts
请求拦截器
自动补全URL
超时设置
Token注入
响应处理器
状态码过滤
错误统一处理
方法封装
GET/POST/PUT/DELETE
  • 核心机制
    • BaseURL自动补全:非http开头的请求自动拼接http://localhost:8080
    • 智能Token管理:从Pinia store自动获取并注入Authorization头
    • 双拦截器设计:同时拦截requestuploadFile请求
3. 状态管理层 (State Management)
member.ts
Pinia Store
响应式状态
profile对象
操作方法
setProfile
clearProfile
持久化
uni-app存储
  • 数据流

    登录成功 → 更新Pinia状态 → 自动持久化到Storage → 下次启动自动恢复
    
4. 完整数据流示例
界面层 网络层 后端 状态管理 Storage 提交登录表单(username/password) POST /user/login 返回token setProfile(token) 更新界面状态 持久化token 界面层 网络层 后端 状态管理 Storage

二、前端界面实现

1. 登录/注册表单组件

在这里插入图片描述

login.vue文件中,我们实现了一个双模式表单,可以在登录和注册状态间切换:

<view v-if="!isRegister" class="form-box">
  <!-- 登录表单内容 -->
</view>

<view v-else class="form-box">
  <!-- 注册表单内容 -->
</view>

登录表单包含:

  • 用户名输入框
  • 密码输入框
  • 登录按钮
  • 切换到注册的链接

注册表单包含:

  • 用户名输入框
  • 密码输入框
  • 确认密码输入框
  • 邮箱输入框
  • 昵称输入框
  • 注册按钮
  • 切换到登录的链接
2. 表单验证机制

在这里插入图片描述

前端实现了实时表单验证功能,在用户输入时即时反馈:

// 验证用户名格式
validateUsername(username) {
  return /^\S{5,16}$/.test(username)
},

// 验证密码格式
validatePassword(password) {
  return /^\S{5,16}$/.test(password)
},

// 验证密码是否匹配
validatePasswordMatch(password, confirmPassword) {
  return password === confirmPassword
}

验证规则:

  • 用户名:5-16位非空字符
  • 密码:5-16位非空字符
  • 确认密码:必须与密码一致
  • 邮箱:必须符合邮箱格式

三、网络请求层实现

1. HTTP拦截器

http.ts中实现了请求拦截器,主要功能包括:

const httpInterceptor = {
  invoke(options: UniApp.RequestOptions) {
    // 1. 非 http 开头需拼接地址
    if (!options.url.startsWith('http')) {
      options.url = baseURL + options.url
    }
    // 2. 请求超时设置
    options.timeout = 10000
    // 3. 添加小程序端请求头标识
    options.header = {
      ...options.header,
      'source-client': 'miniapp',
    }
    // 4. 添加 token 请求头标识
    const memberStore = useMemberStore()
    const token = memberStore.profile?.token
    if (token) {
      options.header.Authorization = token
    }
  },
}
2. 统一的请求处理

封装了http函数处理所有请求的响应和错误:

export const http = <T>(options: UniApp.RequestOptions) => {
  return new Promise<T>((resolve, reject) => {
    uni.request({
      ...options,
      success(res) {
        // 处理各种状态码
        if (res.statusCode >= 200 && res.statusCode < 300) {
          const data = res.data as ResultData<T>
          if (data.code === 200) {
            resolve(data.data)
          } else if (data.code === 401) {
            handleUnauthorized()
            reject(data)
          } else {
            uni.showToast({
              icon: 'none',
              title: data.message || '业务错误',
            })
            reject(data)
          }
        }
        // 其他状态码处理...
      },
      fail(err) {
        uni.showToast({
          icon: 'none',
          title: '网络错误,请检查网络连接',
        })
        reject(err)
      },
    })
  })
}

四、状态管理实现

使用Pinia进行状态管理,在member.ts中定义了用户状态:

export const useMemberStore = defineStore(
  'member',
  () => {
    // 用户信息
    const profile = ref<any>()

    // 保存用户信息
    const setProfile = (val: any) => {
      profile.value = val
    }

    // 清理用户信息
    const clearProfile = () => {
      profile.value = undefined
    }

    return {
      profile,
      setProfile,
      clearProfile,
    }
  },
  // 持久化配置
  {
    persist: {
      storage: {
        getItem(key) {
          return uni.getStorageSync(key)
        },
        setItem(key, value) {
          uni.setStorageSync(key, value)
        },
      },
    },
  },
)

五、登录功能实现细节

1. 登录流程
用户 前端界面 网络层 后端 状态管理 路由 1. 输入用户名/密码 2. 实时格式验证 显示错误提示(红色边框) 3. 点击登录按钮 4. 发送登录请求(POST /user/login) 5. 认证校验 6. 返回错误码(1002/1003) 7. 显示错误Toast 8. 提示"密码错误"等 6. 返回token 7. 保存token(setProfile) 8. 持久化到Storage 9. 跳转逻辑判断 10. 返回上一页(navigateBack) 10. 跳转首页(switchTab) alt [有历史页面] [无历史页面] 11. 显示"登录成功"Toast alt [认证失败] [认证成功] alt [验证失败] [验证通过] 用户 前端界面 网络层 后端 状态管理 路由

时序图关键节点解释

  1. 步骤4-5:网络层会自动添加Authorization头(如果已有token)

    // http.ts拦截器
    if (token) {
      options.header.Authorization = token
    }
    
  2. 步骤7-8:采用uni.setStorageSync双写保证可靠性

    // login.vue中的处理
    memberStore.setProfile({ token: res })
    uni.setStorageSync('token', res) // 双重保险
    
  3. 步骤10:智能跳转逻辑避免页面栈混乱

    // 判断逻辑优先保障用户体验
    
2. 前端验证阶段

在这里插入图片描述

输入用户名
长度5-16位?
显示红色提示
输入密码
长度5-16位?
显示红色提示
解锁登录按钮
  • 验证规则

    // login.vue中的验证方法
    validateUsername(username) {
      return /^\S{5,16}$/.test(username) // 非空字符5-16位
    }
    
3. 网络请求阶段
发起请求
拦截器处理
添加baseURL
注入token头
设置10s超时
发送到后端
  • 请求示例

    await post('/user/login', {
      username: 'testuser',
      password: '123456'
    })
    
4. 令牌存储阶段
收到token
Pinia存储
触发持久化
写入uniStorage
下次启动自动读取
  • 存储逻辑

    // member.ts中的action
    setProfile(val: any) {
      this.profile = val  // 响应式更新
      // 通过persist插件自动持久化
    }
    
5. 跳转逻辑判断

在这里插入图片描述

登录成功
有页面历史?
返回上一页
跳转首页
保持用户操作上下文
进入主界面
  • 实现代码

    const pages = getCurrentPages()
    if (pages.length > 1) {
      uni.navigateBack()  // 返回
    } else {
      uni.switchTab({     // 首页
        url: '/pages/index/index'
      })
    }
    
6. 异常处理分支
异常类型处理方式用户提示
用户名格式错误阻止提交,显示行内提示“用户名需5-16位非空字符”
密码格式错误阻止提交,显示行内提示“密码需5-16位非空字符”
用户不存在网络层拦截,显示Toast“用户不存在”
密码错误网络层拦截,显示Toast“密码错误”
网络连接失败fail回调处理,显示Toast“网络异常,请检查连接”
服务端错误根据statusCode处理“服务繁忙,请稍后重试(code)”

六、注册功能实现细节

1. 注册流程
用户 前端界面 网络层 后端 状态管理 1. 填写注册信息 2. 实时表单验证 显示行内错误提示 3. 点击注册按钮 4. 发送注册请求(POST /user/register) 5. 处理注册逻辑 6. 返回错误码(1001) 7. 显示错误Toast 8. 提示"用户名已存在" 6. 返回成功响应 7. 处理成功逻辑 8. 自动填充用户名 9. 清空注册表单 10. 切换至登录表单 11. 显示"注册成功"Toast alt [用户名已存在/其他错误] [注册成功] alt [任何字段验证失败] [所有验证通过] 用户 前端界面 网络层 后端 状态管理
2. 表单验证阶段
失败
通过
失败
通过
失败
通过
失败
通过
开始注册
验证用户名格式
显示红色提示
验证密码格式
显示红色提示
验证密码一致性
显示红色提示
验证邮箱格式
显示红色提示
启用注册按钮
  • 验证逻辑示例

    // login.vue中的验证方法
    validatePasswordMatch(password, confirmPassword) {
      return password === confirmPassword // 密码一致性检查
    }
    
3. 网络请求阶段
成功
失败
封装请求数据
添加JSON Content-Type
发送到/user/register
响应处理
触发成功逻辑
提取错误码
  • 请求示例

    await post('/user/register', {
      username: 'newuser',
      password: '123456',
      confirmPassword: '123456',
      email: 'user@example.com',
      nickname: '昵称'
    })
    
4. 注册后处理阶段
收到成功响应
填充用户名到登录表单
清空注册表单字段
切换表单状态
显示成功提示
  • 自动填充实现

    this.loginForm.username = this.registerForm.username
    this.registerForm = {
      username: '',
      password: '',
      // 其他字段重置...
    }
    this.isRegister = false
    
5. 异常处理场景
异常类型检测方式用户反馈方式
用户名格式不符前端正则校验 /\S{5,16}/输入框下方红色文字提示
密码不一致比较password和confirmPassword字段确认密码框下方提示
邮箱格式错误检查是否包含@符号邮箱输入框下方提示
用户名已存在后端返回1001错误码顶部Toast提示"用户名已存在"
网络请求超时拦截器10s超时机制Toast提示"网络连接超时"
6. 与登录流程的差异点
  1. 多字段协同验证

    密码字段
    确认密码
    邮箱格式
    独立校验
  2. 成功后的特殊处理

    // 注册特有的表单处理
    this.loginForm.username = this.registerForm.username // 用户名自动传递
    
  3. 更复杂的验证逻辑

    // 注册时需要验证更多字段
    if (!this.registerForm.nickname.trim()) {
      this.showErrorToast('请输入昵称')
      return
    }
    

七、安全与优化措施

  1. Token存储安全

    • 使用Pinia持久化插件将token存储在本地
    • 每次请求自动携带token
  2. 401未授权处理

    function handleUnauthorized() {
      const memberStore = useMemberStore()
      memberStore.clearProfile()
      uni.navigateTo({ url: '/pages/login/login' })
      uni.showToast({
        icon: 'none',
        title: '登录已过期,请重新登录',
      })
    }
    
  3. 请求超时设置

    options.timeout = 10000
    
  4. 网络错误处理

    fail(err) {
      uni.showToast({
        icon: 'none',
        title: '网络错误,请检查网络连接',
      })
      reject(err)
    }
    

八、用户体验优化

  1. 表单切换动画

    • 使用v-if/v-else实现表单切换
    • 清空密码字段确保安全
  2. 加载状态反馈

    在这里插入图片描述

    <button :disabled="isLogging" :loading="isLogging">
      {{ isLogging ? '登录中...' : '登 录' }}
    </button>
    
  3. 输入实时验证

    @input="validateInput('username')"
    
  4. 成功后的自动跳转

    setTimeout(() => {
      const pages = getCurrentPages()
      if (pages.length > 1) {
        uni.navigateBack()
      } else {
        uni.switchTab({
          url: '/pages/index/index'
        })
      }
    }, 1500)
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值