用户脚本头部详解:@match @grant @require 等元数据逐个讲
用户脚本的全部「说明书」都在开头那段以 // ==UserScript== 开始、// ==/UserScript== 结束的注释里,行话叫元数据块。管理器靠它决定脚本在哪些页面运行、拥有什么权限、依赖哪些外部资源。这段注释是协议,不是摆设——写错一个字段,脚本可能静默失效。这一篇把最常用的字段逐个讲透。
核心字段速查
| 字段 | 作用 | 必填 |
|---|---|---|
| @name | 脚本名,安装与更新时的身份 | 是 |
| @namespace | 身份命名空间,与 name 组成唯一键 | 建议 |
| @match | 目标页面的 URL 模式 | 实质必填 |
| @grant | 申请的 GM_* 特权 | 是 |
| @version | 版本号,决定是否提示更新 | 建议 |
| @description | 一句话说明 | 建议 |
| @run-at | 注入时机 | 否,默认 document-end |
| @require | 引入外部 JS 库 | 否 |
| @resource | 引入外部 CSS 等资源 | 否 |
| @exclude | 在 @match 命中范围内排除 URL | 否 |
| @noframes | 只在顶层框架运行 | 否 |
@match:决定脚本在哪运行
@match 的语法与扩展的 match patterns 一致,格式是 scheme://host/path 三段式:
// ==UserScript==
// @match https://www.example.com/*
// @match https://*.taobao.com/item/*
// @exclude https://*.taobao.com/item/login*
// ==/UserScript==
三段各有规则:协议部分只能写 http、https 或通配 *;主机部分的 * 必须在开头(如 *.example.com),不能写成 www.*.com;路径部分 * 匹配任意长度字符串。注意一个高频误区:*://example.com/* 不匹配 example.com:8080,端口不同算不同主机,需要单独声明。正则基础不牢的话,这类模式串很容易写错,正则匹配写法可参考本站《正则表达式从入门到精通》:正则实战。
@match 可以出现多次,命中任意一条即注入;@exclude 从命中结果里再挖掉一部分。二者配合能表达「全站生效但登录页除外」这类需求。
@grant:权力申请单
@grant 声明脚本要用哪些特权 API,管理器据此决定脚本的运行方式。三种典型取值:
@grant none:无特权,脚本直接在页面环境运行,能访问页面的 window 对象,但用不了任何 GM_* API;@grant GM_setValue之类:按需列举,用到几个写几个,脚本被放进沙箱;@grant unsafeWindow:显式申请访问页面原始 window,用于和页面自身的 JavaScript 变量打交道。
最小权限原则在这里同样适用:能 none 就别乱申请,每多一个 grant,脚本的能力边界就大一分。这条原则与扩展的权限设计完全同构,第三章讲权限模型时会再对一遍。
@run-at 与注入时机
@run-at 控制脚本相对页面生命周期的执行时刻:
// @run-at document-start
三个取值:document-start 在页面任何脚本运行前注入,适合抢注事件、拦截函数;document-end 在 DOM 就绪后(默认值);document-idle 在页面完全空闲后。做去广告和暗黑模式通常要 document-start,晚了广告先闪一下。这与扩展 content script 的 run_at 字段是同一套概念。
@require 与 @resource
@require 相当于 <script src>,把外部库打进你的脚本执行环境,最常见是引 jQuery:
// @require https://code.jquery.com/jquery-3.7.1.min.js
@resource 引入非 JS 资源,用 GM_getResourceText 或 GM_getResourceURL 取用。两者都会让脚本依赖外部网络,写企业内网脚本时建议把库文件内容直接内联,避免外网不可达时脚本瘫掉。
组合示范
一个典型的现代脚本头部:
// ==UserScript==
// @name 知乎自动展开
// @namespace local.zhihu
// @version 1.2.0
// @description 列表页自动展开折叠的回答
// @match https://www.zhihu.com/*
// @exclude https://www.zhihu.com/signin*
// @run-at document-start
// @grant none
// ==/UserScript==
只读页面、不动数据,grant 写 none;要抢在页面脚本前生效,run-at 提前;登录页不需要处理,用 exclude 排掉。头部写清楚,脚本就成功了一半。
需要说明的是,用户脚本领域没有官方文档,以上均为 Tampermonkey 与社区多年形成的通用约定,个别字段在 Greasy Fork 发布时还有额外的站点审核要求,发布前以其文档为准。
冷门但有用的字段
上面速查表之外,还有几个不常用但关键时刻救场的字段:
| 字段 | 作用 | 使用场景 |
|---|---|---|
| @updateURL / @downloadURL | 指定更新检查与下载地址 | 自托管分发,不走脚本站 |
| @supportURL | 反馈地址 | 面板里一键跳转反馈页 |
| @homepage | 项目主页 | 展示文档与更新日志 |
| @noframes | 仅顶层框架运行 | iframe 密集站点防重复注入 |
| @match 关于 file 协议 | file:///* |
本地 HTML 文件处理 |
| @antifeature | 声明推广内容 | Greasy Fork 要求披露 |
@noframes 值得单独说:很多资讯站正文和评论区都在 iframe 里,不加它脚本会在每个框架各跑一份,逻辑稍复杂就互相打架。默认加上、确认需要再去掉,是更稳妥的选择。
元数据的解析细节
三个容易踩空的解析规则。第一,元数据块必须位于脚本最顶部,前面多一个空行或语句,整块注释就会被当成普通注释,脚本按无权限、无匹配处理——症状是「脚本莫名不运行」,查它。第二,字段名大小写不敏感(@match 与 @MATCH 等价),但值的大小写敏感(URL 主机大小写不敏感,路径敏感)。第三,同一字段可重复声明,语义是「求并集」(如多个 @match);但 @name 与 @namespace 重复声明会以最后一条为准。
第四个规则最隐蔽:// ==UserScript== 与 // ==/UserScript== 的等号数量必须精确,社区见过 ===UserScript=== 的写法导致整块失效。模板生成新脚本时别手抖。
一份生产级头部模板
把本篇要点收敛成一个可直接复用的模板,注释标明每行的取舍理由:
// ==UserScript==
// @name 站点增强 - 短描述
// @namespace yourname.sites.example
// @version 1.0.0
// @description 具体做了什么、对谁有用,一句话说清
// @author yourname
// @match https://www.example.com/*
// @exclude https://www.example.com/login*
// @run-at document-start
// @noframes
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @license MIT
// ==/UserScript==
逐行理由:@author 与 @license 在公开分发时是基本礼仪;grant 按实际用到的 API 精确列举;noframes 默认防御;version 遵守语义化,更新必加一。把模板存成编辑器代码片段,每个新脚本从这里开始,头部就不会再有「忘了写 grant 导致 API 报 undefined」这类低级故障。
需要说明的是,用户脚本领域没有官方文档,以上均为 Tampermonkey 与社区多年形成的通用约定,个别字段在 Greasy Fork 发布时还有额外的站点审核要求,发布前以其文档为准。
常见的头部错误对照
元数据块写错时症状各异,一张对照表覆盖最高频的几种:
| 症状 | 原因 | 修复 |
|---|---|---|
| 脚本从不运行 | 元数据块不在文件顶部 | 块前不能有任何字符与空行 |
| GM_* 报 undefined | @grant 未声明对应 API | 逐个列出实际用到的函数名 |
| 在 iframe 里跑多份 | 未加 @noframes | 默认加上,确认需要再去掉 |
| 收不到更新 | @version 没改 | 每次发布必加一 |
| 匹配不到目标站 | host 或路径段写错 | 按 scheme/host/path 三段逐段核对 |
| 更新后行为异常 | @namespace 被改动 | 身份字段保持稳定 |
排查口诀:先看「块在不在顶部」,再查「grant 全不全」,最后核对「match 严不严」。多数头部问题落在这三处。
头部字段是纯文本协议,没有编译期检查,写错的代价是静默失效——在编辑器里为它配一个代码片段模板(配置思路见 HBuilderX 效率技巧)是最划算的防护。
本章由 WorkBuddy 原创整理,API 行为依据 Chrome 扩展官方文档(Manifest V3)。
