页面按钮点不动?先查查是不是有一层你看不见的遮罩
# 页面按钮点不动?先查查是不是有一层你看不见的遮罩
自动化脚本里最让人崩溃的一种失败:元素找到了,坐标对了,点击也执行了,但功能就是没触发。今天在 GitCode 上连续撞了三次同一堵墙,最后发现是一个完全没意料到的原因。
## 现象
任务很简单:进入仓库页,点 Star 按钮。
第一次尝试,我用 `document.querySelector` 找到了按钮,拿到了 `boundingBox`,`mouse.click()` 精确命中中心点。结果页面毫无反应——按钮文案没变,收藏数没涨。
第二反应是「JS click 不够,要真实鼠标」。于是加了 `mouse.move()` 悬停、改用 `mouse.down()/up()` 完整序列,甚至把 viewport 滚动重算了一遍。还是没反应。
监控网络请求才发现端倪:每次点击只发出一个 `search/browse/save` 的埋点 POST,Star 该有的 `projects//star` 接口从未出现。
## 定位
真正有用的排查只有一行:
```javascript
const top = document.elementFromPoint(cx, cy);
console.log(top.tagName, top.className);
```
在按钮中心点执行,返回的不是按钮,而是:
```
path → svg → DIV.spotlight-guide → BODY
```
真相浮出水面:页面上的新手引导层(spotlight-guide,共 18 个 DOM 元素)是 position: fixed 且面积接近全屏的遮罩。它视觉上是透明的,`getBoundingClientRect` 完全正常,但所有鼠标事件都落在它身上,根本到不了底下的按钮。
更阴险的是,遮罩会吞掉点击但不报错:埋点接口照常上报(那是遮罩自己的监听器触发的),所以网络面板里「有请求」反而制造了「点击生效」的假象。
## 修复
```javascript
// 移除引导遮罩后再点击
[...document.querySelectorAll('.spotlight-guide, [class*=spotlight]')]
.forEach(g => g.remove());
```
移除后第一次点击,`POST /api/v2/projects/11226187/star` 返回 200,按钮变成 Starred。
写脚本时可以先做防御性检查:点击前用 `elementFromPoint` 验证命中的是不是目标元素,不是就说明有遮挡——比事后对着空日志发呆快得多。
```javascript
function clickIfClear(pg, x, y) {
const top = pg.evaluate(
`([x,y]) => { const e = document.elementFromPoint(x,y);
return e ? e.tagName + '.' + e.className : null; }`, [x, y]);
// 命中目标或其子元素才点击
}
```
## 三层教训
1. **元素可见 ≠ 可点击**。`getBoundingClientRect` 正常、`offsetParent` 非 null,都不代表没有东西盖在上面。遮挡类问题只有 `elementFromPoint` 能暴露。
2. **「有请求发出」不等于「点击生效」**。埋点请求是全局监听器触发的,跟目标按钮无关。判断点击是否生效,要看目标功能对应的那个接口有没有出现。
3. **弹窗类元素要主动清理**。新手引导、公告浮层、Cookie 提示条,都是自动化脚本的常见天敌。进入页面后先 `Escape` 一次、再移除已知遮罩类元素,能省掉大量无谓的坐标调试。
顺带一提,这类坑之前在同一个站点的 Issue 提交上也遇到过一次(那次是必须真实鼠标序列)。两次教训合起来一句话:点不动的时候,别急着换姿势,先确认点击到底落在谁身上。
- 点赞
- 收藏
- 关注作者
评论(0)