调试方法论:world / 验证 / SPA 选择器
调试注入类应用时最容易踩的三个坑:搞错脚本运行的 world、用不可靠的方式「验证」交互效果、依赖 SPA 里不稳定的选择器。本节给出一套可复用的方法论。
World 语义:脚本到底运行在哪
| 运行方式 | World | 能看到什么 |
|---|---|---|
已安装应用 / liveDebug on | USER_SCRIPT(隔离 world) | 共享页面 DOM,但不共享 JS 全局:看不到页面框架的 window 变量,页面也看不到你的 |
run --tab <target>(默认) | MAIN(页面 world) | 与页面 JS 同一环境;看不到 USER_SCRIPT world 里 liveDebug 应用的全局状态 |
run --tab <target> --world user-script | USER_SCRIPT(与 liveDebug 同 world) | 可直接探测 liveDebug 应用的全局变量、监听器状态 |
LFRuntime.runInMainWorld(fn) | 从 USER_SCRIPT 跨到 MAIN | 在应用内读取页面框架数据(如 React/Vue 内部状态) |
最常见的误判
用 run --tab 探测「我的应用有没有挂上」,结果 window.__myPanel === undefined,于是断定注入失败——其实脚本好好地跑在 USER_SCRIPT world 里,只是你在 MAIN world 看不到它。探测 liveDebug 应用状态必须加 --world user-script。
两个 world 共享同一个 DOM:DOM 节点、DOM 事件(dispatchEvent 也算)跨 world 可见。不共享的只有 JS 全局对象、原型链补丁和闭包。
验证方法论:看 → 操作 → 断言
看:先拍快照再动手
用
snapshotText --tab <t>获取带@N引用的可访问性快照,确认目标元素真实存在、角色和文案符合预期。不要凭记忆写选择器。操作:用受信输入而非合成事件
input hover/click/fill --ref @N走 CDP 发出受信 (trusted) 输入:能触发 CSS:hover、框架的原生事件委托和浏览器默认行为。dispatchEvent(new MouseEvent(...))是合成事件:isTrusted: false,不会触发:hover样式,部分框架会忽略。验证 hover 出现的按钮时必须用input hover。断言:用输出而不是「没报错」
操作后再次
snapshotText(或input ... --expect ...)确认 UI 达到预期状态。「命令执行成功」不等于「页面发生了预期变化」。
假设分诊:当行为不符合预期时,先用一条最小探测命令区分「代码没注入」「注入了但没挂载」「挂载了但选择器没命中」「命中了但事件没触发」四类原因,再改代码。每轮只验证一个假设。
SPA 选择器指引
- class 名多为构建期哈希(如
feed-active-video-xK3f),版本更新即失效;优先用语义属性(role/aria-*/data-*)、稳定的文案、或snapshotText的@N引用定位 - 同一列表在不同状态下 class 可能不同(如激活项
feed-active-videovs 普通项feed-video),写选择器前先在多个状态下各拍一次快照对比 - SPA 路由切换(
history.pushState)不更换 document:liveDebug 不会重注入,你的 MutationObserver / 事件委托要能覆盖新渲染的节点;用LFDOM.waitForElement/LFDOM.locator(自动等待重试)而不是一次性querySelector - 虚拟列表只渲染可视区节点,
querySelectorAll数量 ≠ 数据总量;用LFDOM.findInVirtualList收集 - 悬浮出现的控件(hover 菜单、tooltip)在快照里可能不存在:先
input hover --ref再拍第二次快照