feat: 增加基于图片拼图切片平移的验证码
parent
8554924cb9
commit
bbd8a53d9d
|
@ -3,4 +3,5 @@ export { default as PointSelectionCaptchaCard } from './point-selection-captcha/
|
|||
|
||||
export { default as SliderCaptcha } from './slider-captcha/index.vue';
|
||||
export { default as SliderRotateCaptcha } from './slider-rotate-captcha/index.vue';
|
||||
export { default as SliderTranslateCaptcha } from './slider-translate-captcha/index.vue';
|
||||
export type * from './types';
|
||||
|
|
|
@ -127,7 +127,12 @@ function resetCanvas() {
|
|||
if (!puzzleCanvas || !pieceCanvas) return;
|
||||
pieceCanvas.width = canvasWidth;
|
||||
const puzzleCanvasCtx = puzzleCanvas.getContext('2d');
|
||||
const pieceCanvasCtx = pieceCanvas.getContext('2d');
|
||||
// Canvas2D: Multiple readback operations using getImageData
|
||||
// are faster with the willReadFrequently attribute set to true.
|
||||
// See: https://html.spec.whatwg.org/multipage/canvas.html#concept-canvas-will-read-frequently (anonymous)
|
||||
const pieceCanvasCtx = pieceCanvas.getContext('2d', {
|
||||
willReadFrequently: true,
|
||||
});
|
||||
if (!puzzleCanvasCtx || !pieceCanvasCtx) return;
|
||||
puzzleCanvasCtx.clearRect(0, 0, canvasWidth, canvasHeight);
|
||||
pieceCanvasCtx.clearRect(0, 0, canvasWidth, canvasHeight);
|
||||
|
@ -139,9 +144,16 @@ function initCanvas() {
|
|||
const pieceCanvas = unref(pieceCanvasRef);
|
||||
if (!puzzleCanvas || !pieceCanvas) return;
|
||||
const puzzleCanvasCtx = puzzleCanvas.getContext('2d');
|
||||
const pieceCanvasCtx = pieceCanvas.getContext('2d');
|
||||
// Canvas2D: Multiple readback operations using getImageData
|
||||
// are faster with the willReadFrequently attribute set to true.
|
||||
// See: https://html.spec.whatwg.org/multipage/canvas.html#concept-canvas-will-read-frequently (anonymous)
|
||||
const pieceCanvasCtx = pieceCanvas.getContext('2d', {
|
||||
willReadFrequently: true,
|
||||
});
|
||||
if (!puzzleCanvasCtx || !pieceCanvasCtx) return;
|
||||
const img = new Image();
|
||||
// 解决跨域
|
||||
img.crossOrigin = 'Anonymous';
|
||||
img.src = src;
|
||||
img.addEventListener('load', () => {
|
||||
draw(puzzleCanvasCtx, pieceCanvasCtx);
|
||||
|
@ -158,6 +170,7 @@ function initCanvas() {
|
|||
);
|
||||
pieceCanvas.width = pieceLength;
|
||||
pieceCanvasCtx.putImageData(imageData, 0, sy);
|
||||
setLeft('0');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -265,7 +278,7 @@ onMounted(() => {
|
|||
@click="resume"
|
||||
></canvas>
|
||||
<div
|
||||
class="absolute bottom-3 left-0 z-10 block h-7 w-full text-center text-xs leading-[30px] text-white"
|
||||
class="h-15 absolute bottom-3 left-0 z-10 block w-full text-center text-xs leading-[30px] text-white"
|
||||
>
|
||||
<div
|
||||
v-if="state.showTip"
|
||||
|
|
|
@ -159,6 +159,42 @@ export interface SliderRotateCaptchaProps {
|
|||
defaultTip?: string;
|
||||
}
|
||||
|
||||
export interface SliderTranslateCaptchaProps {
|
||||
/**
|
||||
* @description 拼图的宽度
|
||||
* @default 420
|
||||
*/
|
||||
canvasWidth?: number;
|
||||
/**
|
||||
* @description 拼图的高度
|
||||
* @default 280
|
||||
*/
|
||||
canvasHeight?: number;
|
||||
/**
|
||||
* @description 切块上正方形的长度
|
||||
* @default 42
|
||||
*/
|
||||
squareLength?: number;
|
||||
/**
|
||||
* @description 切块上圆形的半径
|
||||
* @default 10
|
||||
*/
|
||||
circleRadius?: number;
|
||||
/**
|
||||
* @description 图片的地址
|
||||
*/
|
||||
src?: string;
|
||||
/**
|
||||
* @description 允许的最大差距
|
||||
* @default 3
|
||||
*/
|
||||
diffDistance?: number;
|
||||
/**
|
||||
* @description 默认提示文本
|
||||
*/
|
||||
defaultTip?: string;
|
||||
}
|
||||
|
||||
export interface CaptchaVerifyPassingData {
|
||||
isPassing: boolean;
|
||||
time: number | string;
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
"pointSelection": "Point Selection Captcha",
|
||||
"sliderCaptcha": "Slider Captcha",
|
||||
"sliderRotateCaptcha": "Rotate Captcha",
|
||||
"sliderTranslateCaptcha": "Translate Captcha",
|
||||
"captchaCardTitle": "Please complete the security verification",
|
||||
"pageDescription": "Verify user identity by clicking on specific locations in the image.",
|
||||
"pageTitle": "Captcha Component Example",
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
"pointSelection": "点选验证",
|
||||
"sliderCaptcha": "滑块验证",
|
||||
"sliderRotateCaptcha": "旋转验证",
|
||||
"sliderTranslateCaptcha": "拼图滑块验证",
|
||||
"captchaCardTitle": "请完成安全验证",
|
||||
"pageDescription": "通过点击图片中的特定位置来验证用户身份。",
|
||||
"pageTitle": "验证码组件示例",
|
||||
|
|
|
@ -196,6 +196,15 @@ const routes: RouteRecordRaw[] = [
|
|||
title: $t('examples.captcha.sliderRotateCaptcha'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'TranslateVerifyExample',
|
||||
path: '/examples/captcha/slider-translate',
|
||||
component: () =>
|
||||
import('#/views/examples/captcha/slider-translate-captcha.vue'),
|
||||
meta: {
|
||||
title: $t('examples.captcha.sliderTranslateCaptcha'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'CaptchaPointSelectionExample',
|
||||
path: '/examples/captcha/point-selection',
|
||||
|
|
Loading…
Reference in New Issue