真正可控的做法是不用 slider 组件,改用 view + touch 事件模拟拖拽;需同步 canvas 宽高属性与 css 尺寸、严格使用后端返回的 blocky 坐标、采集 starttime/duration/pathpoints/velocity 等轨迹数据加密提交。

滑块验证块样式完全由 CSS 控制,但必须避开 slider 组件的默认覆盖
uni-app 的原生 slider 组件在各端渲染逻辑不一致:H5 用 input[type=range],小程序走自定义 canvas 封装,App 端又依赖原生控件。直接改它的 class 或伪元素几乎无效,且 iOS 上 /deep/ 和 ::-webkit-slider-thumb 失效率极高。
真正可控的做法是「不用 slider 组件」,改用 view + 手动绑定 touch 事件模拟拖拽。这样所有样式(圆角、阴影、背景渐变、图标箭头)都能自由写,也不受平台限制。
- 滑块容器设
position: relative,滑块元素设position: absolute; top: 50%; transform: translateY(-50%)垂直居中 - 滑块宽度建议用
rpx(如80rpx),避免不同屏幕缩放错位 - 禁用系统高亮:给滑块加
-webkit-tap-highlight-color: transparent - 安卓真机上长按可能触发文字选择,需加
user-select: none
防刷动画不是“转圈”,而是基于拖动轨迹的动态反馈
所谓“防刷”,本质是让自动化脚本难以预测和复现交互路径。纯 CSS 动画(比如滑块旋转)毫无意义——脚本只要等动画结束再提交就行。关键在于把用户真实操作行为编码进验证参数里。
必须采集并上报的字段不止 dragX,至少还包括:
-
startTime:touchstart 时间戳(毫秒级) -
duration:touchstart 到 touchend 的总耗时 -
pathPoints:touchmove 过程中采样 5–8 个点的{x, y, t}(t 是相对于 startTime 的偏移) -
velocity:末段平均速度(单位 px/ms),用于识别匀速拖拽(脚本特征)
这些数据要和后端下发的 captchaId、用户手机号一起加密签名后提交。后端不只校验最终位置,还会检查轨迹是否符合人类操作分布(比如起始加速、中间微抖、末端减速)。
canvas 拼图区域必须与滑块 DOM 同步缩放,否则像素比对失效
很多项目 canvas 渲染正常,但验证总失败,问题出在「缩放失配」:CSS 设置了 width: 100%; height: 160rpx,但 canvas 的 width 和 height 属性没同步设置,导致 canvas 内部分辨率被浏览器自动拉伸,缺口坐标计算全乱。
正确做法是显式设置 canvas 的宽高属性(非 CSS):
const query = uni.createSelectorQuery().in(this);
query.select('#verifyCanvas').fields({ node: true, size: true }, res => {
const canvas = res.node;
const dpr = uni.getSystemInfoSync().pixelRatio;
canvas.width = res.width * dpr;
canvas.height = res.height * dpr;
// 后续绘图时所有坐标都要 × dpr
});
同时注意:iOS 真机上 clip() 对复杂路径支持不稳定,建议改用 globalCompositeOperation = 'destination-out' 配合透明矩形“擦除”背景来模拟缺口,兼容性更好。
后端返回的缺口 Y 坐标必须参与前端绘制,且不能硬编码
缺口图和背景图的垂直对齐是拼图严丝合缝的前提。如果前端自己写死 y = 40,而实际后端生成的是 y = 42.3,那用户永远对不齐——因为人眼能容忍几像素横向误差,但对纵向错位极其敏感。
后端接口必须返回 blockY 字段(单位 px,非 rpx),前端拿到后直接传给 canvas 绘制逻辑:
ctx.drawImage(pieceImage, x, blockY, pieceWidth, pieceHeight);
容易忽略的一点:blockY 是相对于背景图左上角的绝对坐标,不是相对于 canvas 容器。如果背景图做了缩放或居中,要先还原原始尺寸再计算真实绘制位置。
防刷的关键不在动画多炫,而在轨迹数据是否真实、是否和服务端会话强绑定。canvas 缩放、Y 坐标、touch 轨迹采样这三处,任一漏掉都会让整个验证形同虚设。










