鸿蒙(Harmony)实现滑块验证码

在Android和ios两端已经使用的滑块验证码框架还未适配鸿蒙版,于是需要自己去实现类似如下的滑块验证码:

那么实现这样的验证码主要涉及到几个内容:

1、自定义弹窗
2、base64图片转换
3、滑动组件与滑块的联动,以及横移距离转换等
自定义弹窗:

自定义一个可导出的弹窗组件CustomDialog,最主要是使用 @CustomDialog 修饰符。

@CustomDialog
export struct BlockPuzzleDialog {phoneNum: number | string = ''controller: CustomDialogController = new CustomDialogController({builder: BlockPuzzleDialog({}),})build() {Column(){}}// 验证码校验回调给使用页面blockCheckCallback: (token: string) => void = (token: string) => {}
}

在使用页面创建构造器与弹窗绑定

 @Entry@Componentstruct LoginPage {dialogController: CustomDialogController = new CustomDialogController({builder: BlockPuzzleDialog({phoneNum: this.phoneNum, blockCheckCallback: (token: string) => {this.blockPuzzleSuccessCallback(token)}}),autoCancel: false,//弹窗是否自动取消alignment: DialogAlignment.Center,// 弹窗位置cornerRadius: 8,width: '90%'// 弹窗宽度})build(){...}}

弹窗UI组件的实现:核心组件就一个预先挖孔的底图上面叠加滑块图片再加上一个slider组件

build(){......Stack() {Image(this.coverUri).width('100%').margin({ top: 10 }).objectFit(ImageFit.Auto).onComplete((event) => {this.scaleRatio = event!!.componentWidth / event?.width!!})Image(this.blockUri).width(this.blockW + "px").height(this.blockH + "px").margin({ top: 10 }).objectFit(ImageFit.Auto).onComplete((event) => {this.blockW = event?.width!! * this.scaleRatiothis.blockH = event?.height!! * this.scaleRatiothis.slideMax = Const.mWidth * 0.9 - 24 - px2vp(this.blockW)}).translate({ x: this.bolckTranslateX + "px" })this.loading()}.width('100%').alignContent(Alignment.Start)RelativeContainer() {Text('向右拖动滑动填充拼图').fontSize(18).fontColor($r('app.color.C_BEBEC6')).id('blockTip').alignRules({"top": {"anchor": "slider","align": VerticalAlign.Top},"bottom": {"anchor": "slider","align": VerticalAlign.Bottom},"left": {"anchor": "slider","align": HorizontalAlign.Start},"right": {"anchor": "slider","align": HorizontalAlign.End},}).textAlign(TextAlign.Center)Slider({style: SliderStyle.InSet,value: $$this.sliderValue,step: 1,max: vp2px(this.slideMax)}).trackColor(this.sliderConfig.trackColor).selectedColor(this.sliderConfig.selectedColor).blockSize({ height: 40, width: 44 }).blockStyle({type: SliderBlockType.IMAGE,image: this.sliderConfig.blockImg})// .sliderInteractionMode(SliderInteraction.SLIDE_ONLY).trackBorderRadius(Const.BORDER_RADIUS_4).trackThickness(40).width('100%').onChange((value: number, mode: SliderChangeMode) => {// this.bolckTranslateX = this.slideMax * (value / this.slideMax)this.bolckTranslateX = valueconsole.info('滑块滑动:滑块滑动数值==' + value + " 图片位移==" + this.bolckTranslateX)if (mode == SliderChangeMode.End) {// this.sliderValue = valuelet point = new Point()point.x = parseFloat((this.bolckTranslateX / this.scaleRatio).toFixed(0))console.info('滑动结束:滑动数值 this.sliderValue==' + this.sliderValue + " this.bolckTranslateX==" +this.bolckTranslateX + " 转像素==" + point.x)this.checkCaptcha(point)}}).id('slider')}.width('100%').height(40).margin({ top: 10 })......}

滑块图片translate的值就是Slider组件的滑动值。使用

this.dialogController.open() 弹窗
Base64图片的下载与转换
aboutToAppear(): void {this.getSlideImage()
}......// 获取底图和滑块图片的base64数据并保存到本地,同时获取到滑块校验相关信息。
getSlideImage() {this.sliderConfig.showLoading = trueHttpUtil.getData<BlockResult>(Const.URL_BLOCK_IMG).then((result) => {if (result !== undefined && result !== null) {this.blockResult = resultthis.coverBase64 = this.blockResult.repData?.originalImageBase64!!this.blockBase64 = this.blockResult.repData?.jigsawImageBase64!!console.info("滑块:获取到base64 ==" + this.coverBase64)let coverName = "coverBase64_" + Date.now().toString() + ".png"let blockName = "blockBase64_" + Date.now().toString() + ".png"this.coverPath = this.context.filesDir + "/temp/" + coverName;this.blockPath = this.context.filesDir + "/temp/" + blockName;this.coverUri =Utils.saveBase64Image(this.coverBase64, this.context, coverName)this.blockUri =Utils.saveBase64Image(this.blockBase64, this.context, blockName)this.sliderConfig.showLoading = falsethis.reset()}})}

可以参考官网示例 通过buffer.from的方法,将base64编码格式的字符串创建为新的Buffer对象,接着用fileIo.writeSync方法将转换好的Buffer对象写入文件。

let context = getContext(this) as common.UIAbilityContext; 
let filesDir = context.filesDir; // data为需要转换的base64字符串,返回沙箱路径uri 
export async function writeFile(data: string): Promise<string> { let uri = '' try { let filePath = filesDir + "/1.png"; uri = fileUri.getUriFromPath(filePath); let file = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); console.info("file fd: " + file.fd); const reg = new RegExp("data:image/\\w+;base64,") const base64 = data.replace(reg, ""); console.log("base64flag", base64) const dataBuffer = buffer.from(base64, 'base64') let writeLen = fileIo.writeSync(file.fd, dataBuffer.buffer); hilog.info(0xA0c0d0,'uri',uri) fileIo.closeSync(file); } catch (Error) { hilog.error(0xA0c0d0,'Error',Error.code) } return uri; 
}

当然你还可以直接将Base64转换成PiexlMap.先将base64字符串解析成arraybuffer,然后利用这个arraybuffer构建新PixelMap,需要注意的是,使用decodeSync对base64字符串解码时,传入的base64字符串不能有'data:image/jpeg;base64,'这样的前缀。

import CommonConstants from '../common/constants/CommonContants'; 
import { util } from '@kit.ArkTS';
import { image } from '@kit.ImageKit';@Entry
@Component
struct Index {@State message: string = 'Base64ToPixelMap';private base64: string = CommonConstants.Image_Base64_String; // 该变量为图片的base64格式字符串 @State private pixelMap: PixelMap | null = null;build() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold).onClick(async () => {let helper = new util.Base64Helper();let buffer: ArrayBuffer = helper.decodeSync(this.base64, util.Type.MIME).buffer as ArrayBuffer;let imageSource = image.createImageSource(buffer);let opts: image.DecodingOptions = { editable: true };this.pixelMap = await imageSource.createPixelMap(opts);})Image(this.pixelMap).width(200).height(200).margin(15)}.width('100%')}.height('100%')}
}

将得到的图片本地保存地址uri或者转换成的piexlMap设置给底图和滑动图片。

滑动值校验

上面已经说过,滑块的移动值就是Slider滑动值。其中slider 步长设置为1,滑动的最大值slideMax=底图的宽度-滑块图片的宽度。这样滑动值转换更方便,联动效果也更好。这里注意下 底图在填满控件的时候有一定的缩放,滑动图片组件也需要按照这个缩放比例设置宽高。

step: 1,
max: vp2px(this.slideMax)

最后在slider的onchange回调中校验滑动值是不是正确,注意滑动值要除以上面的底图缩放比例。

将滑动值加上校验token传给校验接口获取校验结果。

.onChange((value: number, mode: SliderChangeMode) => {this.bolckTranslateX = valueconsole.info('滑块滑动:滑块滑动数值==' + value + " 图片位移==" + this.bolckTranslateX)if (mode == SliderChangeMode.End) {// this.sliderValue = valuelet point = new Point()point.x = parseFloat((this.bolckTranslateX / this.scaleRatio).toFixed(0))console.info('滑动结束:滑动数值 this.sliderValue==' + this.sliderValue + " this.bolckTranslateX==" +this.bolckTranslateX + " 转像素==" + point.x)this.checkCaptcha(point)}
})
checkFail() {this.sliderConfig.showLoading = falsethis.sliderConfig.trackColor = $r('app.color.C_0DF32222')this.sliderConfig.selectedColor = $r('app.color.C_F32222')this.sliderConfig.blockImg = $r('app.media.drag_btn_error')this.sliderValue = 0this.bolckTranslateX = 0setTimeout(() => {// 删掉滑块图片FileUtil.delFile(this.coverPath)FileUtil.delFile(this.blockPath)this.getSlideImage()}, 300)}checkSuccess() {this.sliderConfig.showLoading = falsethis.sliderConfig.trackColor = $r('app.color.C_0D1264E0')this.sliderConfig.selectedColor = $r('app.color.C_1264E0')this.sliderConfig.blockImg = $r('app.media.drag_btn_success')setTimeout(() => {this.controller.close()// 删掉滑块图片FileUtil.delFile(this.coverPath)FileUtil.delFile(this.blockPath)if (this.blockCheckCallback !== undefined) {this.blockCheckCallback(this.blockResult?.token!!)}}, 300)}

调用刚刚定义的回调方法将校验结果回调给登录页面this.blockCheckCallback(this.blockResult?.token!!)

至此导致流程已结束,当然还有一些细节需要自己根据业务实现。最后完成效果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/466794.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是嵌入式操作系统?

什么是嵌入式操作系统? 想象一下&#xff0c;如果一个智能设备&#xff0c;比如你口袋里的智能手机&#xff0c;是一个有头脑的机器人&#xff0c;那么嵌入式操作系统&#xff08;Embedded Operating System&#xff0c;简称EOS&#xff09;就相当于这个机器人的大脑。它告诉机…

后台管理系统窗体程序:评论管理

目录 评论管理的功能介绍&#xff1a; 1、进入页面 2、页面内的各种功能设计 &#xff08;1&#xff09;网页内的表格 &#xff08;2&#xff09;拒绝按钮&#xff0c;批准按钮 &#xff08;3&#xff09;删除按钮 &#xff08;4&#xff09;页面翻页跳转按钮 一、网页设计​…

nginx代理 proxy_pass

一、location 包含 location /api/ {proxy_pass http://127.0.0.1:85;} 二、location 不包含 location /api/ {proxy_pass http://127.0.0.1:85/;} 三、locaion 包含 location /api {proxy_pass http://127.0.0.1:85;}四、location 包含 location /api {proxy_pass http://127.…

InnoDB 存储引擎<七>通用表空间+临时表空间

目录 通⽤表空间 - General Tablespace 临时表空间 - Temporary Tablespaces 通⽤表空间 - General Tablespace 对应磁盘上的文件需要用户手动创建 1.通⽤表空间的作⽤和特性&#xff1f; 解答问题&#xff1a; 1.作用&#xff1a;可以把数据量比较小且强相关的表&#xff…

乐维网管平台(五):如何精准定位网络终端设备

在当今数字化高度发展的时代&#xff0c;网络已经成为企业和组织运营的关键基础设施。而在网络管理领域&#xff0c;终端定位技术正发挥着越来越重要的作用。 一、什么是终端定位 终端定位是网络管理中的关键环节&#xff0c;从本质上讲&#xff0c;它是一种精确确定网络终端…

企业邮箱后缀设置指南,轻松融入公司品牌

邮箱后缀指""后域名&#xff0c;本文介绍如何添加公司名作为后缀&#xff0c;以Zoho邮箱为例&#xff0c;需注册账号、购买域名、配置DNS、添加自定义域名、创建账号。Zoho邮箱安全可靠、个性化定制、易于管理&#xff0c;提供不同定价方案&#xff0c;并给出客户端配…

【D3.js in Action 3 精译_039】4.3 D3 面积图的绘制方法及其边界标签的添加

当前内容所在位置&#xff1a; 第四章 直线、曲线与弧线的绘制 ✔️ 4.1 坐标轴的创建&#xff08;上篇&#xff09; 4.1.1 D3 中的边距约定&#xff08;中篇&#xff09;4.1.2 坐标轴的生成&#xff08;中篇&#xff09; 4.1.2.1 比例尺的声明&#xff08;中篇&#xff09;4.1…

时序动作定位 | 基于层次结构潜在注意模型的弱监督动作定位(ICCV 2023)

<Weakly-Supervised Action Localization by Hierarchically-structured Latent Attention Modeling> 这篇文章的标题是《Weakly-Supervised Action Localization by Hierarchically-structured Latent Attention Modeling》,作者是Guiqin Wang等人,来自西安交通大学和…

华为交换机Vlan划分

华为交换机Vlan划分 Tip&#xff1a;一个广播域划分vlan达到隔离广播目的且不能互访。 一个广播域划分子网掩码也可以不能互访&#xff0c;但是还是在一个广播域&#xff0c;还是会发生广播风暴。 本次实验模拟交换机不同端口划分不同vlan达到隔绝广播风暴效果。 pc1 pc2分配…

[linux]docker快速入门

安装 docker官网: CentOS | Docker Docs 准备工作: 准备ConstOS7的虚拟机环境账密: root/root飞书文档: Docs 卸载旧版本 // 首先如果系统中已经存在旧的Docker&#xff0c;则先卸载 yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest…

vue echarts左右间距调整 左右空白

咱就说这样的左右间距丑不丑。。 经过调整后&#xff0c;嗯&#xff0c;好看了很多。页面也协调多了&#xff01; 直接上代码&#xff1a;添加以下配置数据&#xff1a; grid: {x: 50,y: 25,x2: 30,y2: 35 }, this.chart.setOption({width: 100%,xAxis: {show: false,type: ca…

内置函数【MySQL】

文章目录 日期函数字符串函数数学函数其他函数 日期函数 current_date函数用于获取当前的日期 mysql> select current_date(); ---------------- | current_date() | ---------------- | 2024-11-03 | ---------------- 1 row in set (0.00 sec)current_time函数用于获…

软件设计师-上午题-14 信息安全(5分)

信息安全题号一般为7-9或10-11题&#xff0c;分值一般为5分。 目录 1 防火墙 1.1 真题 2 病毒 2.1 真题 3 网络攻击 3.1 真题 4 网络安全 4.1 真题 5 杂题选讲 1 防火墙 1.1 真题 1.2009年下半年第8题 2.2013年上半年第8题 3.2014年上半年第8题 4.2011年上半年第9题…

移植 AWTK 到 纯血鸿蒙 (HarmonyOS NEXT) 系统 (9) - 编译现有的AWTK应用程序

AWTK 应用程序开发完成后&#xff0c;在配置文件中添加 harmonyos 的选项&#xff0c;通过create_project.py脚本即可生成 DevEco Studio的工程。 安装开发环境 DevEco Studio HarmonyOS 的开发工具。 Python 运行环境。 git 源码管理工具。 下载 awtk 和 awtk-harmonyos…

如何创建备份设备以简化 SQL Server 备份过程?

SQL Server 中的备份设备是什么&#xff1f; 在 SQL Server 中&#xff0c;备份设备是用于存储备份数据的物理或逻辑介质。备份设备可以是文件、设备或其他存储介质。主要类型包括&#xff1a; 文件备份设备&#xff1a;通常是本地文件系统中的一个或多个文件。可以是 .bak 文…

Dependency: androidx.webkit:webkit:1.11.0-alpha02. 问题

android studio 打包后出现这个问题 1.步骤更新topOn sdk 添加 //Admob api “com.anythink.sdk:adapter-admob:6.4.18” api “com.google.android.gms:play-services-ads:23.4.0” api "com.google.android.gms:play-services-ads:23.4.0"sdk 中会出现打包编译报错…

ubuntu 20.04 NVIDIA驱动、cuda、cuDNN安装

1. NVIDIA驱动 系统设置->软件和更新->附加驱动->选择NVIDIA驱动->应用更改。该界面会自动根据电脑上的GPU显示推荐的NVIDIA显卡驱动。 运行nvidia-smi: NVIDIA-SMI has failed because it couldnt communicate with the NVIDIA driver. Make sure that the lat…

SpringBoot监控

1、Spring Boot Actuator 监控 Spring Boot Actuator 可以帮助监控和管理 Spring Boot 应用&#xff0c;比如健康检查、审计、统计和 HTTP 追踪等。所有的这些特性可以通过 JMX 或者 HTTP endpoints 来获得。 1、Actuator 监控应用程序 启用 Actuator 的端点&#xff0c;只要…

动态规划 —— dp 问题-粉刷房子

1. 剑指offer —— 粉刷房子 题目链接&#xff1a; LCR 091. 粉刷房子 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/JEj789/description/ 2. 题目解析 根据上图可以得到costs横坐标&#xff08;行&#xff09;是房子的号数&#xff0c;红色的下标是0&…

RPA是什么,RPA有什么作用?

在数字化转型的时代背景下&#xff0c;企业面临着提高效率、降低成本和优化流程的巨大压力。RPA作为一种革新性的数字化技术&#xff0c;迅速成为企业实现这些目标的利器。那么&#xff0c;RPA究竟是什么&#xff1f;它又能为企业带来哪些实际作用呢&#xff1f;本文金智维将对…