三个真实脚本案例:去广告、自动展开全文、网页暗黑模式

API 认识了,元数据也会写了,这一篇把三者串起来,做三个真实场景的小脚本。每个都控制在几十行内,但都覆盖了完整流程:观察页面、写选择器、处理动态加载、验证效果。建议边读边在自己机器上跑。

案例一:去广告

思路是最简单的「找到就藏掉」。多数广告有稳定的类名或容器特征:

// ==UserScript==
// @name     通用去横幅广告
// @match    https://*.news-site.com/*
// @run-at   document-start
// @grant    GM_addStyle
// ==/UserScript==

GM_addStyle(`
  .ad-banner, .ad-wrapper, [class*="advert"] { display: none !important; }
`);

[class*="advert"] 是属性选择器,匹配 class 里含 advert 字样的元素,对付拼写的变体很有效。但这只能处理静态广告;现代页面的广告大多是异步插入的,样式先藏住占位,内容后到,还得补一手 MutationObserver:

new MutationObserver(() => {
  document.querySelectorAll(".ad-lazy").forEach(el => el.remove());
}).observe(document.documentElement, { childList: true, subtree: true });

页面一有 DOM 变动就扫一遍,发现广告节点直接移除。注意性能:扫描选择器要尽量窄,别在每帧都全量 querySelector。

案例二:自动展开全文

很多资讯站把长文折叠,要点一下「展开」。通用思路是模拟点击展开按钮,或直接移除限制高度的样式:

// ==UserScript==
// @name     自动展开全文
// @match    https://forum.example.com/thread/*
// @grant    none
// ==/UserScript==

(function expand() {
  // 方式一:找展开按钮就点
  const btn = document.querySelector(".read-more-btn");
  if (btn) btn.click();

  // 方式二:解除高度限制与遮罩
  const content = document.querySelector(".article-content");
  if (content) {
    content.style.maxHeight = "none";
    content.style.overflow = "visible";
  }
  const mask = document.querySelector(".expand-mask");
  if (mask) mask.remove();
})();

有的站点展开逻辑在内部状态里,点按钮也没用,这时要进 DevTools 的 Elements 面板观察类名变化,找到触发函数改调用。这个案例的主要技能是「用 DevTools 反推页面逻辑」,比写代码本身更重要。

案例三:网页暗黑模式

给没有夜间模式的老站点整体换肤。纯 CSS 暴力方案对简单页面够用:

// ==UserScript==
// @name     站点暗黑模式
// @match    https://legacy.example.com/*
// @run-at   document-start
// @grant    GM_addStyle
// @grant    GM_registerMenuCommand
// ==/UserScript==

let on = GM_getValue("dark", true);

function apply() {
  GM_addStyle(`
    html { filter: invert(1) hue-rotate(180deg); background: #fff; }
    img, video, iframe, [style*="background-image"] {
      filter: invert(1) hue-rotate(180deg);
    }
  `);
}

if (on) apply();

GM_registerMenuCommand("切换暗黑模式", () => {
  on = !on;
  GM_setValue("dark", on);
  location.reload();
});

这里用了一个经典技巧:invert(1) hue-rotate(180deg) 先把整个页面颜色反转再转回色相,得到自然的深色效果,图片视频会被二次反转复原。这套滤镜方案是社区通行的「通用暗黑」做法。菜单项加开关,用 GM 存储记住选择。

三个案例的公共经验

  1. 先观察后动手。打开 DevTools,确认目标元素的选择器真的稳定,别对着猜的类名写代码。
  2. 考虑动态加载。主流站点都是 SPA 或流式渲染,一次性脚本常常只对首屏有效,MutationObserver 是标配工具。
  3. 给用户留开关。哪怕只给自己用,加个菜单开关也能避免「某些场景想临时关掉」时去改代码。

选择器和正则在三个案例里反复出现,不熟的话正则匹配写法可参考本站《正则表达式从入门到精通》:正则实战。习惯在本地编辑器开发的话,这三个脚本都适合放进 HBuilderX 工程管理,改完粘贴进油猴即可,见 HBuilderX 效率技巧。

案例四:强化版去广告的完整结构

案例一只给了片段,这里给一个可以直接跑的完整版本,展示「样式隐藏 + 动态移除 + 菜单开关」的三层结构:

// ==UserScript==
// @name     三层去广告
// @match    https://*.news-site.com/*
// @run-at   document-start
// @grant    GM_addStyle
// @grant    GM_registerMenuCommand
// @grant    GM_getValue
// @grant    GM_setValue
// ==/UserScript==

const enabled = GM_getValue("enabled", true);

if (enabled) {
  // 第一层:样式预隐藏,页面渲染前生效
  GM_addStyle(`.ad-banner, [class*="advert"] { display: none !important; }`);

  // 第二层:DOM 变动监听,清掉异步插入的节点
  new MutationObserver(() => {
    document.querySelectorAll(".ad-lazy").forEach(el => el.remove());
  }).observe(document.documentElement, { childList: true, subtree: true });
}

// 第三层:菜单开关,改完刷新生效
GM_registerMenuCommand(enabled ? "暂时停用去广告" : "恢复去广告", () => {
  GM_setValue("enabled", !enabled);
  location.reload();
});

注意 enabled 是脚本启动时读的一次性值,切换后靠 reload 应用。要「不刷新即时生效」就得把样式节点动态增删,复杂度上一个台阶——多数场景不值得。

调试这三个案例的通用手法

脚本「跑了但没效果」时的排查三板斧:

  1. 确认选择器命中:在目标页 Console 里手敲 document.querySelector("你的选择器"),返回 null 就是选择器错——这是八成故障的根因;
  2. 确认脚本时机:@run-at document-start 时 document.body 可能还是 null,操作 DOM 前先判空或等 DOMContentLoaded;
  3. 确认没有冲突:同页面装了多个改样力的脚本时(比如两个暗黑模式),互相覆盖 filter 或样式,面板里逐个停用做二分。

调试期间建议临时把 @match 收窄到单个测试页面,避免全站弹日志干扰你。定位完成后恢复原匹配范围。

把案例变成自己的模板库

三个案例分别对应三类改造模板:样式注入型(去广告、暗黑)、交互模拟型(自动展开)、状态管理型(带开关与记忆)。真实需求九成落在这三类里。建议把三份代码存成编辑器片段,新需求先判断属于哪一类,从对应模板改起,起手效率完全不同。改模板时最容易错的就是选择器与 URL 模式,正则不熟的话见 正则实战;本地管理脚本工程见 HBuilderX 效率技巧。

三案例的模板归类

案例 模板类型 核心 API / 技巧 难点
去广告 样式注入型 GM_addStyle、MutationObserver 动态插入的广告
自动展开 交互模拟型 el.click()、样式覆写 反推页面内部逻辑
暗黑模式 状态管理型 filter 反转、GM 存储 + 菜单 图片二次反转

把每个案例往对应模板里归档后,新需求「改样式、点按钮、换皮肤」基本都能套用现成骨架,起手速度完全不同。

本章由 WorkBuddy 原创整理,API 行为依据 Chrome 扩展官方文档(Manifest V3)。