当前位置: 首页 > news >正文

油猴脚本学习1——元数据头部

元数据脚本基本结构就是

基本的脚本就是这样的

// ==UserScript==
// @name         我的第一个脚本
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  修改网页背景色
// @author       You
// @match        https://*/*
// @grant        none
// ==/UserScript==

(function() {
'use strict';
document.body.style.backgroundColor = '#f0f8ff';
})();

// ==UserScript==
// @key value
// @key value
// ==/UserScript==

然后中间填写

// @name         My Awesome Script
// @name         百度搜索优化,

名字空间,为脚本命名,命名主要是为了避免相互冲突

想象一下这个场景:

  • 你安装了两个脚本,脚本A脚本B

  • 脚本A定义了一个全局变量 var config = { ... }

  • 脚本B也定义了一个同名的全局变量 var config = { ... }

  • 当两个脚本都在同一个页面上运行时,后加载的脚本会覆盖先加载的脚本的变量。这会导致脚本A无法正常工作,因为它的 config 被篡改了。

命名空间就是为了解决这个问题而生的。

2. 工作原理

当你在脚本的元数据(@namespace)中声明一个命名空间后,油猴会将你的脚本包裹在一个“沙箱”或“隔离环境”中。你脚本中声明的所有变量和函数,默认都不会泄露到全局 window 对象上。

但是,如果你必须要设置一个全局变量(例如某个网站的特殊API要求),命名空间就为这个全局变量提供了一个“前缀”或“所属范围”,极大地降低了冲突的概率。

// @version      1.0
// @version      2.1.5
// @version      0.8.0-beta

版本号

油猴脚本中版本号的核心作用

1. 触发更新检测 - 最核心的功能

这是版本号在油猴中存在的首要理由。

  • 油猴管理器会定期(例如每天)检查你安装的脚本是否有更新。

  • 检查的方式就是对比脚本元数据中的 @version 和脚本发布网址上的 @version

  • 如果发布网址上的版本号高于你本地安装的版本号,油猴就会在管理面板中显示一个更新按钮(通常带有数字徽标),提示你有新版本可用。

  • 没有版本号,这个自动更新机制就完全失效了。

2. 管理脚本的更新流程

当用户点击更新时,油猴会:

  1. 根据版本号判断有更新。

  2. 显示一个对比界面,让你查看新版本修改了哪些代码和元数据。

  3. 允许你选择“立即安装”或“忽略此次更新”。

版本号是这个流程的唯一凭证

3. 向用户传达变更的严重性

油猴社区通常遵循 语义化版本 规范,用户可以通过版本号的变化快速了解这次更新的性质:

版本号变化含义用户应有的预期
主版本号 变化
(例如 2.5.0 -> 3.0.0
重大更新脚本可能进行了彻底重写,可能与网站新布局适配,但可能与你用的其他脚本冲突,或设置项被重置。需要谨慎更新。
次版本号 变化
(例如 2.5.0 -> 2.6.0
新增功能加入了新功能,但不会破坏现有功能。通常是安全且值得更新的。
修订号 变化
(例如 2.5.0 -> 2.5.1
问题修复修复了一些Bug,没有新功能。强烈建议更新
4. 脚本仓库的强制要求

在 GreasyForkOpenUserJS 等主流的油猴脚本发布平台上:

  • @version 是必须的元数据,没有它你无法成功发布脚本。

  • 每次更新脚本时,都必须提高版本号,平台不允许你上传一个版本号与现有版本相同或更低的脚本。


描述

// @description  增强网页功能
// @description  自动填充表单,移除广告

作者

// @author       Your Name
// @author       Anonymous

3. 匹配规则字段

// @match        *://*.example.com/*
// @match        https://www.google.com/search*
// @match        http://localhost:8080/app/*

@include - 宽松匹配

javascript

// @include      http://*
// @include      https://*
// @include      *://*.example.com/path/*
@exclude - 排除URL

javascript

// @exclude      *://*.example.com/admin/*
// @exclude      https://www.google.com/search?q=test*

运行时

// @run-at       document-start      // 尽早执行
// @run-at       document-body       // body元素出现时
// @run-at       document-end        // DOMContentLoaded时
// @run-at       document-idle       // 默认,页面加载完成后
// @run-at       context-menu        // 右键菜单点击时

1. // @run-at document-start

执行时机:资源开始加载,但尚未解析 DOM。

  • 特点

    • 脚本在页面 HTML 刚开始下载时就注入

    • document.readyState === "loading"

    • DOM 树尚未构建,document.body 为 null

    • 可以拦截和修改最初的 HTML 内容

// ==UserScript==
// @run-at document-start
// ==/UserScript==// 拦截和修改原始 HTML
document.addEventListener('beforescriptexecute', function(e) {// 阻止某些脚本执行if (e.target.src.includes('advertisement')) {e.preventDefault();}
});// 修改尚未解析的页面内容
document.documentElement.addEventListener('DOMNodeInserted', function(e) {// 监控 DOM 节点的插入
});

2. // @run-at document-body

执行时机<body> 元素首次出现时。

  • 特点

    • 当 document.body 不为 null 但可能为空时执行

    • DOM 刚开始构建,页面内容可能还不完整

    • 比 document-start 稍晚,比 document-end 早

  • 典型用途

// ==UserScript==
// @run-at document-body
// ==/UserScript==// 立即在 body 中添加元素
const loader = document.createElement('div');
loader.id = 'my-custom-loader';
document.body.appendChild(loader);// 设置初始样式或布局
document.body.style.overflow = 'hidden'; // 先隐藏滚动条

3. // @run-at document-end

执行时机:DOM 解析完成时(DOMContentLoaded 事件)。

  • 特点

    • DOM 树已完全构建,可以安全地操作页面元素

    • 图片等资源可能仍在加载

    • document.readyState === "interactive"

    • 这是最常用的时机之一

// ==UserScript==
// @run-at document-end
// ==/UserScript==// 安全地操作页面元素
const buttons = document.querySelectorAll('button');
buttons.forEach(btn => {btn.style.backgroundColor = 'red';
});// 修改页面内容
const header = document.querySelector('h1');
if (header) {header.textContent = '已修改的标题';
}

4. // @run-at document-idle

执行时机:页面完全加载完成后(window.onload 事件)。

  • 特点

    • 默认值,如果不指定 @run-at 则使用此选项

    • 所有资源(图片、样式表等)都已加载完成

    • document.readyState === "complete"

    • 确保页面完全稳定后再执行脚本

// ==UserScript==
// @run-at document-idle
// ==/UserScript==// 需要页面完全加载后才能执行的操作
const allImages = document.images;
console.log('页面共有图片:', allImages.length);// 进行复杂的 DOM 操作
setTimeout(() => {// 确保所有动态内容都已加载processDynamicContent();
}, 1000);

5. // @run-at context-menu

执行时机:用户在页面上右键点击脚本名称时。

  • 特点

    • 脚本不会自动执行

    • 只在用户通过右键菜单选择时才运行

    • 适合工具类、辅助类脚本

// ==UserScript==
// @run-at context-menu
// ==/UserScript==// 右键菜单工具脚本
const selectedText = window.getSelection().toString().trim();if (selectedText) {// 处理选中的文本console.log('选中的文本:', selectedText);// 可以翻译、搜索、格式化等window.open(`https://www.google.com/search?q=${encodeURIComponent(selectedText)}`);
} else {alert('请先选择一些文本');
}

执行时机对比总结

指令执行时机DOM 状态资源加载使用频率
document-start最早未解析刚开始中等
document-body较早body 刚出现进行中较少
document-endDOM 解析完成DOM 就绪进行中很高
document-idle页面完全加载完全就绪已完成最高(默认)
context-menu用户触发任意时机任意状态特殊用途

实际选择建议

  1. 需要拦截修改原始内容 → document-start

  2. 操作页面主要元素 → document-end(最常用)

  3. 依赖完整页面资源 → document-idle(默认)

  4. 工具类、按需使用 → context-menu

  5. 特定布局调整 → document-body

@grant - 权限控制

// @grant        none                // 不使用特殊API
// @grant        GM_setValue         // 存储数据
// @grant        GM_getValue         // 读取数据
// @grant        GM_xmlhttpRequest   // 跨域请求
// @grant        GM_addStyle         // 添加CSS
// @grant        GM_notification     // 桌面通知
// @grant        GM_setClipboard     // 剪贴板操作
// @grant        unsafeWindow        // 访问页面window对象

1. // @grant none

含义:脚本运行在页面的原生环境中,不使用任何油猴特殊 API

  • 特点

    • 脚本与页面共享同一个 JavaScript 环境

    • 可以直接访问页面的 window 对象

    • 权限最低,但执行效率最高

    • 无法使用油猴的存储、网络请求等高级功能

  • 使用场景

    // ==UserScript==
    // @grant none
    // ==/UserScript==// 可以直接操作页面变量
    const pageVariable = window.somePageVariable;// 可以直接调用页面函数
    if (typeof pageFunction === 'function') {pageFunction();
    }// 简单的 DOM 操作
    document.querySelector('button').click();

    2. // @grant GM_setValue 和 // @grant GM_getValue

    含义:启用键值对存储功能,用于持久化保存数据

  • 特点

    • 数据在浏览器关闭后依然保存

    • 每个脚本有独立的存储空间

    • 适合保存用户设置、历史记录等

  • // ==UserScript==
    // @grant GM_setValue
    // @grant GM_getValue
    // ==/UserScript==// 保存用户设置
    GM_setValue('theme', 'dark');
    GM_setValue('lastVisit', new Date().toISOString());// 读取设置
    const theme = GM_getValue('theme', 'light'); // 第二个参数是默认值
    const lastVisit = GM_getValue('lastVisit');console.log(`当前主题:${theme},最后访问:${lastVisit}`);

    3. // @grant GM_xmlhttpRequest

    含义:启用跨域网络请求功能。

  • 特点

    • 可以绕过浏览器的同源策略

    • 支持所有 HTTP 方法(GET、POST 等)

    • 可以自定义请求头、超时时间等

  • // ==UserScript==
    // @grant GM_xmlhttpRequest
    // ==/UserScript==// 调用外部 API
    GM_xmlhttpRequest({method: 'GET',url: 'https://api.example.com/data',headers: {'User-Agent': 'MyUserScript'},onload: function(response) {const data = JSON.parse(response.responseText);console.log('获取到的数据:', data);},onerror: function(error) {console.error('请求失败:', error);}
    });

    4. // @grant GM_addStyle

    含义:向页面注入 CSS 样式

  • 特点

    • 安全地添加样式,避免与页面样式冲突

    • 自动处理样式作用域

    • 适合修改页面外观

  • // ==UserScript==
    // @grant GM_addStyle
    // ==/UserScript==// 添加自定义样式
    GM_addStyle(`.my-custom-widget {position: fixed;top: 10px;right: 10px;background: #fff;border: 1px solid #ccc;z-index: 9999;}/* 隐藏广告 */.advertisement {display: none !important;}/* 修改页面主题 */body {background-color: #f0f0f0 !important;}
    `);

    5. // @grant GM_notification

    含义:显示桌面通知

  • 特点

    • 即使用户不在当前标签页也能看到

    • 适合重要事件提醒

  • 使用场景

  • // ==UserScript==
    // @grant GM_notification
    // ==/UserScript==// 显示通知
    GM_notification({title: '任务完成',text: '数据已成功处理',image: 'https://example.com/icon.png',timeout: 3000, // 3秒后自动关闭onclick: function() {// 点击通知时的回调window.focus();}
    });

    6. // @grant GM_setClipboard

    含义:操作系统剪贴板

  • 特点

    • 可以安全地复制文本到剪贴板

    • 不需要用户手动复制

  • 使用场景

  • // ==UserScript==
    // @grant GM_setClipboard
    // ==/UserScript==// 复制文本到剪贴板
    function copyToClipboard(text) {GM_setClipboard(text, 'text'); // 第二个参数是数据类型GM_notification({title: '复制成功',text: '内容已复制到剪贴板'});
    }// 使用示例
    copyToClipboard('Hello, World!');

    7. // @grant unsafeWindow

    含义:直接访问页面的原始 window 对象

  • 特点

    • 绕过油猴的安全沙箱

    • 有风险,可能被页面代码检测或干扰

    • 仅在必要时使用

  • 使用场景

  • // ==UserScript==
    // @grant unsafeWindow
    // ==/UserScript==// 访问页面全局变量
    const pageConfig = unsafeWindow.pageConfig;// 修改页面全局变量(谨慎使用!)
    unsafeWindow.someGlobalFunction = function() {console.log('被脚本修改的函数');
    };// 与页面代码交互
    if (unsafeWindow.jQuery) {unsafeWindow.jQuery('body').css('background-color', 'red');
    }
    Grant 指令功能风险等级使用频率
    none无特殊权限
    GM_setValue / GM_getValue数据存储
    GM_xmlhttpRequest跨域请求
    GM_addStyle添加样式
    GM_notification桌面通知
    GM_setClipboard剪贴板操作
    unsafeWindow访问页面对象

  • 最佳实践建议

  • 按需申请权限:只申请脚本真正需要的权限

  • 优先使用安全API:避免使用 unsafeWindow,除非必要

  • 组合使用权限:可以同时申请多个权限

    javascript

    复制

    下载
    // ==UserScript==
    // @grant GM_setValue
    // @grant GM_getValue
    // @grant GM_xmlhttpRequest
    // @grant GM_addStyle
    // ==/UserScript==
  • 测试权限可用性:在使用前检查 API 是否可用

    javascript

    复制

    下载
    if (typeof GM_setValue !== 'undefined') {GM_setValue('key', 'value');
    }
  • 正确使用 @grant 指令可以让你的脚本既功能强大又安全可靠。

// ==UserScript==
// @require      https://code.jquery.com/jquery-3.6.0.min.js          // 先加载
// @require      https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js  // 后加载
// @require      https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js   // 最后加载
// ==/UserScript==

规则@require 按声明顺序同步加载和执行。

执行时机

  • 在所有 @require 加载并执行完成后,才执行脚本主代码

  • 执行时机受 @run-at 指令影响


实际应用场景

场景 1:使用 UI 库创建界面

// ==UserScript==
// @name         带UI的增强脚本
// @namespace    http://tampermonkey.net/
// @version      1.0
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @require      https://unpkg.com/sweetalert/dist/sweetalert.min.js
// @match        *://example.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==(function() {'use strict';// 使用引入的库$(document).ready(function() {// 添加自定义按钮$('body').prepend('<button id="myBtn">点击我</button>');$('#myBtn').click(function() {// 使用 SweetAlert 显示美观的弹窗swal({title: "你好!",text: "这是一个使用外部库的示例",icon: "success",buttons: true,});});});
})();

场景 2:工具函数库

javascript

复制

下载

// ==UserScript==
// @name         数据处理脚本
// @namespace    http://tampermonkey.net/
// @version      1.0
// @require      https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/axios/1.4.0/axios.min.js
// @match        *://data.example.com/*
// @grant        none
// ==/UserScript==(function() {'use strict';// 数据处理const processData = (data) => {return _.chain(data).filter(item => item.active).groupBy('category').mapValues(group => _.sumBy(group, 'value')).value();};// 使用 axios 进行 HTTP 请求const fetchData = async () => {try {const response = await axios.get('/api/data');const processed = processData(response.data);console.log('处理后的数据:', processed);} catch (error) {console.error('请求失败:', error);}};fetchData();
})();

@resource - 加载资源

javascript

复制

下载

// @resource     icon1   http://example.com/icon.png
// @resource     html    http://example.com/template.html
// @resource     css     https://example.com/styles.css
1. 加载图片资源
javascript
// @resource    icon1   http://example.com/icon.png
特点:图片会被缓存,避免重复下载可以获取图片的 base64 数据 URL使用示例:javascript
// ==UserScript==
// @name         使用图片资源的脚本
// @namespace    http://tampermonkey.net/
// @version      1.0
// @resource     customIcon https://www.google.com/favicon.ico
// @resource     banner     https://via.placeholder.com/300x100.png
// @match        *://*/*
// @grant        GM_getResourceURL
// ==/UserScript==(function() {'use strict';// 获取图片的 Data URLconst iconUrl = GM_getResourceURL('customIcon');const bannerUrl = GM_getResourceURL('banner');// 在页面中使用图片const myIcon = document.createElement('img');myIcon.src = iconUrl;myIcon.style.width = '16px';myIcon.style.height = '16px';document.body.appendChild(myIcon);
})();

2. 加载 HTML 模板

javascript

复制

下载

// @resource    html    http://example.com/template.html

特点

  • 预加载 HTML 片段或模板

  • 避免在脚本中嵌入大量 HTML 字符串

使用示例

javascript

复制

下载

// ==UserScript==
// @name         使用HTML模板的脚本
// @namespace    http://tampermonkey.net/
// @version      1.0
// @resource     popupTemplate https://raw.githubusercontent.com/user/repo/master/templates/popup.html
// @match        *://*/*
// @grant        GM_getResourceText
// ==/UserScript==(function() {'use strict';// 获取 HTML 模板内容const templateHtml = GM_getResourceText('popupTemplate');// 插入到页面中const container = document.createElement('div');container.innerHTML = templateHtml;container.id = 'my-custom-popup';document.body.appendChild(container);// 现在可以操作模板中的元素const closeBtn = document.getElementById('close-popup');if (closeBtn) {closeBtn.addEventListener('click', function() {container.style.display = 'none';});}
})();

// @resource    css     https://example.com/styles.css

配套的 GM API 函数

1. GM_getResourceURL(资源名称)

获取资源的 Data URL(适用于图片、字体等二进制资源)。

javascript

mageUrl = GM_getResourceURL('myImage'); // 返回: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="

2. GM_getResourceText(资源名称)

获取资源的文本内容(适用于 HTML、CSS、JSON 等文本资源)。

javascript

const template = GM_getResourceText('myTemplate');
// 返回: "<div class='widget'>Hello World</div>"

@connect - 跨域权限

javascript

复制

下载

// @connect      example.com
// @connect      api.github.com
// @connect      localhost
// @connect      *                     // 允许所有域名

6. 更新相关字段

@updateURL - 更新地址

javascript

复制

下载

// @updateURL    https://example.com/myscript.meta.js
@downloadURL - 下载地址

javascript

复制

下载

// @downloadURL  https://example.com/myscript.user.js
@supportURL - 支持页面

javascript

复制

下载

// @supportURL   https://github.com/user/repo/issues

7. 高级功能字段

@noframes - 禁止在iframe运行

javascript

复制

下载

// @noframes
@unwrap - 不包装脚本

javascript

复制

下载

// @unwrap
@nocompat - 兼容性控制

javascript

复制

下载

// @nocompat     Chrome 90+
// @nocompat     Firefox 88+
http://www.dtcms.com/a/532027.html

相关文章:

  • mysql 如何让事件执行
  • PantherX2 debain/armbian Jellyfin10.10.7升级10.11启动后无法监听端口8096的解决办法
  • 网站建设利弊中山币做网站公司
  • Kaleidoscope for mac 文件对比工具
  • LeetCode 1901.寻找峰值2
  • 沈阳建设网站费用北京网站优化软件
  • 【Android】【底层原理】深入解析SELinux模块
  • 阮一峰《TypeScript 教程》学习笔记——注释指令
  • 最好的开发网站建设价格app免费制作平台下载
  • 供应链进销存源码uniapp全开源ERP多仓库管理系统pc+app手机端
  • 生物化学Learning Track(15)酶活性的调节
  • 站酷设计网站官网入口下载国外手机设计网站
  • Rust 泛型与特性
  • GPT-1 技术报告
  • 中英双语 网站 模板wordpress返佣
  • 机器学习库的决策树绘制
  • k8s的calico出现ipset报错解决方法
  • SimpleDateFormat
  • 网站后期的维护和更新池州网站建设推广
  • 低空经济的实时神经系统:空地一体化音视频架构的技术演进
  • 更换MacbookAir固态硬盘,并用U盘安装MacOS操作系统
  • 创建一个简单的SpringBoot
  • 硅基计划2.0 学习总结 玖 图书管理系统 2.0复盘版(文字末尾源码可复制)
  • 河北省建设信息网站十种营销方法
  • qt调用摄像头进行yolo的实时检测
  • 网站备案通过什么可以备案wordpress熊掌号插件
  • IntelliJ IDEA 使用 Lombok 报错:“Lombok requires enabled annotation processing” 解决方案
  • qtmqtt: 一个开源且好用的mqtt开源客户端
  • 数据仓库——总线架构详解
  • 软件中锁机制全解析:从线程到分布式锁