当前位置: 首页 > news >正文

Vue 使用接口返回的背景图片和拼图图片进行滑动拼图验证

一、背景

前两天发了一篇 vue-monoplasty-slide-verify 滑动验证码插件使用及踩坑_vue-monoplasty-slide-verify 引用后不显示-CSDN博客

这两天项目又需要通过接口校验,接口返回了背景图片和拼图图片,于是在网上找了一篇帖子,vue + 图片滑动验证_基于vue图片滑动验证-CSDN博客

写的不错,代码拿过来就能用;但是感觉源码和vue-monoplasty-slide-verify的比较像,vue-monoplasty-slide-verify的icon图片拿过来直接就能在参考帖子里用。

二、获取验证码接口返回数据示例

三、校验接口返回数据示例

 

四、封装与后端配合的滑动组件

//在参考帖基础上修改的
<template><div><el-dialog :visible.sync="showSlideVerify" title="向右滑动通过验证" :width=" w +48 + 'px'" :close-on-click-modal="false" :close-on-press-escape="false"><div class="slide-verify" :style="{width: w + 'px'}" id="slideVerify" onselectstart="return false;"><!-- 图片加载遮蔽罩 --><div :class="{'slider-verify-loading': loadBlock}"></div><canvas :width="w" :height="h" ref="canvas"></canvas><div v-if="showRefresh" @click="refresh" class="slide-verify-refresh-icon"></div><canvas :width="block_width" :height="h" ref="block" class="slide-verify-block"></canvas><!-- container --><div class="slide-verify-slider" :class="{'container-active': containerActive, 'container-success': containerSuccess, 'container-fail': containerFail}"><div class="slide-verify-slider-mask" :style="{width: sliderMaskWidth}"><!-- slider --><div @mousedown="sliderDown" @touchstart="touchStartEvent" @touchmove="touchMoveEvent" @touchend="touchEndEvent" class="slide-verify-slider-mask-item" :style="{left: sliderLeft}"><div class="slide-verify-slider-mask-item-icon"></div></div></div><span class="slide-verify-slider-text">{{sliderText}}</span></div></div></el-dialog></div></template>
<script>
import { getCanvasAndPuzzle, checkPuzzle } from '@/api/modules/setting'export default {name: 'SlideVerify',props: {sliderText: {type: String,default: '向右滑动'},showRefresh: {type: Boolean,default: true}},data () {return {showSlideVerify: false,containerActive: false, // container active classcontainerSuccess: false, // container success classcontainerFail: false, // container fail classnonceStr: '',canvasCtx: null,blockCtx: null,block: null,block_src: undefined,block_y: undefined,block_width: undefined,block_height: undefined,block_radius: undefined,w: 0,h:0,img: undefined,originX: undefined,originY: undefined,isMouseDown: false,trail: [],sliderLeft: 0, // block right offsetsliderMaskWidth: 0, // mask width,success: false, // Bug Fixes 修复了验证成功后还能滑动loadBlock: true, // Features 图片加载提示,防止图片没加载完就开始验证timestamp: null}},methods: {show () {Object.assign(this.$data, {success: false,containerActive: false,containerSuccess: false,containerFail: false,nonceStr: '',w: 0,h: 0,img: undefined,loadBlock: true,block_src: undefined,block_y: undefined,block_width: undefined,block_height: undefined,block_radius: undefined,sliderLeft: 0,sliderMaskWidth: 0});this.getCanvasAndPuzzle();},getCanvasAndPuzzle () { //从接口获取滑动组件背景图片、图片宽高与拼图图片、拼图宽高、block_radius、垂直方向上的位置getCanvasAndPuzzle().then(res => {Object.assign(this.$data, {nonceStr: res.data.nonceStr, //根据接口的校验逻辑,校验时需传递给后台w: res.data.canvasWidth,h: res.data.canvasHeight,img: res.data.canvasSrc,block_src: res.data.blockSrc,block_y: res.data.blockY,block_width: res.data.blockWidth,block_height: res.data.blockHeight,block_radius: res.data.blockRadius,showSlideVerify: true});this.$nextTick(() => {this.init();});}).catch(error => {this.$message.error(error);});},init () {this.initDom();this.initImg();this.bindEvents();},initDom () {this.block = this.$refs.block;this.canvasCtx = this.$refs.canvas.getContext('2d');this.blockCtx = this.block.getContext('2d');},initImg () {let _this = this, image = new Image(), blockImage = new Image();image.src = this.img;blockImage.src = this.block_src;image.onload = () => {_this.canvasCtx.drawImage(image, 0, 0, _this.w, _this.h);};blockImage.onload = () => {_this.loadBlock = false;// 第二个、三个参数分别是被拖动的拼图在水平、垂直方向的偏移量_this.blockCtx.drawImage(blockImage, 0, _this.block_y, _this.block_width, _this.block_height);};},sliderDown (event) {if (this.success) return;this.originX = event.clientX;this.originY = event.clientY;this.isMouseDown = true;this.timestamp = + new Date();},touchStartEvent (e) {if (this.success) return;this.originX = e.changedTouches[0].pageX;this.originY = e.changedTouches[0].pageY;this.isMouseDown = true;this.timestamp = + new Date();},bindEvents () {document.addEventListener('mousemove', (e) => {if (!this.isMouseDown) return false;const moveX = e.clientX - this.originX;const moveY = e.clientY - this.originY;if (moveX < 0 || moveX + 38 >= this.w) return false;this.sliderLeft = moveX + 'px';let blockLeft = (this.w - 40 - 20) / (this.w - 40) * moveX;this.block.style.left = blockLeft + 'px';this.containerActive = true;this.sliderMaskWidth = moveX + 'px';this.trail.push(moveY);});document.addEventListener('mouseup', (e) => {if (!this.isMouseDown) return false;this.isMouseDown = false;if (e.clientX === this.originX) return false;this.containerActive = false;this.timestamp = + new Date() - this.timestamp;this.verify();});},touchMoveEvent (e) {if (!this.isMouseDown) return false;const moveX = e.changedTouches[0].pageX - this.originX;const moveY = e.changedTouches[0].pageY - this.originY;if (moveX < 0 || moveX + 38 >= this.w) return false;this.sliderLeft = moveX + 'px';let blockLeft = (this.w - 40 - 20) / (this.w - 40) * moveX;this.block.style.left = blockLeft + 'px';this.containerActive = true;this.sliderMaskWidth = moveX + 'px';this.trail.push(moveY);},touchEndEvent (e) {if (!this.isMouseDown) return false;this.isMouseDown = false;if (e.changedTouches[0].pageX === this.originX) return false;this.containerActive = false;this.timestamp = + new Date() - this.timestamp;this.verify();},verify () {
//将拼图水平方向拖动量传递给接口,接口来校验是否拼好返回校验结果,我也不是很理解这个操作,但没办法,就让这样做,只能自己网上找例子,然后改出来了checkPuzzle({nonceStr: this.nonceStr,value: parseInt(this.block.style.left) //被拖动拼图在水平方向上的移动量}).then(res => {if(res.code===-1 || !res.data) {//校验通过,res.data的值为true,否则为falsethis.containerFail = true;this.$message.error(res.message);this.refresh();} else {this.$emit('verify-success');Object.assign(this.$data, {containerSuccess: true,success: true,showSlideVerify: false});}}).catch(error => {this.$message.error(error);});},refresh () {let { w, h, block_width } = this;this.canvasCtx.clearRect(0, 0, w, h);this.blockCtx.clearRect(0, 0, block_width, h);this.block.style.left = 0;Object.assign(this.$data, {success: false,containerActive: false,containerSuccess: false,containerFail: false,nonceStr: '',img: undefined,loadBlock: true,sliderLeft: 0,sliderMaskWidth: 0});this.getCanvasAndPuzzle();}}
}
</script>
<style scoped>
.slide-verify {position: relative;
}/* 图片加载样式 */
.slider-verify-loading {position: absolute;top: 0;right: 0;left: 0;bottom: 0;background: rgba(255, 255, 255, 0.9);z-index: 999;animation: loading 1.5s infinite;
}@keyframes loading {0% {opacity: 0.7;}100% {opacity: 9;}
}.slide-verify-block {position: absolute;left: 0;top: 0;
}.slide-verify-refresh-icon {position: absolute;right: 0;top: 0;width: 34px;height: 34px;cursor: pointer;background: url('./imgs/icon.png') 0 -437px;background-size: 34px 471px;
}.slide-verify-slider {position: relative;text-align: center;width: 100%;height: 40px;line-height: 40px;/* margin-top: 15px; */background: #f7f9fa;color: #45494c;border: 1px solid #e4e7eb;
}.slide-verify-slider-mask {position: absolute;left: 0;top: 0;height: 40px;border: 0 solid #1991fa;background: #d1e9fe;
}.slide-verify-slider-mask-item {position: absolute;top: 0;left: 0;width: 40px;height: 40px;background: #fff;box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);cursor: pointer;transition: background 0.2s linear;
}.slide-verify-slider-mask-item:hover {background: #1991fa;
}.slide-verify-slider-mask-item:hover .slide-verify-slider-mask-item-icon {background-position: 0 -13px;
}.slide-verify-slider-mask-item-icon {position: absolute;top: 15px;left: 13px;width: 14px;height: 12px;background: url('./imgs/icon.png') 0 -26px;background-size: 34px 471px;
}
.container-active .slide-verify-slider-mask-item {height: 38px;top: -1px;border: 1px solid #1991fa;
}.container-active .slide-verify-slider-mask {height: 38px;border-width: 1px;
}.container-success .slide-verify-slider-mask-item {height: 38px;top: -1px;border: 1px solid #52ccba;background-color: #52ccba !important;
}.container-success .slide-verify-slider-mask {height: 38px;border: 1px solid #52ccba;background-color: #d2f4ef;
}.container-success .slide-verify-slider-mask-item-icon {background-position: 0 0 !important;
}.container-fail .slide-verify-slider-mask-item {height: 38px;top: -1px;border: 1px solid #f57a7a;background-color: #f57a7a !important;
}.container-fail .slide-verify-slider-mask {height: 38px;border: 1px solid #f57a7a;background-color: #fce1e1;
}.container-fail .slide-verify-slider-mask-item-icon {top: 14px;background-position: 0 -82px !important;
}.container-active .slide-verify-slider-text,
.container-success .slide-verify-slider-text,
.container-fail .slide-verify-slider-text {display: none;
}
</style>

五、 接口

意义不太大,要根据项目实际情况来的

 六、CSS 代码里用到的图片资源

https://download.csdn.net/download/hrcsdn13/89709217

七、CSS与组件文件位置

八、效果图

相关文章:

Vue 使用接口返回的背景图片和拼图图片进行滑动拼图验证

一、背景 前两天发了一篇 vue-monoplasty-slide-verify 滑动验证码插件使用及踩坑_vue-monoplasty-slide-verify 引用后不显示-CSDN博客 这两天项目又需要通过接口校验&#xff0c;接口返回了背景图片和拼图图片&#xff0c;于是在网上找了一篇帖子&#xff0c;vue 图片滑动…...

1-7 掩膜的运用 opencv树莓派4B 入门系列笔记

目录 一、提前准备 二、代码详解 num_pixels np.sum(mask 255) contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) c max(contours, keycv2.contourArea) x, y, w, h cv2.boundingRect(c) M cv2.moments(contours[0]) if contours…...

EG边缘计算网关连接华为云物联网平台(MQTT协议)

需求概述 实现一个流程&#xff1a;EG8200mini采集Modbus RTU数据&#xff0c;通过MQTT协议连接华为云物联网平台 Modbus RTU采集此处不做过多赘述&#xff0c;可参考其他案例&#xff08;串口读取Modbus传感器数据&#xff09;介绍。下文默认已经采集到Modbus RTU数据。 要…...

List中常见的方法和五种遍历方式

有序&#xff1a;存取的顺序一致 有索引&#xff1a;可以通过索引操作元素 可重复&#xff1a;存储的元素可以重复 package mylist;import java.util.ArrayList; import java.util.List;public class A01_LIstDemo1 {public static void main(String[] args) {List<String…...

华为 HCIP-Datacom H12-821 题库 (8)

有需要题库的可以看主页置顶 1.在 DHCP 运行过程中&#xff0c;如果客户端 IP 地址在相约过去 87.5%还没有完成续约的话&#xff0c;客户将发送什么报文进行再次续约&#xff1f; A、DHCP discover 广播报文 B、DHCP release 单播报文 C、DHCP request 广播报文 D、DHCP reques…...

12. GIS地图制图工程师岗位职责、技术要求和常见面试题

本系列文章目录&#xff1a; 1. GIS开发工程师岗位职责、技术要求和常见面试题 2. GIS数据工程师岗位职责、技术要求和常见面试题 3. GIS后端工程师岗位职责、技术要求和常见面试题 4. GIS前端工程师岗位职责、技术要求和常见面试题 5. GIS工程师岗位职责、技术要求和常见面试…...

ORACLE 统计信息的备份与恢复

备份 --需要先创建统计信息基础表 exec dbms_stats.create_stat_table(USER1,STAT_TIMESTAMP); --导出某个用户的所有统计信息 exec dbms_stats.export_schema_stats(USER1,STAT_TIMESTAMP);--测试(插入100条&#xff0c;更新统计信息&#xff0c;略) select num_rows,last_ana…...

2. GIS数据工程师岗位职责、技术要求和常见面试题

本系列文章目录&#xff1a; 1. GIS开发工程师岗位职责、技术要求和常见面试题 2. GIS数据工程师岗位职责、技术要求和常见面试题 3. GIS后端工程师岗位职责、技术要求和常见面试题 4. GIS前端工程师岗位职责、技术要求和常见面试题 5. GIS工程师岗位职责、技术要求和常见面试…...

Spark MLlib模型训练—文本算法 LDA(Latent Dirichlet Allocation)

Spark MLlib模型训练—文本算法 LDA(Latent Dirichlet Allocation) Latent Dirichlet Allocation(LDA)是一种用于主题建模的生成式概率模型,广泛应用于文本分析和自然语言处理。LDA 的目标是从一组文档中发现潜在的主题,并将每个文档表示为这些主题的概率分布。它通过推断…...

C++ ─── List的模拟实现

目录 ​编辑 一&#xff0c; List的模拟实现 二&#xff0c;代码实现 三、list和vector的区别 一&#xff0c; List的模拟实现 List 是一个双向循环链表,由于List的节点不连续&#xff0c;不能用节点指针直接作为迭代器&#xff0c;因此我们要对结点指针封装&#xff0c;来…...

Spring Boot详解

好的&#xff01;Spring Boot 是一个基于 Spring 框架的项目&#xff0c;它为简化配置、快速启动项目而生。它使得构建独立运行、生产级别的 Spring 应用变得非常简单&#xff0c;让开发者专注于业务逻辑而不再被繁琐的配置所困扰。接下来&#xff0c;我将从以下几个方面为你详…...

Proxfier+burpsuite抓包配置问题

1、burp证书配置 导出证书 后缀为cer 打开浏览器设置 搜索证书--》点安全 管理证书 在圈起来的三个地方添加证书 2、Proxifer配置 配置代理服务器 配置ip和port 配置代理规则 注意画圈部分...

sqli-lab靶场学习(一)——Less1-4

前言 最近一段时间想切入安全领域&#xff0c;因为本身有做数据库运维工作&#xff0c;就打算从sql注入方向切入。而sql注入除了学习日常书本上的概念外&#xff0c;需要有个实践的环境&#xff0c;刚好看到sqli-lab这个靶场&#xff0c;就打算先用这个来学习。 安装部署 网上…...

el-select如何同时获取value和label?

在element ui 中 下拉框默认获取下拉框value的值&#xff0c;但是有时候根据 业务需求&#xff0c;我们需要label值也发送给后端&#xff0c;在这提供一下获取value、和label 的方式 1、在给el-option绑定:value值时使用对象的方式&#xff0c;将value和label同时绑定到:value…...

1.初识ChatGPT:AI聊天机器人的革命(1/10)

引言 在当今的数字化世界中&#xff0c;人工智能&#xff08;AI&#xff09;正以其独特的方式重塑我们的生活和工作。其中&#xff0c;AI聊天机器人作为人机交互的前沿技术&#xff0c;已经成为企业与客户沟通、提供个性化服务的重要工具。这些机器人通过模拟人类的对话方式&a…...

API安全 | 发现API的5个小tips

在安全测试目标时&#xff0c;最有趣的测试部分是它的 API。API 是动态的&#xff0c;它们比应用程序的其他部分更新得更频繁&#xff0c;并且负责许多后端繁重的工作。在现代应用程序中&#xff0c;我们通常会看到 REST API&#xff0c;但也会看到其他形式&#xff0c;例如 Gr…...

数据结构---单向链表

单向链表 //链表的创建 Link_t *create_link() {Link_t *plink malloc(sizeof(Link_t));if(NULL plink){perror("fail plink");return NULL;}plink->phead NULL;plink->clen 0;return plink; } //头插 int push_link_head(Link_t *plink, DataType data…...

基于STM32设计的ECG+PPG人体参数测量系统(华为云IOT)(217)

文章目录 一、前言1.1 项目介绍【1】开发背景【2】项目实现的功能【3】项目硬件模块组成1.2 设计思路【1】整体设计思路【2】整体构架【3】上位机开发思路【4】ESP8266工作模式配置1.3 项目开发背景【1】选题的意义【2】可行性分析【3】参考文献【4】摘要【5】项目背景1.4 开发…...

SpringBoot教程(十五) | SpringBoot集成RabbitMq(死信队列、延迟队列)

SpringBoot教程&#xff08;十五&#xff09; | SpringBoot集成RabbitMq&#xff08;死信队列、延迟队列&#xff09; &#xff08;一&#xff09;死信队列使用场景具体用法前提示例: &#xff08;二&#xff09;延迟队列使用场景方法一&#xff1a;通过死亡队列实现方法二&…...

Dubbo依赖包

Dubbo 是一个高性能的 RPC 框架&#xff0c;用于构建分布式服务治理系统。要使用 Dubbo&#xff0c;项目中需要引入一些关键的依赖包。这些依赖包提供了 Dubbo 的核心功能、服务注册与发现、网络通信、序列化等能力。 一、Dubbo 核心依赖包 Dubbo 的核心依赖包包含了实现 RPC…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...