为什么我编写的JavaScript点击事件在反应力测试游戏中无法生效?
我从朋友处获得了这个用于测试反应力的链接:https://www.arealme.com/reaction-test/en/
这个游戏会先显示红色圆圈,经过随机时长后变为绿色,我需要在它变绿时尽快点击,所得结果就是我的反应时长。
手动测试的最佳成绩是178,附有截图为证。
我知道可以直接修改178这个数值,但我想编写一个脚本,在绿色圆圈出现时自动生成点击事件。
我计划通过setInterval调用以下函数:
const clickCircle = (className)=> { let greenCircles = document.getElementsByClassName(className); if(greenCircles && greenCircles.length){ greenCircles[0].click(); }else{ console.log("No circles found with name ", className) } } clickCircle("tfny-circleGreen");
绿色圆圈对应的类名为tfny-circleGreen,理论上调用clickCircle("tfny-circleGreen")就会触发点击事件,但实际没有生效。
请问我遗漏了什么?有可能是网站重写了click函数,如果是这种情况该如何恢复?
仅出于趣味尝试,无需过问具体用途。
解决方案
你遇到的这个问题在做网页自动化操作时非常常见,核心原因和对应修复方法如下:
- 首先确认游戏监听的不是
click事件:大多数反应类游戏为了计时更准确,都会监听mousedown/pointerdown这类按下事件,而不是需要等待鼠标抬起才触发的click事件。你可以替换成主动派发mousedown事件的逻辑,替代原生的click()调用:
const triggerPress = (el) => { el.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true, view: window })); };
修改你的点击逻辑为triggerPress(greenCircles[0])即可。
- 如果要追求更快的响应速度,不用
setInterval轮询,改用MutationObserver监听元素类名变化,只要绿色类名一加上就立刻触发点击:
const observer = new MutationObserver((records) => { records.forEach(record => { if (record.target.classList.contains('tfny-circleGreen')) { triggerPress(record.target); } }) }); // 监听整个页面的元素类名变化,也可以缩小范围到圆圈的父元素提升性能 observer.observe(document.body, { attributes: true, attributeFilter: ['class'], subtree: true });
如果确实是网站重写了元素的
click方法,上面的原生事件派发逻辑也完全不受影响,因为没有调用元素上被篡改的click方法,是直接走浏览器原生事件流触发的监听。如果修改后还是不生效,大概率是网站做了反自动化检测,会校验事件的
isTrusted属性,只有用户真实操作触发的事件该属性才为true,纯前端脚本生成的事件无法修改这个属性。这种情况你需要借助浏览器扩展的特权API、或者基于CDP的自动化工具(比如Playwright、Puppeteer)来触发真实点击。
内容的提问来源于stack exchange,提问作者Adnan Sabbir

