AI 帮我重新上架了 Chrome 插件:Copy Unlock

标签:CSS, Google Chrome, JavaScript

14 年前刚学 Chrome 插件开发时,我做了个叫 Enable Copy 的插件,用来解除很多网站对于文本选择、复制和右键菜单的限制。维护 9 年后,该插件的用户量突破了 20 万,先后有 3 个买家想买,我觉得继续维护也麻烦,就卖掉了。
这几天交接工作比较清闲,正好又被 CSDN 的复制限制给恶心到,于是准备重做这个插件。

先说说它的 1.x 版本,原理其实比较简单,分成两块:
  1. CSS:主要是对 DOM 元素加上了 user-select: none-webkit-user-select: none 这样的样式,只要针对性地将这些元素的样式值改成 autotextall 即可恢复。
  2. JavaScript:主要是对 selectstartcopycontextmenu 等事件绑定了自定义的事件处理函数,相应地也有几种方案:
    • oncopy 等属性设置成了事件处理函数:可以将其赋值成 null(即 element.oncopy = null)来解决。
    • 使用了 jQuery:可以用 jQuery(elements).off('copy')jQuery(elements).unbind('copy') 来解决。
    • 使用 addEventListener 绑定事件处理函数:如果有该事件处理函数的引用,可以用 removeEventListener 来解除绑定;否则(大多数情况下是用匿名函数)只能尝试将改元素进行复制,然后替换成一个无事件绑定的元素。

可以看到,不同的网站差异很大,为了兼容它们,我需要查看每个网站的源码,分析它的限制方式和对应的元素,再针对性地进行处理。这也导致了一旦网站发生了变化,我需要再针对性地进行维护的原因。

那么新版本如何解决这个问题呢?
首先是 CSS,考虑到绝大部分网站不会针对一个元素去设置这些样式,因此设置 *, *::before, *::after {user-select: auto !important; -webkit-user-select: auto !important;} 即可解决。
其次是 JavaScript。这里复习一下知识点,addEventListener 绑定多个事件处理函数时,会按绑定顺序依次进行调用。
此外,事件处理时,会分成 3 个阶段:
  1. 捕获阶段:事件从 window 一直向下传递,直到目标元素。
  2. 目标阶段:事件到达目标元素。
  3. 冒泡阶段:事件从目标元素向上冒泡到 window
由此可见,只要我是第一个在 windowdocument 上绑定事件的,并且在捕获阶段就禁止向下传播,那么其他的事件处理函数就不会被调用了,对应的代码大致如下:
document.addEventListener(eventName, (event) => {event.stopImmediatePropagation();}, true);
而为了确保是第一个绑定的,我需要设置 content_scripts"run_at": "document_start" 属性,它会在 DOM 元素构建前和所有 JavaScript 代码执行之前执行。

此外,为了区分用户对哪些域名启用了该功能,避免影响到不需要的网站,我还需要引入一个 backgroud service worker。它需要做 2 件事:
  1. 当用户点击按钮时,将当前域名添加到 chrome.storage.sync(如果已添加,则移除)。然后刷新页面,重新触发 content scripts。
  2. 当标签页更新时(URL 发生了变动、切换了标签页等),判断当前页面的域名是否已经启用该功能,并显示不同颜色的图标。
content_script.js 也可以通过 chrome.storage.sync 来判断当前域名是否启用了该功能,来决定是否需要进行修改。

顺带一提,backgroud service worker 里其实也可以用 chrome.tabs.onUpdated.addListener 来绑定事件,然后在 changeInfo.status === "loading" 时调用 chrome.scripting.executeScript 来执行 content_script.js。这样可以避免不必要地载入 content_script.js,但由于这个过程是异步的,不能保证在所有 JavaScript 代码执行之前执行,因此某些情况可能会出现问题。
我在 1.x 时采用的就是这种方案,也因此调用时机可能是较晚的,无法使用这种方式来阻止其他事件处理函数。

然后是致谢,感谢 AI 在该插件开发与上架过程中做出的突出贡献:
  • 该插件约 80% 的代码由 Roo Code + Gemini 2.5 Pro Preview 生成,token 用量大约为 978 k(输入) / 52 k(输出),模型调用费用是 0(正式版估计约为 $1.74),效果很不错。不过 Gemini 偶尔会出现 503 错误,提示模型过载了,看来用量还是挺大的。
  • 在上架 Chrome Web Store 进行审核时,需要对隐私信息进行描述,例如为啥需要这个权限,是否会收集用户数据等。我将大致的中文交给了 DeepSeek R1,让它翻译成英文,它很敏锐地捕捉到我的意图,帮我完善了很多隐私说明,改得也很地道。
  • 而在命名时,因为 Enable Copy 已经被另一个插件占用了,因此我也让 DeepSeek R1 推荐了一批名字,最后选择了 Copy Unlock。

最后,这个插件发布在了 Chrome Web StoreGithub,欢迎大家使用。

0条评论 你不来一发么↓

    想说点什么呢?