soarli

浏览器黑科技:如何用一行书签代码(Bookmarklet)一键“冻结”与恢复网页 JavaScript?
在日常冲浪或开发调试时,很多人都用过一种极客小技巧——小书签(Bookmarklet)。只要在浏览器的收藏夹栏新建...
扫描右侧二维码阅读全文
29
2026/10

浏览器黑科技:如何用一行书签代码(Bookmarklet)一键“冻结”与恢复网页 JavaScript?

AI 文章摘要
提炼中... · 本文基于 qwen2.5:14b
✨ 正在提炼文章核心脉络…

在日常冲浪或开发调试时,很多人都用过一种极客小技巧——小书签(Bookmarklet)。只要在浏览器的收藏夹栏新建一个书签,把名称改成自定义功能名(比如 f1.75x),并在 URL 一栏填入一段以 javascript: 开头的代码,就能打造一个随点随用的网页外挂。

比如,下面这串经典的“全网音视频强制 1.75 倍速”书签脚本:

javascript:(function(){function forceSpeed(s=1.75){document.querySelectorAll("video,audio").forEach(m=>{if(m.playbackRate!==s)m.playbackRate=s;if(!m._lock){m._lock=!0;m.addEventListener("ratechange",()=>{if(m.playbackRate!==s)m.playbackRate=s;});}});}setInterval(()=>forceSpeed(1.75),500);})();

它的原理非常巧妙:遍历页面上所有的 <video> 和 <audio> 标签,强行将播放倍速锁定为 1.75,同时监听 ratechange 事件并使用 setInterval 每 500 毫秒巡检一次,防止网页自带的播放器把倍速改回去。

既然书签脚本这么强大,一个很自然的想法就诞生了:

平时遇到禁止复制文本、禁用右键菜单、或者弹窗广告满天飞的流氓网页时,我们经常需要打开 F12 开发者工具,进入“设置 -> 首选项 -> 调试程序”,手动勾选“禁用 JavaScript”。能不能也写一段类似的书签脚本,放到收藏夹栏里,点一下禁用 JS,再点一下恢复呢?

本文将从浏览器底层安全机制出发,剖析为什么“直接禁用”是一个不可能完成的悖论,并手把手带你写出一段支持一键冻结、再点恢复的“网页级 JS 开关”书签脚本,最后汇总全网最高效的 JS 开关方案。


一、 为什么书签脚本无法直接勾选“禁用 JavaScript”?

如果我们的目标是让书签脚本实现与开发者工具中勾选“禁用 JavaScript”完全相同的底层效果,在技术上会撞上两堵无法逾越的高墙:

1. “我杀我自己”的逻辑死锁

小书签的本质,是利用浏览器的 javascript: 伪协议,在当前页面的上下文中动态执行一段 JS 代码。
假设你点击第一下书签,成功在浏览器引擎层面彻底关闭了当前页面的 JavaScript 执行权限;那么当你想要点击第二下恢复时,由于浏览器已经拒绝执行任何 javascript: 协议的代码,这枚书签就变成了一颗“哑弹”,永远无法再次触发自己来恢复环境。

2. 浏览器沙盒与权限隔离(Sandbox)

现代浏览器有着严格的权限分级。网页内部运行的脚本(包括 Bookmarklet)处于最底层的页面沙盒(Page Context)中,它只能操作当前页面的 DOM 树、window 对象和 BOM 接口。而“是否允许运行 JavaScript”属于浏览器内核配置或 DevTools 调试器(Debugger)级别的特权开关,网页脚本没有任何 API 权限去越界修改浏览器的首选项设置。


二、 破局思路:打造“网页级 JS 假死/恢复”书签脚本

既然无法从浏览器引擎层面“拔电源”,我们不妨换个角度思考:我们在网页上禁用 JS,真正的痛点是什么?

90% 的情况下,我们禁用 JS 是为了干掉这三件事:

  1. 破解限制:网页通过监听 copy、contextmenu、selectstart、keydown 等事件,阻止你复制文字、弹出右键菜单或按 F12。
  2. 阻止干扰:网页通过 click、mousedown 等事件在你点击页面时乱弹广告窗口,或者拦截你的正常交互。
  3. 停止轮询与动画:网页通过 setInterval、setTimeout 或 requestAnimationFrame 不断刷新弹窗、检测状态或执行烦人的动态效果。

只要我们在不关闭浏览器 JS 引擎的前提下,用一段脚本把页面上所有的定时器全部清空并拦截,同时在事件传播的最顶层截断网页自身的所有交互监听,就能让网页的 JS 瞬间进入“脑死亡(冻结)”状态!而且因为浏览器 JS 引擎本身还活着,你随时可以再点一下书签把拦截器关掉,完美实现“一键冻结、再点还原”。

1. 终极书签代码(单行纯净版,可直接复制)

像平时添加脚本书签一样,在收藏夹栏新建一个书签:

  • 名称:开关JS(或任意你喜欢的名字)
  • URL:完整复制粘贴下方这行代码
javascript:(function(){const evts=['copy','cut','paste','contextmenu','selectstart','dragstart','mousedown','mouseup','click','dblclick','keydown','keyup','keypress'];if(!window._jsBlocker){window._jsBlocker={active:false,fn:function(e){if(window._jsBlocker.active)e.stopImmediatePropagation();},st:window.setTimeout,si:window.setInterval,raf:window.requestAnimationFrame};evts.forEach(t=>window.addEventListener(t,window._jsBlocker.fn,true));window.setTimeout=function(...a){return window._jsBlocker.active?0:window._jsBlocker.st.apply(this,a);};window.setInterval=function(...a){return window._jsBlocker.active?0:window._jsBlocker.si.apply(this,a);};window.requestAnimationFrame=function(...a){return window._jsBlocker.active?0:window._jsBlocker.raf.apply(this,a);};}window._jsBlocker.active=!window._jsBlocker.active;if(window._jsBlocker.active){let id=window._jsBlocker.st.call(window,()=>{},0);while(id--){window.clearTimeout(id);window.clearInterval(id);}}const tip=document.createElement('div');tip.textContent=window._jsBlocker.active?'🚫 页面JS已冻结(再点恢复)':'✅ 页面JS已恢复';tip.style.cssText='position:fixed;top:20px;right:20px;z-index:2147483647;background:'+(window._jsBlocker.active?'#d93025':'#1e8e3e')+';color:#fff;padding:10px 16px;border-radius:8px;font:14px sans-serif;box-shadow:0 4px 12px rgba(0,0,0,.3);transition:opacity .3s;pointer-events:none;';document.body.appendChild(tip);window._jsBlocker.st.call(window,()=>{tip.style.opacity='0';window._jsBlocker.st.call(window,()=>tip.remove(),300);},1500);})();

2. 核心源码拆解(它是如何工作的?)

为了方便阅读和二次修改,我们将上面的压缩代码还原成带有详细注释的格式:

(function() {
  // 1. 定义需要拦截的常见交互与限制事件
  const evts = [
    'copy', 'cut', 'paste', 'contextmenu', 'selectstart', 'dragstart',
    'mousedown', 'mouseup', 'click', 'dblclick', 'keydown', 'keyup', 'keypress'
  ];

  // 2. 初始化全局控制器(仅在第一次点击时挂载)
  if (!window._jsBlocker) {
    window._jsBlocker = {
      active: false, // 当前开关状态
      // 事件拦截函数:一旦开启,立即阻止后续所有事件监听器执行
      fn: function(e) {
        if (window._jsBlocker.active) {
          e.stopImmediatePropagation();
        }
      },
      // 备份原生的计时器函数,供恢复和自身弹窗提示使用
      st: window.setTimeout,
      si: window.setInterval,
      raf: window.requestAnimationFrame
    };

    // 利用事件捕获阶段(第三个参数为 true)在最顶层挂载拦截器
    evts.forEach(t => window.addEventListener(t, window._jsBlocker.fn, true));

    // 劫持并重写全局定时器:当处于冻结状态时,直接罢工返回 0
    window.setTimeout = function(...a) {
      return window._jsBlocker.active ? 0 : window._jsBlocker.st.apply(this, a);
    };
    window.setInterval = function(...a) {
      return window._jsBlocker.active ? 0 : window._jsBlocker.si.apply(this, a);
    };
    window.requestAnimationFrame = function(...a) {
      return window._jsBlocker.active ? 0 : window._jsBlocker.raf.apply(this, a);
    };
  }

  // 3. 切换开关状态(开 -> 关,关 -> 开)
  window._jsBlocker.active = !window._jsBlocker.active;

  // 4. 如果切换为“冻结”状态,暴力清空页面上已经存在的所有定时器
  if (window._jsBlocker.active) {
    let id = window._jsBlocker.st.call(window, () => {}, 0);
    while (id--) {
      window.clearTimeout(id);
      window.clearInterval(id);
    }
  }

  // 5. 在页面右上角生成可视化的状态提示气泡(Toast)
  const tip = document.createElement('div');
  tip.textContent = window._jsBlocker.active ? '🚫 页面JS已冻结(再点恢复)' : '✅ 页面JS已恢复';
  tip.style.cssText = 
    'position:fixed;top:20px;right:20px;z-index:2147483647;' +
    'background:' + (window._jsBlocker.active ? '#d93025' : '#1e8e3e') + ';' +
    'color:#fff;padding:10px 16px;border-radius:8px;font:14px sans-serif;' +
    'box-shadow:0 4px 12px rgba(0,0,0,.3);transition:opacity .3s;pointer-events:none;';
  document.body.appendChild(tip);

  // 使用备份的原生 setTimeout 让提示框在 1.5 秒后自动淡出销毁
  window._jsBlocker.st.call(window, () => {
    tip.style.opacity = '0';
    window._jsBlocker.st.call(window, () => tip.remove(), 300);
  }, 1500);
})();

这段代码有三个精妙的设计细节:

  • 捕获阶段精准截胡(useCapture: true + stopImmediatePropagation):
    DOM 事件流分为“捕获阶段 -> 目标阶段 -> 冒泡阶段”。绝大多数网页脚本绑定事件都挂载在 document、body 或具体元素上(默认冒泡阶段)。我们的脚本直接挂载在最顶层的 window 捕获阶段,一旦触发立刻调用 e.stopImmediatePropagation(),不仅阻止事件往下传,连同级后续监听器也一并掐断。更妙的是,因为我们没有调用 e.preventDefault(),所以浏览器原生的鼠标选中文字、Ctrl+C 复制、右键菜单、页面滚动依然畅通无阻!
  • 递增 ID 逆向清场:
    浏览器中 setTimeout 和 setInterval 共享一套自增的数字 ID 池。当我们创建一个空的 setTimeout 获取当前最大 id 后,通过 while(id--) 循环逆向清除,就能把页面此前埋下的所有定时炸弹一次性排空。
  • 后门保留(保存原生引用):
    虽然我们把 window.setTimeout 废掉了,但我们把原生的计时器保存在了 window._jsBlocker.st 里。这样一方面再次点击书签时可以无损恢复,另一方面我们的右上角状态提示框(Toast)依然能调用原生计时器实现 1.5 秒自动消失。

三、 如果真的需要“底层彻底禁用 JS”,最快的方法是什么?

虽然上面的书签脚本能解决 90% 的日常需求,但如果你在进行前端调试(比如测试网页的 <noscript> 降级表现,或者阻止首屏渲染时的网络请求脚本),确实需要原汁原味的浏览器级“禁用 JavaScript”功能,以下两种方法可以让你告别繁琐的设置菜单翻找:

方法 1:使用浏览器扩展(真正的一键切换)

浏览器扩展(Extension)运行在特权环境中,拥有调用 chrome.contentSettings.javascript 的底层权限。即使当前网页的 JS 被徹底禁用,浏览器右上角的扩展图标依然可以正常点击。

  • 推荐工具:在 Chrome 或 Edge 扩展商店搜索安装 Quick Javascript Switcher。
  • 体验:将图标固定在地址栏右侧,点一下图标变红(当前域名彻底禁用 JS 并自动刷新),再点一下变绿(立刻恢复)。

方法 2:DevTools 命令面板快捷键(免装任何插件)

如果你已经打开了 F12 开发者工具,千万不要再去点右上角齿轮、进“首选项”、滑到最下面找“调试程序 -> 禁用 JavaScript”了,只需三步肌肉记忆:

  1. 在 F12 界面按下快捷键 Ctrl + Shift + P(Mac 为 Cmd + Shift + P)呼出 Run Command 命令面板。
  2. 直接敲键盘输入 js。
  3. 第一项高亮显示的就是“禁用 JavaScript(Disable JavaScript)”,直接按 回车(Enter) 即可生效;想恢复时,再按一次 Ctrl + Shift + P -> js -> 回车 即可立刻开启。

四、 三种方案横向对比

为了方便你在不同场景下挑选最趁手的工具,可以把这三种方案总结为下表:

| 对比维度 | 方案一:本文“冻结JS”书签脚本

方案二:Quick JS Switcher 扩展方案三:DevTools 快捷键 (Ctrl+Shift+P)
操作方式点击书签栏图标一键切换
点击浏览器右上角扩展图标按 F12 后输入 js 回车
是否需要安装插件❌ 免安装,纯代码书签
✅ 需安装浏览器扩展❌ 浏览器原生自带
是否破坏已加载页面🟢 不刷新页面,保留当前阅读进度与已渲染内容🟡 通常需刷新页面以彻底生效🟢 不刷新页面,立即阻断后续脚本执行
作用深度网页 DOM 事件与计时器层(软冻结)浏览器站点权限层(硬禁用)浏览器调试器引擎层(硬禁用)
最佳适用场景破解禁止复制/右键、停掉烦人弹窗与轮询脚本频繁针对特定网站永久或临时开关 JS前端开发调试、测试无 JS 环境表现

把文章开头的 1.75倍速 脚本和今天这枚 开关JS 脚本一起放进你的浏览器收藏夹栏,一个对付流媒体视频,一个对付流氓网页脚本,你的日常冲浪体验绝对会清爽一大截!

最后修改:2026 年 10 月 29 日 06 : 09 AM

👍 相关推荐

2026 年 10 月 18 日
为什么你的 iOS 深色模式图标像个“黑洞”?原生 App 与 Safari Web App 图标规范全解析
2026 年 09 月 22 日
2026 局域网与外网远程控制终极指南:从高效办公到电竞级串流
2026 年 09 月 21 日
打造 Windows 沉浸式听书神器:解锁微软“晓晓”高音质全网划词朗读
✂️

💬 评论

0 / 1000