油猴(Tampermonkey) 入门指北

一、前言

浏览器插件 泛指 Tampermonkey, Violentmonkey, Greasemonkey 这类给页面注入 js 的浏览器扩展。

通过在浏览器扩展在网页加载时注入特定的 js 达到更改页面布局效果等等一切 js 能做的事情。这些扩展也提供了一些网页没有的 api,使注入的 js 能突破网页默认的限制,实现其他的功能。

二、了解 Tampermonkey

早期浏览器脚本的执行机制:动态创建一个 script 元素插入到 document ,当脚本执行完毕后删除 script 元素。但是这种方式有几个缺陷:

  1. 插入 script 标签时会触发 DOMNodeInserted 事件,如下:
js 复制代码
document.addEventListener("DOMNodeInserted",()=>{
  // ...
},true)
  1. 脚本封装的 GM_API 有泄露风险。可能会被恶意网页调用 GM_API 实现跨网页窃取数据。
  2. 脚本可以可以通过 file:// 路径来发起请求,读取用户磁盘数据,但这也给恶意网页开了后门,一旦被反向注入会导致用户本地隐私数据泄密。

后面脚本新增了沙盒模式(iframe 方案/with+proxy方案)进行重构,不再通过注入 script 元素的方式,也不会在宿主环境全局定义 GM_API。并引入了 XPCNativeWrappers 机制(返回了一个包装过的数据,这个数据是可以信任的,确保不会被网页进行恶意篡改)。

但是这个方案也不是完美的,也有一些问题:如在设置 onclick 回调函数的时候不可以直接进行赋值;在设置自定义属性的时候没有作用。这些都是因为可信任进程通信管道返回的是一个包装后的数据,而不是原来的数据本身,这时候我们只能使用 addEventListener 来进行添加 onclick 回调函数,使用 setAttribute 来设置自定义属性等等,这很繁琐。

为了妥协,Tampermonkey 提出了 unsafewindows ,它是原网页数据的一个映射,我们操纵它就相当于操纵原网页。注意:一旦使用了 unsafewindows,代表破坏了安全模型!并且 unsafewindows 的内容并不完全可信,需要谨慎处理!

默认情况下,脚本运行在沙盒环境下,此环境无法访问到前端 dom 。若声明 @grant none,那脚本就会被直接放在浏览器环境上下文中执行,这时脚本上下文(this)就是浏览器上下文(this)。这更加方便获取 dom 节点,但会导致 GM_API 无法使用。

grant 属性可用来申请 GM_ * 函数和 unsafeWindow 权限。

  • none 就是直接运行在前端页面中,此时脚本中的 this 指向宿主网页的 window 对象。
  • unsafeWindow 和 GM_* 就是运行在沙盒环境,需要使用 unsafeWindow 去操作前端的元素。

常用头部信息

名称 描述 说明
@name 脚本名称
@namespace 脚本命名空间
@version 脚本版本 语义化版本规则
@author 脚本作者 -
@description 脚本描述 -
@include 脚本匹配地址 可以使用正则表达式/通配符 *
@match 脚本匹配地址 允许使用通配符,更加严格
@exclude 排除脚本匹配地址 -
@require 引入外部 JS 文件 加载并执行的 js文件,如 UNPKG、jsDelivr 等 cdn 或本地资源
@resource 预加载资源 将外部库保存成资源,可以在代码中通过 GM_getResourceURL 访问
@connect 获取网站访问权限 允许由 GM_xmlhttpRequest 检索的子域
@run-at 脚本运行时机 可选项:document-start、body、end、idle、menu
@grant 申请脚本环境/GM_API none 表示直接注入宿主环境,unsafeWindow 表示沙盒环境,其他权限由 API 名称指定
@noframes 脚本标记 标记使脚本在主页上运行,但不在 iframe 上运行

下面列举部分常用 GM_API,其它可见:官方文档

名称 描述
GM_addStyle 将给定样式添加到文档中并返回注入的样式元素
GM_addElement 创建指定的 HTML 元素,应用所有给定的属性并返回注入的 HTML 元素,此功能是实验性的
GM_setValue 存储一个给定名称的值
GM_getValue 从 GM_setValue 存储的名称中获取值
GM_deleteValue 将 GM_setValue 存储的名称删除
GM_listValues 列出存储的所有名称
GM_addValueChangeListener 侦听 GM_setValue 储存名称的值的更改并返回更改前和后的值
GM_removeValueChangeListener 删除由 GM_addValueChangeListener 添加的侦听器
GM_log 向控制台记录消息
GM_getResourceText 获取由 @resource 预加载的资源
GM_getResourceURL 获取由 @resource 预加载的 Base64 编码 URI
GM_registerMenuCommand 注册一个菜单,在运行此脚本的页面的中显示
GM_unregisterMenuCommand 取消由 GM_registerMenuCommand 注册的菜单
GM_openInTab 通过给定的 URL 打开一个新标签页
GM_xmlhttpRequest 通过脚本发送的 XHR 请求
GM_download 通过给定的 URL 下载文件到本地
GM_saveTab 保存选项卡对象,生命周期为选项卡的打开->关闭
GM_getTab 获取选项卡对象,生命周期为选项卡的打开->关闭
GM_getTabs 获取所有选项卡对象,生命周期为选项卡的打开->关闭
GM_notification 显示桌面通知
GM_setClipboard 将数据复制到剪贴板

三、工程化

最基础的开发方式是通过插件自带的在线编辑器开发,但有着诸多问题:只能写原生 js、没有代码提示、没有 js model ,只能通过 @require API 引入第三方库、没有工程化概念,复杂工程管理困难、没有模块热更新等。

第二种方式:通过脚本 @require file:\C:\Users\userName\Desktop\tm_demo\xxx.user.js 引用本地资源这种方式,配合 IDE ,如 vscode 开发,但这种只解决了部分问题,复杂项目依然难以维护。

第三种是通过 puppeteer,加载 Tampermonkey 魔改插件,对插件进行了非侵入式hook,并且起了个服务器跟浏览器的插件用 socket 通信,实现了文件的自动监控,授权修改,动态更新。原理可参考:李恒道---尝试抹平Tampermonkey的VSCode开发体验

第四种:最常见的是通过 webpack/rollup/uglify-js/esbuild/vite 等构建工具,我选择了 vite-plugin-monkey,vite 相比 webpack 的优势在于:

  • 明确区分了 开发/构建 模式
  • 暴露了本地开发服务器的 api 供外部使用
  • 更加轻量快速的热重载
  • 支持中间件,用来生成中间桥接代码,无需每次生成文件或手动填写代码

具体可参考 vite-plugin-monkey 文档

四、常见问题

1. 异步获取元素

获取 dom 节点时可能会出现元素延迟加载的问题,常见解决方案如下:

使用 settimeout 获取,缺点:实时性不足(需要等当前 tick),有性能损失

DOMNodeInserted 事件的性能也 不好

MutationObserver ,缺点:语法复杂

使用第三方库:如 ElementGetter 等,

2. 存在 iframe 框架

存在某个网页通过 iframe 内嵌了其它网页需要注入,解决方案如下:

@match 匹配到脚本内部

在同域的情况下可以获取到 iframe 元素后通过 conetentWindow 属性访问 iframe 的作用域

3. 需要掌握的 JS API

MutationObserver 参考:DOM 变动观察器(Mutation observer)

Proxy 参考:Proxy 和 Reflect

4. 需要知道的 CSS 知识点

需要知道:选择器

相关推荐
熊的猫25 分钟前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
瑶琴AI前端1 小时前
uniapp组件实现省市区三级联动选择
java·前端·uni-app
会发光的猪。1 小时前
如何在vscode中安装git详细新手教程
前端·ide·git·vscode
我要洋人死2 小时前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人2 小时前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人2 小时前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR2 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香2 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596932 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai3 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书