UNPKG

@oiij/use

Version:

Som Composable Functions for Vue 3

140 lines (138 loc) 4.05 kB
import { useEventListener } from "@vueuse/core"; import { computed, onMounted, ref } from "vue"; //#region src/composables/use-image-verify.ts function randomNum(min, max) { const num = Math.floor(Math.random() * (max - min) + min); return num; } function randomColor(min, max) { const r = randomNum(min, max); const g = randomNum(min, max); const b = randomNum(min, max); return `rgb(${r},${g},${b})`; } function drawLine(ctx, width, height, length) { for (let i = 0; i < length; i += 1) { ctx.beginPath(); ctx.moveTo(randomNum(0, width), randomNum(0, height)); ctx.lineTo(randomNum(0, width), randomNum(0, height)); ctx.strokeStyle = randomColor(180, 230); ctx.closePath(); ctx.stroke(); } } function drawPoint(ctx, width, height, length) { for (let i = 0; i < length; i += 1) { ctx.beginPath(); ctx.arc(randomNum(0, width), randomNum(0, height), 1, 0, 2 * Math.PI); ctx.closePath(); ctx.fillStyle = randomColor(150, 200); ctx.fill(); } } function useImageVerify(options = { type: "character" }) { const { width = 120, height = 40, refreshOnClick = true, disturbLine = 10, disturbPoint = 40 } = options ?? {}; const domRef = ref(); const value = ref(""); const code = ref(""); const passed = computed(() => value.value.toUpperCase() === code.value.toUpperCase()); function validate() { return new Promise((resolve, reject) => passed.value ? resolve(true) : reject(/* @__PURE__ */ new Error("Failed to verify."))); } function reset() { value.value = ""; } function refresh() { generate(); } function generate() { const _code = _draw(); code.value = _code; return _code; } function _draw() { let imgCode = ""; const ctx = domRef.value?.getContext("2d"); if (!ctx) return imgCode; ctx.fillStyle = randomColor(180, 230); ctx.fillRect(0, 0, width, height); if (options?.type === "character") { const { length = 4, characterPool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" } = options?.config ?? {}; for (let i = 0; i < length; i += 1) { const text = characterPool[randomNum(0, characterPool.length)]; imgCode += text; ctx.fillStyle = randomColor(50, 160); ctx.font = `${randomNum(height * 2 / 4, height * 3 / 4)}px SimHei`; ctx.textBaseline = "top"; const x = i * ((width - 10) / length); const y = randomNum(5, height / 4); ctx.fillText(text, x + 5, y); } } if (options?.type === "operation") { const { figure = 10, arith } = options?.config ?? {}; let num1 = Math.floor(Math.random() * figure); let num2 = Math.floor(Math.random() * figure); let codeShow = ""; const _arith = arith ?? [ "+", "-", "*" ][Math.floor(Math.random() * 3)]; switch (_arith) { case "+": imgCode = (num1 + num2).toString(); codeShow = `${num1} + ${num2} = ?`; break; case "-": if (num1 < num2) { const tempNum = num1; num1 = num2; num2 = tempNum; } imgCode = (num1 - num2).toString(); codeShow = `${num1} - ${num2} = ?`; break; case "*": imgCode = (num1 * num2).toString(); codeShow = `${num1} × ${num2} = ?`; break; } for (let i = 0; i < codeShow.length; i += 1) { const text = codeShow[i]; ctx.fillStyle = randomColor(50, 160); ctx.font = `${randomNum(height * 2 / 4, height * 3 / 4)}px SimHei`; ctx.textBaseline = "top"; const x = i * ((width - 10) / codeShow.length); const y = randomNum(5, height / 4); ctx.fillText(text, x + 5, y); } } drawLine(ctx, width, height, disturbLine); drawPoint(ctx, width, height, disturbPoint); return imgCode; } useEventListener(domRef, "click", () => { if (refreshOnClick) generate(); }); onMounted(() => { if (domRef.value) { domRef.value.width = width; domRef.value.height = height; domRef.value.style.width = `${width}px`; domRef.value.style.height = `${height}px`; generate(); } }); return { domRef, value, code, passed, validate, reset, refresh }; } //#endregion export { useImageVerify };