滑块验证码组件必须自行实现,不可依赖第三方UI库。因各端canvas渲染、touch事件、图片缩放差异大,需统一使用uni.createCanvasContext,严格保证背景图与缺口图同源同尺寸,blockX/blockY由后端返回,前端仅归一化上报拖动结果。

滑块组件必须自己写,别直接套第三方 UI 库
uni-app 里没有开箱即用、多端一致的滑块验证码组件。所谓“UI 库内置”基本是 H5 可用、小程序崩、App 错位——因为 canvas 渲染逻辑、touch 事件行为、图片缩放策略在各端差异太大。uni.createCanvasContext 是唯一靠谱的绘制入口,但必须手动控制裁剪、贴图、坐标对齐。第三方封装往往把 clip() 和 drawImage 封装成黑盒,一到 iOS 真机或鸿蒙就裁剪失效,缺口对不上。
- 背景图和缺口图必须同源、同尺寸、同缩放比例,否则像素级比对失效
- 缺口 Y 坐标(
blockY)必须由后端返回,前端不能自行估算或固定值 - H5 用
canvas type="2d",小程序/APP 必须用canvas-id+uni.createCanvasContext,不能混用 - 安卓真机上网络图直传
drawImage容易加载失败,得先uni.downloadFile缓存再读本地路径
touch 位移计算要防抖 + 限界 + 归一化
用户手指一滑,touchmove 每秒触发几十次,不处理就会卡顿、上报冗余数据。关键不是“拖到哪”,而是“拖动终点是否落在容差范围内”。
- 在
touchstart记下初始clientX和滑块当前left值(比如 0) -
touchmove中实时计算deltaX = clientX - startX,然后newLeft = Math.max(0, Math.min(initialLeft + deltaX, maxWidth)) -
touchend时才计算归一化偏移:normalized = parseFloat((newLeft / maxWidth).toFixed(3)),保留三位小数防浮点误差 - maxWidth 必须是背景图实际渲染宽度(非 rpx 值),需用
uni.upx2px(300)或uni.getSystemInfoSync().windowWidth动态算
canvas 绘制缺口的两种可靠方式
iOS 真机上 clip() 经常失效,尤其配合 scale 缩放时。不能只依赖一种方案,得按平台 fallback。
- 首选:用
ctx.beginPath() → ctx.rect(x, y, w, h) → ctx.clip(),画完背景图后再贴缺口图 - fallback:当检测到 iOS 或裁剪异常时,改用
ctx.globalCompositeOperation = 'destination-out',先画背景图,再用透明矩形“擦出”缺口区域 - 缺口图(
sliderImg)必须和背景图来自同一张原始图、同一裁剪坐标,否则拼不上 - 滑块 DOM 元素(可拖拽的那块小图)只负责视觉反馈,不参与 canvas 绘制;它的
left值随 touch 实时更新即可
后端返回字段一个都不能少
前端所有“看起来可以自己定”的值,其实都得和服务端强绑定。漏掉任意一个,验证就形同虚设。
-
bg:背景图 base64 或同源 URL(避免跨域限制) -
slider:缺口图 base64(必须和 bg 同源同批生成) -
blockX:缺口左边缘在背景图中的真实像素横坐标(后端生成时记录) -
blockY:缺口顶部纵坐标(决定拼图块垂直位置) -
token或captchaId:本次验证会话标识,提交时必须原样带上,用于后端查表比对
blockX 是校验核心,但前端绝不参与“计算正确答案”,只负责把用户拖动后的 normalized 值 + token 一起发过去。任何在前端算 Math.abs(blockX - userX) 的做法都是自欺欺人。










