油猴脚本学习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.bodynull

    • 可以拦截和修改最初的 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-end DOM 解析完成 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 URL
    const 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+
相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J5 天前
从“Hello World“ 开始 C++
c语言·c++·学习