必须用 touch 事件 + canvas + 后端双图下发实现跨端滑块验证,因 movable-view 无法满足像素级对齐、归一化计算和多端一致性要求,前端不得生成缺口或裁剪图片,所有资源须由后端返回并严格校验会话 token。

不能直接套用 Web SDK,必须用 touch 事件 + canvas + 后端双图下发才能真正跨端可用。 所有“前端生成缺口”“本地裁剪图片”的做法,在 iOS 小程序或安卓 App 上都会因 canvas 跨域、drawImage 加载失败、clip 行为不一致而崩;动态图片也必须由后端返回 base64 或同源 URL,不能前端拼接路径。
为什么 movable-view 不适合做滑块验证主体
它只提供位移值,不提供像素级拖动过程、无法绑定背景图与缺口图的对齐关系,更没法做归一化偏移比计算。真机上常见问题包括:movable-view 在某些安卓机型上拖拽卡顿、iOS 小程序中 @change 频率极低、松手时 e.detail.x 值跳变。它适合 Tab 滑块,但不适合需要像素级校验的验证码场景。
- 滑块位移必须和背景图宽度严格映射(比如 0~280px 对应 0%~100%),而
movable-view的x是绝对像素,不同屏幕下无法统一容差范围 - 缺口图和背景图的 Y 轴对齐必须精确到像素,
movable-view无法驱动 canvas 内部的clip()或globalCompositeOperation动态重绘 - 用户拖动过程中需实时反馈对齐状态(如阴影渐变、边缘高亮),这些视觉反馈只能靠 canvas draw 或自定义
view层叠实现,不是movable-view能承载的
如何用 canvas 渲染动态背景图和缺口图
关键不是“画出来”,而是“怎么让两张图在不同端都严丝合缝”。所有图片资源必须由后端一次性返回:backgroundImg(背景图 base64)、sliderImg(缺口图 base64)、blockX(缺口横坐标)、blockY(缺口纵坐标)、pieceWidth、pieceHeight。前端不做任何裁剪或缩放计算。
-
canvas宽高必须显式设置 CSS 和 canvas 属性(如style="width: 280px; height: 140px;"+canvas-width="280"+canvas-height="140"),否则 H5 和小程序渲染比例错乱 - 安卓真机加载网络图易失败,务必先
uni.downloadFile缓存到tempFilePath,再传给ctx.drawImage - iOS 小程序
clip()可能失效,改用ctx.globalCompositeOperation = 'destination-out':先画背景图,再画一个半透明黑色矩形覆盖缺口区域,最后把缺口图贴上去 - 缺口图只渲染一次,拖动时仅更新其
left值(用position: absolute定位),不要每帧重绘 canvas —— 否则性能暴跌
怎么捕获真实拖动偏移并适配多端屏幕
必须用 touchstart/touchmove/touchend 手动计算 clientX 差值,而不是依赖任何封装事件。因为 touchmove 的触发频率和精度,是唯一能反映人手真实拖拽节奏的信号。
- 记录
touchstart的e.touches[0].clientX为起点,每次touchmove计算当前clientX - startX,得到原始像素偏移dragX - 限制最大拖动范围:
dragX = Math.max(0, Math.min(dragX, trackWidth - sliderWidth)),其中trackWidth是背景图实际渲染宽度(非屏幕宽度) - 最终提交给后端的不是
dragX,而是归一化比值:userOffset = dragX / (trackWidth - sliderWidth),这样后端按相同比例反推原始像素位置,不受设备 DPI 影响 - 别信
event.target.offsetLeft或getBoundingClientRect(),它们在小程序里返回值不可靠;所有坐标计算必须基于 touch 事件原生clientX
最易被忽略的是:动态图片每次请求必须携带唯一 token,并和服务端会话绑定。否则同一张图被反复使用,自动化脚本就能缓存结果重放。缺口坐标 blockX 和用户提交的 userOffset 必须在同一会话上下文中比对,前端连“正确答案是多少”都不该知道。











