鸿蒙(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.xdnf.cn/news/6837.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

《华为工作法》读书摘记

无论做什么事情&#xff0c;首先要明确的就是做事的目标。目标是引导行动的关键&#xff0c;也是证明行动所具备的价值的前提&#xff0c;所以目标管理成了企业与个人管理的重要组成部分。 很多时候&#xff0c;勤奋、努力并不意味着就一定能把工作做好&#xff0c;也并不意味…

三维测量与建模笔记 - 3.3 张正友标定法

上图中&#xff0c;提到了世界坐标系在张正友标定法中的设计&#xff0c;可以理解为将世界坐标系的原点放到了棋盘格左上角点的位置&#xff0c;并且棋盘格平面上所有点的Z为0&#xff0c;将Z规定为0的话&#xff0c;可以简化掉一个维度&#xff08;列向量r3&#xff09;。去掉…

【课程总结】day34:多模态大模型之ViT模型、CLIP模型论文阅读理解

前言 在【课程总结】day31&#xff1a;多模态大模型初步了解一文中&#xff0c;我们对多模态大模型的基本原理有了初步了解&#xff0c;本章内容将通过论文阅读理解&#xff0c;更进一步理解多模态大模型中所涉及的 Vit 架构、Transformer在视觉应用的理念以及 Clip图像与文本…

国药准字生发产品有哪些?这几款不错

头秃不知道怎么选的朋友们看这&#xff0c;基本上市面上火的育发精华我都用了个遍了&#xff0c;陆陆续续也花了有大几w了&#xff0c;都是真金白银总结出来的&#xff0c;所以必须要给掉发人分享一些真正好用的育发产品&#xff0c;大家可以根据自己实际情况来选择。 1. 露卡菲…

golang分布式缓存项目 Day 1

注&#xff1a;该项目原作者&#xff1a;https://geektutu.com/post/geecache-day1.html。本文旨在记录本人做该项目时的一些疑惑解答以及部分的测试样例以便于本人复习。 LRU缓存淘汰策略 三种缓存淘汰策略 FIFO&#xff08;First In, First Out&#xff09;先进先出 原理&…

Android View事件分发

目录 1.什么是View事件分发&#xff1f; 2.事件的类型 3.事件的发生 4.事件分发的方法 4.1 dispatchTouchEvent() 4.2 onTouchEvent() 4.3 onInterceptTouchEvent() 5.滑动冲突 5.1 外部拦截法 5.2内部拦截法 6.onTouch的执行高于onClick 7. onTouch()和onTouchEve…

Elasticsearch常用接口_添加数据

插入es数据&#xff1a;_index/_type/ POST { "tabTitle": "森图表_test", "chtTabTitle": "森图表_test", "status": 0 } 注意&#xff1a;Elasticsearch 6.0.0及更高版本中&#xff0c;索引只能包含一个映射类型

springboot养老院信息管理系统-计算机设计毕业源码30958

目 录 摘要 1绪论 1.1 研究背景 1.2 研究意义 1.3论文结构与章节安排 2 系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据新增流程 2.2.2 数据删除流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分析 2.5本章小结 3 系统总体设…

OkHttp网络请求框架

添加依赖 在 build.gradle 文件中添加 OkHttp 依赖&#xff1a; dependencies {implementation("com.squareup.okhttp3:okhttp:4.10.0") }使用OkHttp发起GET请求 同步请求 public class MainActivity extends AppCompatActivity {// Used to load the okhttptes…

基于sealos部署的集群部署dashboard

1、下载yaml文件进行部署 rootmaster-1:~# wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml2、修改service的访问模式 rootmaster-1:~# vim recommended.yaml kind: Service apiVersion: v1 metadata:labels:k8s-app: kube…

手机贴膜气泡识别组件定位图像分割系统:快速图像识别

手机贴膜气泡识别组件定位图像分割系统源码&#xff06;数据集分享 [yolov8-seg-C2f-Parc&#xff06;yolov8-seg-KernelWarehouse等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge …

C语言 | Leetcode C语言题解之第538题把二叉搜索树转换为累加树

题目&#xff1a; 题解&#xff1a; struct TreeNode* getSuccessor(struct TreeNode* node) {struct TreeNode* succ node->right;while (succ->left ! NULL && succ->left ! node) {succ succ->left;}return succ; }struct TreeNode* convertBST(stru…

SQL--查询连续三天登录数据详解

问题&#xff1a; 现有用户登录记录表&#xff0c;请查询出用户连续三天登录的所有数据记录 id dt1 2024-04-25 1 2024-04-26 1 2024-04-27 1 2024-04-28 1 2024-04-30 1 2024-05-01 1 2024-05-02 1 2024-05-04 1 2024-05-05 2 20…

数据结构和算法-01背包问题01-认识01背包

0-1背包 什么是0-1背包问题&#xff1f; [0-1背包问题Knapsack Problem] 假设有一个背包&#xff0c;可承载的最大重量是W(kg)&#xff0c; 现在有n个物品&#xff0c;每个物品的重量不等&#xff0c; 并且不可分割。我们期待选择几件物品放入背包中&#xff0c;在不超过背包最…

go-carbon 和 gorm 优雅处理数据库日期时间

一、简介 (一) carbon carbon 是一个简单、语义化、开发人员友好的 golang 时间包。carbon 提供了丰富的日期和时间处理功能&#xff0c;使得日期和时间操作更加简单和直观。 (二) gorm gorm 是一个用于 Go 语言的 ORM&#xff08;对象关系映射&#xff09;框架。它提供了简…

Java 抽象类 详解

文章目录 一、概述1.1、什么是抽象类1.2、定义抽象类1.3、什么是抽象方法1.4、定义抽象方法 二、特点2.1、抽象类的特点2.1.1、抽象类不可以实例化对象2.1.2、抽象类必须要被继承2.1.3、抽象类的子类2.1.4、抽象类的成员 2.2、抽象方法的特点2.2.1、只能有方法声明&#xff0c;…

A20红色革命文物征集管理系统

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…

SpringBoot Java教学工具:创新教育体验

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理教学辅助平台的相关信息成为必然。开发合适…

VisionPro —— CogIPOneImgeTool工具详解

CogIPOneImageTool工具主要用来对单张图像进行算法处理操作 CogIPOneImgeTool简介 CogIPOneImageTool 工具可完成高斯平滑、高通滤波和图像量化等基本图像处理操作。Image Processing One Image 工具编辑控件为此工具提供图形用户界面。 Image Processing Operations (图像处…

WPF+MVVM案例实战与特效(二十四)- 粒子字体效果实现

文章目录 1、案例效果2、案例实现1、文件创建2.代码实现3、界面与功能代码3、总结1、案例效果 提示:这里可以添加本文要记录的大概内容: 2、案例实现 1、文件创建 打开 Wpf_Examples 项目,在 Views 文件夹下创建窗体界面 ParticleWindow.xaml,在 Models 文件夹下创建粒子…