前言在此之前的基础教程系列中,为了演示创建了多个 Chrome 扩展程序,它们通常都比较简单。所以在本章,我将说明扩展之外另一种允许用户修改网页的标准:User Script,它的基本思路非常简单,向用户浏览的网站注入自定义的一个脚本片段。但与扩展不同,使用 User Script 通常需要安装一个脚本管理器,例如
通过这类脚本管理器,可以从网站上直接安装其他人创建的 User Script,也可以自己创建需要的脚本。
User Script 结构首先是结构,User Script 虽然只是一个 JavaScript 文本,但同样分为 Manifest 和 Code 两部分,前者使用注释完成,后者则通常包含在闭包函数中。下面这一个非常简单的示例脚本(由 Tampermonkey 创建)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // ==UserScript== // @name New Userscript // @namespace http://tampermonkey.net/ // @version 2026-04-09 // @description try to take over the world! // @author You // @match https://*/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant none // ==/UserScript== ;(function ( ) { 'use strict'
// Your code here... })()
可以看到,开头的注释以 // ==UserScript== 开始和 // ==/UserScript== 结尾,中间每一行的注释都以 @ 开头代表脚本的元数据,例如 @name/@version/@match/@grant 之类的,最接近官方文档的地方可能是 https://www.tampermonkey.net/documentation.php 。你可能注意到 icon 是一个 datauri 图标。是的,由于只有一个 JavaScript 脚本,所以无法放置 icon 文件之类的。
而下面的代码使用了一个看上去有点奇怪的写法,这是在 ES6 之前为了避免全局变量污染而遗留下来的历史包袱。例如如果在 devtools console 中输入两次下面这个代码,将会出现不同的打印结果
1 2 3 4 console .log (a) // undefined var a = 1 console .log (a) // 1 var a = 1
如果使用闭包包裹,则两次执行的变量都是局部的,不会互相影响。
1 2 3 4 5 6 7 8 9 10 ;(function ( ) { 'use strict' console .log (a) // undefined var a = 1 })() ;(function ( ) { 'use strict' console .log (a) // undefined var a = 1 })()
重写之前的扩展对于之前 Browser Extension Dev - 01. 介绍基本概念 创建的那个隐藏 Google 搜索主页上 AI Mode 按钮的扩展,完全可以使用 User Script 重写它。
之前的 manifest.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 { "manifest_version" : 3 , "name" : "Hide AI Mode on Google Search" , "version" : "0.0.1" , "description" : "Hide the AI Mode button on Google Search pages." , "content_scripts" : [ { "matches" : [ "https://www.google.com/" ] , "js" : [ "content-scripts/content.js" ] , "run_at" : "document_start" } ] , "icons" : { "128" : "icon/128.png" } }
转换成 User Script 就变成了
1 2 3 4 5 6 7 8 9 10 11 // ==UserScript== // @name Hide AI Mode on Google Search // @namespace https://rxliuli.com/ // @version 0.0.1 // @description Hide the AI Mode button on Google Search pages. // @author rxliuli // @match https://www.google.com/ // @icon https://www.google.com/s2/favicons?sz=64&domain=google.com // @run-at document-start // @grant none // ==/UserScript==
然后将之前的 content-scripts/content.js 追加到闭包函数中。
1 2 3 4 5 6 7 8 ;(function ( ) { 'use strict' const style = document .createElement ('style' ) style.textContent = 'button:has([d="M15.65 11.58c.18-.5.27-1.03.31-1.58h-2c-.1 1.03-.51 1.93-1.27 2.69-.88.87-1.94 1.31-3.19 1.31C7.03 14 5 12.07 5 9.5 5 7.03 6.93 5 9.5 5c.46 0 .89.08 1.3.2l1.56-1.56C11.5 3.22 10.55 3 9.5 3 5.85 3 3 5.85 3 9.5S5.85 16 9.5 16c.56 0 2.26-.06 3.8-1.3l6.3 6.3 1.4-1.4-6.3-6.3c.4-.5.72-1.08.95-1.72z"]) { display: none; }' document .documentElement .appendChild (style) })()
在 Tampermonkey 中安装脚本现在,我们可以在 Tampermonkey 脚本管理器中安装脚本了。
首先从 Chrome Web Store 中安装 Tampermonkey https://chromewebstore.google.com/detail/dhdgffkkebhmkfjojejmpbldmpobfkfo
安装之后还必须启用 Developer Mode 并且在 Tampermonkey 扩展的设置中允许 User Scripts。
然后打开 chrome-extension://dhdgffkkebhmkfjojejmpbldmpobfkfo/options.html#nav=new-user-script+editor 创建一个新的脚本
最后,将上面的脚本粘贴进去,然后保存。
现在,可以看到 AI Mode 搜索按钮确实被隐藏起来了。
使用 GM API上面我们完成了一个最简单的脚本,但完全没有涉及到 UserScript 提供的独特的 GM API。目前而言,Tampermonkey 包含了相当多的 API https://www.tampermonkey.net/documentation.php 。
最常见的可能是 GM_setValue/GM_getValue,它们是扩展向脚本提供的 KV 存储 API。这里使用 GM_registerMenuCommand 注册一个菜单项来演示如何在脚本内部启用和禁用。
首先仍然需要使用 // @grant 声明权限
1 2 3 4 5 6 7 8 9 10 11 12 13 // ==UserScript== // @name Hide AI Mode on Google Search // @namespace https://rxliuli.com/ // @version 0.0.1 // @description Hide the AI Mode button on Google Search pages. // @author rxliuli // @match https://www.google.com/ // @icon https://www.google.com/s2/favicons?sz=64&domain=google.com // @run-at document-start // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // ==/UserScript==
然后根据设置动态注册菜单项,并且在启用时自动隐藏 AI Mode 按钮。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ;(function ( ) { 'use strict' let menuId if (GM_getValue ('visible' )) { menuId = GM_registerMenuCommand ('Hide AI Mode' , toggle) } else { menuId = GM_registerMenuCommand ('Show AI Mode' , toggle) hide () }
function toggle ( ) { if (GM_getValue ('visible' )) { hide () GM_registerMenuCommand ('Show AI Mode' , toggle, { id : menuId }) GM_setValue ('visible' , false ) } else { show () GM_registerMenuCommand ('Hide AI Mode' , toggle, { id : menuId }) GM_setValue ('visible' , true ) } }
function hide ( ) { const style = document .createElement ('style' ) style.id = 'hide-ai-mode-on-google-search' style.textContent = 'button:has([d="M15.65 11.58c.18-.5.27-1.03.31-1.58h-2c-.1 1.03-.51 1.93-1.27 2.69-.88.87-1.94 1.31-3.19 1.31C7.03 14 5 12.07 5 9.5 5 7.03 6.93 5 9.5 5c.46 0 .89.08 1.3.2l1.56-1.56C11.5 3.22 10.55 3 9.5 3 5.85 3 3 5.85 3 9.5S5.85 16 9.5 16c.56 0 2.26-.06 3.8-1.3l6.3 6.3 1.4-1.4-6.3-6.3c.4-.5.72-1.08.95-1.72z"]) { display: none; }' document .documentElement .appendChild (style) } function show ( ) { document .getElementById ('hide-ai-mode-on-google-search' )?.remove () } })()
现在打开 Tampermonkey 的 Popup 的弹窗就可以看到注册的菜单项了。
总结总体来说,如果你需要快速向网页注入一些脚本(这本质上就是用户脚本的定义),你可以优先使用 UserScript。如果你需要更强大的功能,比如操作标签页、运行后台定时任务,或者需要包含大型资源文件(例如 wasm,直接将 base64 嵌入内容脚本会很乱),那么你可以选择扩展。
UserScript 有几个显著的优势:
没有审核,这意味着你可以为 YouTube 添加视频下载功能,而谷歌禁止所有试图这样做的扩展程序,甚至本地下载工具 FDM 也收到了投诉。https://www.wilderssecurity.com/threads/free-download-manager-removes-support-for-youtube-downloads.441430/
更广泛的可用性,扩展在移动浏览器中难以使用,只有少数浏览器支持扩展,而支持用户脚本的浏览器数量要更多,例如 Firefox Android、Kiwi Browser、Safari + Userscripts app 等
没有数量限制,这可能是许多人不知道的,Chrome 网上应用店限制一个账户最多提交 20 个扩展程序,这是一个不常见的限制,但它确实存在。https://developer.chrome.com/docs/webstore/publish#:~:text=Note%3A%20You%20cannot%20have%20more%20than%2020%20extensions%20published%20on%20the%20Chrome%20Web%20Store
风险相对更低,扩展拥有的能力远超 UserScript,但这也意味着风险更高,例如加密货币领域因恶意扩展损失数百万美元的例子屡见不鲜。https://thehackernews.com/2025/12/trust-wallet-chrome-extension-bug.html
除了拥有更强大的 API 之外,扩展还有几个优势
可发现性,如果你希望被更多人看到,选择扩展可能是更好的选择。扩展有官方的 Chrome Web Store 或 App Store,而 User Script 没有什么“官方”商店,Userscript.Zone 是一个好的搜索工具,但并不负责审核。
可货币化,扩展尽管成功货币化的例子并不多(相比于 App/Web),但仍然存在。很难说服别人为一个脚本付费,尽管有点愚蠢,但脚本小子的刻板印象也存在
UserScript 需求更加“下沉”和“长尾”,相对而言,User Script 的创建门槛足够低,并且缺乏审核或规范,所以你能找到各种形形色色的脚本和开发者,容易被灰黑产滥用
资源限制更高,例如通过嵌入 wasm/onnx 可以运行一些客户端 AI 模型,例如实现网页内容过滤或是图片识别等等,拓宽了 User Script 难以触及的可能性