所有分类
  • 所有分类
  • Html5资源
  • React资源
  • Vue资源
  • Php资源
  • ‌小程序资源
  • Python资源

鸿蒙系统(HarmonyOS)应用开发之经典蓝色风格登录页布局、图文验证码

一、项目概述

本项目是一款基于鸿蒙 ArkTS(ETS)开发的用户登录页面,集成了图文验证码功能,旨在为应用提供安全、便捷的用户身份验证入口。项目采用现代化 UI 设计,兼顾用户体验与安全性,适用于多种需要用户登录的场景。

二、功能特点

  1. 图文验证码防护
    内置自定义验证码组件,支持随机字符、颜色、旋转、干扰线和干扰点,极大提升了防机器自动化攻击的能力。
  2. 动态刷新机制
    用户可点击验证码区域一键刷新,验证码内容与样式实时变化,提升安全性和交互体验。
  3. 表单校验与提示
    登录表单支持用户名、密码、验证码的完整性校验,输入不完整或验证码错误时,自动弹窗友好提示。
  4. 简洁美观的界面
    采用现代化配色和布局,界面简洁、操作直观,适配多种终端分辨率。
  5. 易于集成与扩展
    验证码组件高度解耦,可灵活集成到其他页面或项目中,支持自定义扩展。

三、技术架构

  • 开发语言:ArkTS(ETS)
  • UI 框架:HarmonyOS ArkUI
  • 组件化设计:采用@Entry、@Component 等装饰器实现页面与组件的解耦
  • 状态管理:利用@State、@Prop 等特性实现数据驱动视图
  • 随机算法:内置字符、颜色、旋转、干扰线点等多重随机生成算法
  • 事件响应:支持 onClick、onChange 等事件,提升交互体验

关键技术实现

  • 验证码组件VerifyCodeCanvas通过多组随机数生成干扰线、干扰点和字符样式,极大增强验证码的安全性和不可预测性。
  • 登录逻辑中对用户输入进行严格校验,确保信息完整且验证码正确后才允许登录。

四、使用场景

  • 企业/组织内部系统登录
    适用于 OA、ERP、CRM 等需要身份验证的企业级应用,提升系统安全性。
  • 移动 App 用户注册/登录
    可集成到各类移动应用的注册、登录、找回密码等流程中,防止恶意注册和暴力破解。
  • Web 管理后台
    适合各类管理后台、控制台等需要登录验证的 Web 端项目。
  • IoT 设备管理
    用于智能设备的远程管理登录,保障设备安全接入。

完整源码

// 定义点位置的接口
interface PointPosition {
  x: number;
  y: number;
}

// 验证码组件
@Component
struct VerifyCodeCanvas {
  @Prop code: string
  @Prop refreshFlag: number
  // 用于存储随机生成的数据
  @State private linePoints1: number[][] = []
  @State private linePoints2: number[][] = []
  @State private dotPositions: PointPosition[] = []
  @State private charColors: string[] = []
  @State private charRotations: number[] = []

  aboutToAppear() {
    this.generateRandomData()
  }

  // 生成所有随机数据
  private generateRandomData() {
    // 生成干扰线点
    this.linePoints1 = [
      [Math.random() * 100, Math.random() * 40],
      [Math.random() * 100, Math.random() * 40],
      [Math.random() * 100, Math.random() * 40],
      [Math.random() * 100, Math.random() * 40]
    ]

    this.linePoints2 = [
      [Math.random() * 100, Math.random() * 40],
      [Math.random() * 100, Math.random() * 40],
      [Math.random() * 100, Math.random() * 40]
    ]

    // 生成干扰点位置
    this.dotPositions = [
      { x: Math.random() * 100, y: Math.random() * 40 },
      { x: Math.random() * 100, y: Math.random() * 40 },
      { x: Math.random() * 100, y: Math.random() * 40 },
      { x: Math.random() * 100, y: Math.random() * 40 }
    ]

    // 生成字符颜色和旋转角度
    this.charColors = [
      this.getRandomColor(),
      this.getRandomColor(),
      this.getRandomColor(),
      this.getRandomColor()
    ]

    this.charRotations = [
      this.getRandomRotation(),
      this.getRandomRotation(),
      this.getRandomRotation(),
      this.getRandomRotation()
    ]
  }

  // 生成随机颜色
  private getRandomColor(): string {
    const colors = ['#0D5BC3', '#2979FF', '#1565C0', '#0277BD']
    return colors[Math.floor(Math.random() * colors.length)]
  }

  // 生成随机旋转角度
  private getRandomRotation(): number {
    return (Math.random() - 0.5) * 30
  }

  // 生成随机位置偏移
  private getRandomOffset(): number {
    return (Math.random() - 0.5) * 6
  }

  // 监听refreshFlag变化
  onPropertyChange(propName: string, newValue: number): void {
    if (propName === 'refreshFlag') {
      this.generateRandomData()
    }
  }

  build() {
    Stack({ alignContent: Alignment.Center }) {
      // 背景
      Rect()
        .width('100%')
        .height('100%')
        .fill('#E8F0FE')

      // 使用Polyline代替多条Line
      Polyline()
        .width('100%')
        .height('100%')
        .points(this.linePoints1)
        .stroke(this.getRandomColor())
        .strokeWidth(1)
        .fillOpacity(0)

      // 再添加一条Polyline增加干扰
      Polyline()
        .width('100%')
        .height('100%')
        .points(this.linePoints2)
        .stroke(this.getRandomColor())
        .strokeWidth(1)
        .fillOpacity(0)

      // 添加几个固定的干扰点
      Circle()
        .width(2)
        .height(2)
        .position({ x: this.dotPositions[0].x, y: this.dotPositions[0].y })
        .fill(this.getRandomColor())

      Circle()
        .width(2)
        .height(2)
        .position({ x: this.dotPositions[1].x, y: this.dotPositions[1].y })
        .fill(this.getRandomColor())

      Circle()
        .width(2)
        .height(2)
        .position({ x: this.dotPositions[2].x, y: this.dotPositions[2].y })
        .fill(this.getRandomColor())

      Circle()
        .width(2)
        .height(2)
        .position({ x: this.dotPositions[3].x, y: this.dotPositions[3].y })
        .fill(this.getRandomColor())

      // 验证码文字
      Flex({ justifyContent: FlexAlign.SpaceEvenly, alignItems: ItemAlign.Center }) {
        Text(this.code[0])
          .fontSize(22)
          .fontWeight(FontWeight.Bold)
          .fontColor(this.charColors[0])
          .rotate({ z: 1, angle: this.charRotations[0] })

        Text(this.code[1])
          .fontSize(22)
          .fontWeight(FontWeight.Bold)
          .fontColor(this.charColors[1])
          .rotate({ z: 1, angle: this.charRotations[1] })

        Text(this.code[2])
          .fontSize(22)
          .fontWeight(FontWeight.Bold)
          .fontColor(this.charColors[2])
          .rotate({ z: 1, angle: this.charRotations[2] })

        Text(this.code[3])
          .fontSize(22)
          .fontWeight(FontWeight.Bold)
          .fontColor(this.charColors[3])
          .rotate({ z: 1, angle: this.charRotations[3] })
      }
      .width('100%')
      .height('100%')
    }
    .width(100)
    .height(40)
    .margin({ right: 10 })
  }
}

@Entry
@Component
struct Index {
  @State username: string = ''
  @State password: string = ''
  @State verifyCode: string = ''
  @State inputCode: string = ''
  @State refreshFlag: number = 0 // 用于触发验证码刷新

  // 生成随机验证码
  private generateVerifyCode(): void {
    const characters = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789'
    let code = ''
    for (let i = 0; i < 4; i++) {
      code += characters.charAt(Math.floor(Math.random() * characters.length))
    }
    this.verifyCode = code
    this.refreshFlag++ // 增加刷新标志,触发重绘
  }

  aboutToAppear() {
    this.generateVerifyCode()
  }

  build() {
    Column() {
      // 标题
      Text('用户登录')
        .fontSize(28)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 80, bottom: 50 })
        .fontColor('#0D5BC3')

      // 用户名输入框
      TextInput({ placeholder: '请输入用户名' })
        .width('80%')
        .height(50)
        .margin({ bottom: 20 })
        .backgroundColor('#F5F5F5')
        .onChange((value: string) => {
          this.username = value
        })

      // 密码输入框
      TextInput({ placeholder: '请输入密码' })
        .width('80%')
        .height(50)
        .margin({ bottom: 20 })
        .backgroundColor('#F5F5F5')
        .type(InputType.Password)
        .onChange((value: string) => {
          this.password = value
        })

      // 验证码区域
      Flex({ justifyContent: FlexAlign.SpaceBetween }) {
        TextInput({ placeholder: '请输入验证码' })
          .width('60%')
          .height(50)
          .backgroundColor('#F5F5F5')
          .onChange((value: string) => {
            this.inputCode = value
          })

        Flex({ justifyContent: FlexAlign.Center }) {
          // 图文验证码组件
          VerifyCodeCanvas({
            code: this.verifyCode,
            refreshFlag: this.refreshFlag
          })
            .onClick(() => {
              this.generateVerifyCode()
            })
        }
        .width('35%')
        .height(50)
        .backgroundColor('#E8F0FE')
      }
      .width('80%')
      .margin({ bottom: 40 })

      // 登录按钮
      Button('登录')
        .width('80%')
        .height(50)
        .backgroundColor('#0D5BC3')
        .fontColor(Color.White)
        .onClick(() => {
          if (!this.username || !this.password || !this.inputCode) {
            AlertDialog.show({
              title: '提示',
              message: '请填写完整信息',
              confirm: {
                value: '确定',
                action: () => {
                  console.info('用户确认')
                }
              }
            })
            return
          }

          if (this.inputCode.toLowerCase() !== this.verifyCode.toLowerCase()) {
            AlertDialog.show({
              title: '提示',
              message: '验证码错误',
              confirm: {
                value: '确定',
                action: () => {
                  this.generateVerifyCode()
                }
              }
            })
            return
          }

          // TODO: 实现登录逻辑
          console.info('登录信息:', this.username, this.password)
        })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
  }
}
资源下载
下载价格免费
注意:本网站资源属于虚拟产品,不支持退款。请谨慎购买! 购买后资源无法下载,请联系客服QQ:844475003,微信号:th844475003。
原文链接:https://code.ifrontend.net/archives/655,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?