用 run-at 控制用户脚本的注入时机
页面加载是分阶段的:HTML 结构先到,样式渲染,图片后到。脚本在哪个阶段被注入,直接影响它能不能找到要操作的元素。@run-at 就是声明这个时机的字段——官方文档强调,它定义的是「脚本最早希望运行的时刻」。
四个常规取值
| 取值 | 注入时刻 | 适用 |
|---|---|---|
document-start | 尽可能早,页面还没成形 | 要抢在页面脚本前干预(如改写变量、提前埋钩子) |
document-body | body 元素出现时 | 要挂载 UI 到 body 的脚本 |
document-end | DOMContentLoaded 触发时 | 操作 DOM 结构的常规脚本 |
document-idle | DOMContentLoaded 之后 | 默认值——不写 @run-at 时按这个算 |
还有第五个特殊值 @run-at context-menu(较新版本引入):脚本不随页面自动运行,等你在右键菜单或弹出菜单里点它才执行,且此模式下 include/exclude 声明被忽略。适合「按需触发」的脚本。
选择建议
- 改样式、加按钮:
document-end或默认document-idle,最省心; - 抢时机:比如脚本要在页面自己的脚本运行前动手,才用
document-start——但它要求你的代码能承受「页面元素还不存在」的状态; - 拿不准:先用默认值;元素找不到再降到
document-end/document-start,配合等待元素出现的代码。
与 @require 的相互作用
官方文档明确提到一个细节:如果脚本用 @require 挂了外部库,下载库文件可能耗时,脚本实际执行会晚于声明的 @run-at——「最早时刻」不保证「准点到达」。
事件缓存机制
官方描述:在声明的注入时刻之后发生的 DOM 插入、DOMContentLoaded、load 事件会被缓存,再派发给脚本里注册的监听器——所以 document-start 注入的脚本也不会错过 load 事件,放心写事件监听。
调试时机问题
「元素找不到」类报错,先确认脚本的注入时机和元素出现时机的先后关系:
- 看头部
@run-at值; - 开发者工具里对比元素实际出现时间;
- 需要看扩展侧日志时开调试级别,见调试日志。
相关页面
- 元数据头总览:
@run-at在头部的位置; - 运行环境(页面世界/隔离世界)的更底层选择,见官方文档 @sandbox 条目的说明。