Chrome扩展如何调用Tampermonkey脚本内自定义函数
答案
该需求完全可以实现。
Chrome扩展弹窗运行在独立的扩展上下文,@grant none模式下的Tampermonkey脚本运行在页面主世界上下文,二者默认隔离无法直接访问对方的变量/函数,通过自定义DOM事件做跨上下文通信即可完成调用,你现有manifest申请的activeTab、scripting权限已经完全满足需求,不需要额外配置权限。
具体实现步骤
1. 修复现有文件的语法问题
你提供的manifest.json存在几处语法错误,先修复:
- permissions数组最后一项
"webRequestBlocking"后补全缺失的数组闭合 action.default_popup、icons配置下的所有路径字符串补全缺失的闭合双引号- Tampermonkey脚本的
@match原配置为http://*/*,仅匹配http站点,修改为*://*/*即可覆盖所有http/https站点,避免https站点下脚本不生效。
2. 修改Tampermonkey脚本
原脚本中createFolder是立即执行函数内的局部变量,外部无法访问。需要将待调用函数挂载到window对象(方便控制台调试),同时添加自定义事件监听,响应扩展发来的调用指令:
// ==UserScript== // @name All functions // @namespace http://tampermonkey.net/ // @version 0.1 // @match *://*/* // @grant none // ==/UserScript== (function() { 'use strict'; function createFolder() { try { var folderName = prompt('Folder Name'); if (!folderName) return; var jsZip = document.createElement('script'); jsZip.type = 'text/javascript'; jsZip.src = 'https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.0/jszip.js'; jsZip.className = 'jsZip'; document.body.appendChild(jsZip); var fileSaver = document.createElement('script'); fileSaver.type = 'text/javascript'; fileSaver.src = 'https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.0/FileSaver.js'; fileSaver.className = 'fileSaver'; document.body.appendChild(fileSaver); setTimeout(function () { var zip = new JSZip(); zip.folder(folderName).file("myFile.js", `code code code`); zip.generateAsync({ type: "blob" }) .then(function (content) { saveAs(content, folderName); }); }, 1000); } catch (error) { console.log('%c --- ' + error + ' --- ', 'background: black; color: white; font-size: 15px; font-family: monospace; padding: 0px;'); } } // 挂载到window,控制台可直接调用 window.createFolder = createFolder; // 监听扩展触发的自定义事件 window.addEventListener('callTMCreateFolder', createFolder); })();
3. 调整popup.html
原文件未引入脚本、也未给点击区域绑定交互,修改后如下:
<!DOCTYPE html> <html lang="en"> <head> <title>Interface</title> <meta charset="UTF-8"> <style> .button-container { cursor: pointer; padding: 10px; } .button-img { display: block; width: 32px; height: 32px; } </style> </head> <body> <div class="row"> <div class="button-container" id="createFolderBtn"> <img class="button-img" src="button-img.png" alt="创建文件夹"> </div> </div> <script src="popup.js"></script> </body> </html>
4. 新建popup.js处理点击逻辑
绑定按钮点击事件,点击时获取当前激活标签页,直接向页面主世界注入脚本派发自定义事件,触发油猴中的函数执行:
document.getElementById('createFolderBtn').addEventListener('click', async () => { // 获取当前窗口激活的标签页 const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true }); if (!activeTab.id) return; // 注入脚本到页面主世界(和油猴脚本同上下文),派发事件触发函数 await chrome.scripting.executeScript({ target: { tabId: activeTab.id }, world: 'MAIN', func: () => { window.dispatchEvent(new CustomEvent('callTMCreateFolder')); } }); // 执行后自动关闭弹窗 window.close(); });
补充说明
- 必须保持Tampermonkey脚本的
@grant none配置,否则脚本会运行在油猴的独立沙箱中,无法收到页面主世界派发的事件 - 如果需要从扩展向油猴函数传递参数,可在
CustomEvent初始化时将参数放入detail字段,油猴侧的事件回调中通过e.detail读取即可 - 测试时需要先在Chrome扩展管理页开启开发者模式、重新加载修改后的扩展,同时刷新目标页面让Tampermonkey脚本重新注入生效
内容的提问来源于stack exchange,提问作者user19416089
相关产品推荐
相关产品推荐

