油猴脚本开发入门用JavaScript给任意网页加『黑科技』功能从写第一个脚本开始你是否曾浏览某个网站时心里冒出这样的念头“要是这里能自动填表就好了”、“这个按钮要是能一键操作就完美了”、“页面广告太多真想一键净化”……对于大多数普通用户来说这些想法往往止步于想象。但对于了解一点前端知识或者愿意动手尝试的你来说这些“黑科技”功能完全可以亲手实现。今天我们就来聊聊如何通过编写用户脚本UserScript借助Tampermonkey俗称油猴这个强大的工具将你的浏览器变成一个高度定制化的“超级浏览器”。简单来说用户脚本就是一段运行在特定网页上的JavaScript代码。它像是一个隐形的助手在网页加载时悄悄介入按照你设定的规则去修改页面内容、添加功能或自动化操作。而Tampermonkey就是管理、运行这些脚本的“指挥官”。它本身不提供具体功能但为你搭建了一个安全、便捷的脚本运行环境。这意味着你无需等待网站官方更新也不必依赖功能固定的浏览器扩展就能为自己打造独一无二的浏览体验。无论你是刚接触JavaScript的前端新手还是希望将想法快速落地的开发者用户脚本开发都是一个绝佳的实践场。它门槛相对较低能让你立刻看到代码带来的改变获得强烈的正反馈。接下来我们将从零开始一步步构建你的第一个脚本并深入探讨如何让它变得更强大、更智能。1. 环境搭建与脚本管理器选择在开始编写代码之前我们需要一个“舞台”来运行我们的脚本。这个舞台就是用户脚本管理器。市面上主流的脚本管理器有好几款它们各有特色但核心功能相似安装、管理、启用/禁用用户脚本。1.1 主流脚本管理器对比目前最广为人知且功能最完善的当属Tampermonkey篡改猴这也是本文主要使用的工具。它支持 Chrome、Edge、Firefox、Safari、Opera 等几乎所有主流浏览器拥有超过千万的用户生态成熟文档齐全。除了Tampermonkey还有Violentmonkey暴力猴和Greasemonkey油猴Firefox专属等选择。为了帮助你快速做出选择这里有一个简单的功能对比表格特性Tampermonkey (篡改猴)Violentmonkey (暴力猴)Greasemonkey (油猴)主要支持浏览器Chrome, Edge, Firefox, Safari, Opera 等Chrome, Edge, Firefox, Opera 等仅 Firefox开源情况部分开源核心开源完全开源完全开源同步功能支持通过浏览器同步、Google Drive、Dropbox等同步脚本支持通过浏览器同步、Gist等同步脚本支持通过浏览器同步内置编辑器功能强大支持语法高亮、ESLint检查基础编辑器基础编辑器高级API支持非常全面包括GM_*系列API、GM_info等支持大部分常用API支持大部分常用API社区与生态最庞大脚本资源极其丰富活跃资源较多历史悠久但主要限于Firefox推荐人群绝大多数用户和开发者追求稳定和全面功能偏好开源软件、轻量简洁的用户坚定的Firefox用户提示对于初学者和大多数场景强烈建议从Tampermonkey开始。其庞大的用户基数意味着你在遇到问题时更容易找到解决方案丰富的功能也能满足你未来更复杂的开发需求。1.2 安装Tampermonkey安装过程非常简单以Chrome浏览器为例打开Chrome网上应用店。在搜索框中输入“Tampermonkey”。找到由“Jan Biniok”开发的“Tampermonkey”扩展点击“添加到Chrome”。在弹出的确认对话框中点击“添加扩展程序”。安装成功后你会在浏览器工具栏的扩展程序区域看到一个猴头图标。点击它如果看到类似“仪表盘”、“添加新脚本”的菜单就说明安装成功了。// 这是一个最简单的Tampermonkey脚本元数据块示例我们稍后会详细解释 // UserScript // name My First Script // namespace http://tampermonkey.net/ // version 0.1 // description try to take over the world! // author You // match https://www.example.com/* // grant none // /UserScript对于无法访问Chrome商店的用户也可以从Tampermonkey官网或一些可信的第三方扩展商店下载.crx文件进行离线安装。安装完成后别忘了点击猴头图标进入“仪表盘”熟悉一下界面。你会看到“已安装脚本”、“实用工具”、“设置”等选项卡这里就是你未来管理所有“黑科技”的大本营。2. 编写你的第一个脚本从“Hello World”到实战理论知识铺垫完毕现在让我们动手创建第一个脚本。我们将从一个经典的“Hello World”开始然后迅速升级到一个有实际用途的案例为任意网页添加一个自定义按钮。2.1 创建新脚本与理解元数据在Tampermonkey面板中点击“添加新脚本”。你会看到一个预置了模板的编辑器窗口。最上方被// UserScript和// /UserScript包裹的部分称为元数据块Metadata Block。它定义了脚本的基本信息和行为规则是脚本的“身份证”和“说明书”。让我们逐行解读一个基础元数据块// UserScript // name 页面美化助手 // namespace https://your-site.com // version 1.0.0 // description 自动移除页面广告并添加夜间模式切换按钮 // author YourName // match https://*.zhihu.com/* // match https://www.bilibili.com/video/* // exclude https://www.bilibili.com/read/* // grant GM_addStyle // grant GM_notification // require https://code.jquery.com/jquery-3.6.0.min.js // run-at document-end // /UserScriptname: 脚本的名称会显示在管理列表中。namespace: 一个唯一的标识符通常使用你的域名用于避免与其他作者的脚本名称冲突。version: 版本号便于更新和管理。description: 脚本功能的简要描述。author: 作者信息。match:最重要的指令之一。它使用URL模式来指定脚本在哪些网页上运行。例如https://*.zhihu.com/*表示在所有知乎子域名下的所有页面运行。你可以添加多个match规则。exclude: 排除规则即使在match范围内符合exclude规则的URL也不会运行脚本。grant: 声明脚本需要使用的特殊Tampermonkey APIGM_* API。例如GM_addStyle用于添加CSS样式GM_notification用于发送桌面通知。如果不需要特殊API可以写grant none。require: 在脚本运行前预先加载外部JavaScript库如jQuery、Lodash等。run-at: 指定脚本注入的时机。document-end默认表示在DOM加载完成后、图片等资源加载前运行document-start表示尽可能早地运行document-idle表示在页面完全加载后运行。注意match规则编写需要格外小心。过于宽泛如*://*/*可能导致脚本在不需要的网站上运行影响性能甚至引发错误。过于狭窄又可能无法覆盖目标网站的所有页面。建议先使用具体URL测试再逐步放宽规则。2.2 实战案例为页面添加一个功能按钮假设我们想为某个技术博客网站例如example-tech-blog.com的每篇文章页面添加一个“一键复制文章标题和链接”的按钮。首先我们创建脚本并填写元数据// UserScript // name 技术博客文章助手 // namespace https://my-scripts.com // version 0.2 // description 为技术博客文章页面添加一键复制标题和链接的功能按钮 // author DevLearner // match https://example-tech-blog.com/article/* // grant GM_setClipboard // grant GM_notification // /UserScript (function() { use strict; // 你的代码将写在这里 })();接下来我们编写核心功能。思路是等待页面主体内容加载完成找到文章标题的DOM元素然后创建一个按钮并为其绑定点击事件。(function() { use strict; // 使用MutationObserver监听DOM变化确保目标元素已加载 const observer new MutationObserver(function(mutations, obs) { // 尝试查找文章标题元素这里假设标题在一个h1标签内且类名为.article-title const titleElement document.querySelector(h1.article-title); if (titleElement) { // 找到标题后停止观察 obs.disconnect(); // 执行添加按钮的函数 addCopyButton(titleElement); } }); // 开始观察整个文档body的子节点变化 observer.observe(document.body, { childList: true, subtree: true }); // 如果页面加载很快可能在我们开始观察前标题就已经存在了所以立即检查一次 const initialTitle document.querySelector(h1.article-title); if (initialTitle) { observer.disconnect(); addCopyButton(initialTitle); } function addCopyButton(titleElement) { // 获取文章标题文本 const articleTitle titleElement.textContent.trim(); // 获取当前页面URL const articleUrl window.location.href; // 创建按钮元素 const copyButton document.createElement(button); copyButton.textContent 复制标题与链接; copyButton.style.cssText position: fixed; top: 80px; right: 20px; z-index: 9999; padding: 8px 16px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; border-radius: 20px; cursor: pointer; font-size: 14px; box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08); transition: all 0.15s ease; ; copyButton.onmouseover () { copyButton.style.opacity 0.9; }; copyButton.onmouseout () { copyButton.style.opacity 1; }; // 为按钮添加点击事件 copyButton.addEventListener(click, function() { // 组合要复制的文本例如“文章标题 - 文章链接” const textToCopy ${articleTitle} - ${articleUrl}; // 使用Tampermonkey的API将文本写入剪贴板 GM_setClipboard(textToCopy, text).then(() { // 复制成功后发送一个桌面通知需要grant GM_notification GM_notification({ text: “${articleTitle}”的标题和链接已复制到剪贴板, title: 复制成功, timeout: 3000 }); // 也可以简单改变按钮文字提示 const originalText copyButton.textContent; copyButton.textContent ✅ 已复制; copyButton.style.background #10b981; setTimeout(() { copyButton.textContent originalText; copyButton.style.background linear-gradient(135deg, #667eea 0%, #764ba2 100%); }, 2000); }, (err) { // 复制失败的处理 console.error(复制失败:, err); GM_notification({ text: 复制失败请尝试手动复制。, title: 操作失败, timeout: 3000 }); }); }); // 将按钮添加到页面中 document.body.appendChild(copyButton); } })();这个脚本做了以下几件事智能等待使用MutationObserver确保在文章标题元素加载完成后再执行操作避免因页面加载速度问题导致脚本失效。创建UI动态创建了一个风格现代的固定定位按钮。实现核心功能点击按钮后使用GM_setClipboardAPI将格式化后的标题和链接复制到剪贴板。提供反馈复制成功后通过GM_notification发送桌面通知并临时改变按钮样式和文字给予用户清晰的操作反馈。保存脚本CtrlS后刷新目标博客的文章页面你应该能看到一个紫色的按钮悬浮在页面右上角。点击它如果一切顺利你会收到复制成功的通知并且粘贴板里已经有了整理好的信息。3. 掌握核心技能DOM操作与GM_* API详解上一个案例我们接触了DOM操作和两个GM_* API。要编写更强大的脚本必须深入理解这两块内容。3.1 精准的DOM查询与操作用户脚本的本质是操作网页的DOM文档对象模型。document.querySelector和document.querySelectorAll是你最常用的武器。document.querySelector(selector)返回匹配指定CSS选择器的第一个元素。document.querySelectorAll(selector)返回一个包含所有匹配元素的NodeList类似数组。选择器策略网站结构可能变化过于依赖具体的类名或ID可能导致脚本失效。更健壮的策略是使用相对路径和语义化标签例如article h1比.post-header .title .text更稳定。组合使用属性选择器a[href*download]选择所有链接中包含“download”的a标签。备用方案如果首选选择器找不到元素尝试备用选择器。// 更健壮的元素查找示例 function findArticleContent() { // 首选方案通过文章容器的常见类名或ID查找 let content document.querySelector(article .content, .post-content, #articleBody); if (content) return content; // 备用方案通过语义化标签和结构查找 content document.querySelector(main article, main .post); if (content) return content; // 最终备用尝试查找页面中最大的文本容器 const allDivs Array.from(document.querySelectorAll(div)); const contentDiv allDivs.reduce((a, b) a.textContent.length b.textContent.length ? a : b); return contentDiv.textContent.length 500 ? contentDiv : null; // 假设文章内容至少500字符 }操作DOM找到元素后你可以修改其内容、样式、属性或者创建、插入、删除元素。// 修改元素 const title document.querySelector(h1); title.textContent 新标题; // 修改文本 title.style.color red; // 修改样式 title.classList.add(highlight); // 添加CSS类 // 创建并插入新元素 const newDiv document.createElement(div); newDiv.innerHTML p这是动态添加的内容/p; document.body.appendChild(newDiv); // 插入到body末尾 title.parentNode.insertBefore(newDiv, title.nextSibling); // 插入到标题后面 // 监听事件 const button document.querySelector(#myButton); button.addEventListener(click, (event) { event.preventDefault(); // 阻止默认行为如表单提交、链接跳转 console.log(按钮被点击了); });3.2 强大的GM_* API工具箱Tampermonkey提供了一系列以GM_开头的特殊API让脚本能安全地执行一些普通JavaScript在网页上下文中无法完成的操作。使用前必须在元数据中用grant声明。以下是一些最常用和强大的APIAPI用途示例GM_setValue/GM_getValue在浏览器存储中保存和读取脚本的持久化数据。GM_setValue(theme, dark); let theme GM_getValue(theme, light);GM_setClipboard安全地将文本写入系统剪贴板。GM_setClipboard(要复制的文本, text/plain)GM_xmlhttpRequest发起跨域HTTP请求这是脚本与外部API交互的关键。可用于获取其他网站的数据实现数据聚合。GM_addStyle向页面注入CSS样式。比直接修改style标签更优雅。GM_addStyle(body { background-color: #f0f0f0; })GM_notification创建桌面通知。GM_notification({text: 任务完成, title: 提示})GM_openInTab在新标签页中打开URL。GM_openInTab(https://example.com, {active: false});GM_registerMenuCommand在Tampermonkey菜单中注册自定义命令。为脚本添加一个快捷操作入口。让我们看一个结合了数据存储和网络请求的复杂例子一个简单的网页阅读进度保存器。// UserScript // name 阅读进度保存器 // namespace http://tampermonkey.net/ // version 0.3 // description 自动保存和恢复你在长文章中的阅读位置 // match https://*.long-article-site.com/* // grant GM_setValue // grant GM_getValue // grant GM_addStyle // /UserScript (function() { use strict; // 为进度条添加样式 GM_addStyle( #reading-progress-bar { position: fixed; top: 0; left: 0; height: 4px; background: linear-gradient(90deg, #ff6b6b, #4ecdc4); z-index: 10000; width: 0%; transition: width 0.2s ease; } #reading-progress-resume { position: fixed; bottom: 20px; right: 20px; padding: 10px 20px; background-color: #4ecdc4; color: white; border: none; border-radius: 25px; cursor: pointer; display: none; z-index: 10000; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } ); // 生成当前页面的唯一标识使用URL和文章标题 const pageKey reading_progress_${window.location.pathname}_${document.title}; // 创建进度条和恢复按钮 const progressBar document.createElement(div); progressBar.id reading-progress-bar; document.body.appendChild(progressBar); const resumeButton document.createElement(button); resumeButton.id reading-progress-resume; resumeButton.textContent ⏩ 跳转到上次阅读位置; document.body.appendChild(resumeButton); // 尝试加载上次保存的滚动位置 const savedScrollY GM_getValue(pageKey, 0); if (savedScrollY 100) { // 如果保存的位置超过100像素显示恢复按钮 resumeButton.style.display block; resumeButton.addEventListener(click, () { window.scrollTo({ top: savedScrollY, behavior: smooth }); resumeButton.style.display none; }); // 10秒后自动隐藏恢复按钮 setTimeout(() { resumeButton.style.display none; }, 10000); } // 监听滚动事件更新进度条并保存位置 let saveTimeout; window.addEventListener(scroll, () { // 计算阅读进度百分比 const scrollTop window.scrollY; const docHeight document.documentElement.scrollHeight - window.innerHeight; const scrollPercent docHeight 0 ? (scrollTop / docHeight) * 100 : 0; progressBar.style.width ${scrollPercent}%; // 防抖处理停止滚动500ms后才保存位置避免频繁写入存储 clearTimeout(saveTimeout); saveTimeout setTimeout(() { GM_setValue(pageKey, scrollTop); console.log(阅读位置已保存: ${scrollTop}px); }, 500); }); // 页面卸载前强制保存一次 window.addEventListener(beforeunload, () { GM_setValue(pageKey, window.scrollY); }); })();这个脚本展示了如何将多个GM_* API与DOM操作结合创建一个有状态、有交互的实用功能。它自动记录你的滚动位置并在你下次访问同一文章时提供一键跳转的便利。4. 调试、优化与脚本发布脚本写好了但它可能不完美或者需要在不同环境下测试。掌握调试和优化技巧至关重要。4.1 调试你的脚本Tampermonkey脚本的调试与普通网页JavaScript调试几乎相同。使用浏览器开发者工具在运行脚本的页面上按F12打开开发者工具。切换到“源代码Sources”面板在这里你可以找到你的脚本。它通常位于(油猴脚本) - [你的脚本名称]目录下。你可以在这里设置断点、单步调试、查看变量。控制台Console输出在脚本中使用console.log()、console.warn()、console.error()输出信息这些信息会显示在开发者工具的Console面板中是排查问题最直接的方式。Tampermonkey仪表盘在仪表盘的“已安装脚本”列表中可以方便地启用/禁用脚本、检查错误日志、编辑脚本源代码。注意有时脚本因为run-at时机或match规则问题没有执行。首先检查Tampermonkey图标是否在目标页面显示为彩色通常有数字这表示有脚本在该页面运行。如果图标是灰色的说明match规则可能不匹配当前URL。4.2 提升脚本的健壮性与性能错误处理使用try...catch包裹可能出错的代码块避免脚本因一个错误而完全崩溃。try { const sensitiveData document.querySelector(.user-balance).innerText; // 处理数据... } catch (error) { console.warn(无法获取用户余额可能页面结构已更改:, error); // 提供降级方案或友好提示 }防抖Debounce与节流Throttle对于scroll、resize、input等频繁触发的事件使用防抖或节流技术来限制处理函数的执行频率避免性能问题。上一个进度保存器的例子就使用了防抖。避免全局变量污染始终将你的代码包裹在立即执行函数表达式IIFE中并使用use strict;模式。(function() { use strict; // 你的所有代码在这里 const myPrivateVar safe; // 这是局部变量 })(); // console.log(myPrivateVar); // 错误无法访问尊重网站与用户不要过度请求数据避免影响原网站性能。如果脚本会修改用户界面确保改动是直观、非侵入式的并提供关闭或配置选项。4.3 分享与发布你的脚本当你创作了一个有用的脚本可能会想分享给他人。Greasy Fork是目前最主流、最安全的用户脚本分享平台。发布前请确保代码清晰添加必要的注释说明脚本的功能和配置方法。元数据完整准确填写name、description、match等。遵守规则阅读并遵守Greasy Fork的发布规则不发布恶意、侵权或违反道德的脚本。考虑开源将脚本代码托管在GitHub等平台便于他人贡献和改进。发布流程通常是在Greasy Fork点击“发布新脚本”将你的脚本代码粘贴进去填写描述、标签等信息然后提交审核。通过后其他用户就可以通过Tampermonkey的“获取新脚本”功能找到并安装你的作品了。从“Hello World”到能够解决实际问题的自动化工具用户脚本开发为你打开了一扇通往浏览器无限可能的大门。它不仅是学习JavaScript的绝佳沙盒更是将想法快速转化为生产力的利器。当你下次再对某个网页产生“要是有这个功能就好了”的想法时不妨打开Tampermonkey编辑器尝试用代码将它实现。