说明
使用 chrome.scripting API 在不同上下文中执行脚本。
权限
可用性
清单
如需使用 chrome.scripting API,请在清单中声明 "scripting" 权限,并声明要注入脚本的网页的主机权限。使用 "host_permissions" 密钥或 "activeTab" 权限,这会授予临时主机权限。以下示例使用 activeTab 权限。
{ "name": "Scripting Extension", "manifest_version": 3, "permissions": ["scripting", "activeTab"], ... }概念和用法
您可以使用 chrome.scripting API 将 JavaScript 和 CSS 注入网站。这与您可以使用内容脚本执行的操作类似。但通过使用 chrome.scripting 命名空间,扩展程序可以在运行时做出决策。
注入目标
您可以使用 target 参数指定要将 JavaScript 或 CSS 注入到的目标。
唯一的必填字段是 tabId。默认情况下,注入将在指定标签页的主框架中运行。
function getTabId() { ... } chrome.scripting .executeScript({ target : {tabId : getTabId()}, files : [ "script.js" ], }) .then(() => console.log("script injected"));如需在指定标签页的所有框架中运行,您可以将 allFrames 布尔值设置为 true。
function getTabId() { ... } chrome.scripting .executeScript({ target : {tabId : getTabId(), allFrames : true}, files : [ "script.js" ], }) .then(() => console.log("script injected in all frames"));您还可以通过指定各个框架 ID 将代码注入到标签页的特定框架中。如需详细了解框架 ID,请参阅 chrome.webNavigation API。
function getTabId() { ... } chrome.scripting .executeScript({ target : {tabId : getTabId(), frameIds : [ frameId1, frameId2 ]}, files : [ "script.js" ], }) .then(() => console.log("script injected on target frames")); 注意:您不能同时指定 "frameIds" 和 "allFrames" 属性。注入的代码
扩展程序可以通过外部文件或运行时变量指定要注入的代码。
文件
文件以字符串形式指定,这些字符串是相对于扩展程序根目录的路径。以下代码会将文件 script.js 注入到标签页的主框架中。
function getTabId() { ... } chrome.scripting .executeScript({ target : {tabId : getTabId()}, files : [ "script.js" ], }) .then(() => console.log("injected script file"));运行时函数
使用 scripting.executeScript() 注入 JavaScript 时,您可以指定要执行的函数,而不是文件。此函数应是可用于当前扩展程序上下文的函数变量。
function getTabId() { ... } function getTitle() { return document.title; } chrome.scripting .executeScript({ target : {tabId : getTabId()}, func : getTitle, }) .then(() => console.log("injected a function")); function getTabId() { ... } function getUserColor() { ... } function changeBackgroundColor() { document.body.style.backgroundColor = getUserColor(); } chrome.scripting .executeScript({ target : {tabId : getTabId()}, func : changeBackgroundColor, }) .then(() => console.log("injected a function"));您可以使用 args 属性来解决此问题:
function getTabId() { ... } function getUserColor() { ... } function changeBackgroundColor(backgroundColor) { document.body.style.backgroundColor = backgroundColor; } chrome.scripting .executeScript({ target : {tabId : getTabId()}, func : changeBackgroundColor, args : [ getUserColor() ], }) .then(() => console.log("injected a function"));运行时字符串
如果在网页中注入 CSS,您还可以指定要在 css 属性中使用的字符串。此选项仅适用于 scripting.insertCSS();您无法使用 scripting.executeScript() 执行字符串。
function getTabId() { ... } const css = "body { background-color: red; }"; chrome.scripting .insertCSS({ target : {tabId : getTabId()}, css : css, }) .then(() => console.log("CSS injected"));处理结果
执行 JavaScript 的结果会传递给扩展程序。每个帧中包含一个结果。主帧保证是结果数组中的第一个索引;所有其他帧的顺序不确定。
function getTabId() { ... } function getTitle() { return document.title; } chrome.scripting .executeScript({ target : {tabId : getTabId(), allFrames : true}, func : getTitle, }) .then(injectionResults => { for (const {frameId, result} of injectionResults) { console.log(`Frame ${frameId} result:`, result); } });scripting.insertCSS() 不会返回任何结果。
promise
如果脚本执行的结果值是一个 promise,Chrome 将等待该 promise 确定,然后返回结果值。
function getTabId() { ... } async function addIframe() { const iframe = document.createElement("iframe"); const loadComplete = new Promise(resolve => iframe.addEventListener("load", resolve)); iframe.src = "https://example.com"; document.body.appendChild(iframe); await loadComplete; return iframe.contentWindow.document.title; } chrome.scripting .executeScript({ target : {tabId : getTabId(), allFrames : true}, func : addIframe, }) .then(injectionResults => { for (const frameResult of injectionResults) { const {frameId, result} = frameResult; console.log(`Frame ${frameId} result:`, result); } });示例
取消注册所有动态内容脚本
以下代码段包含一个函数,用于取消注册扩展程序之前注册的所有动态内容脚本。
async function unregisterAllDynamicContentScripts() { try { const scripts = await chrome.scripting.getRegisteredContentScripts(); const scriptIds = scripts.map(script => script.id); return chrome.scripting.unregisterContentScripts({ ids: scriptIds }); } catch (error) { const message = [ "An unexpected error occurred while", "unregistering dynamic content scripts.", ].join(" "); throw new Error(message, {cause : error}); } } 要点:取消注册内容脚本不会移除已注入的脚本或样式。如需试用 chrome.scripting API,请从 Chrome 扩展程序示例代码库中安装脚本示例。
类型
ContentScriptFilter
属性
-
ids
string[] 可选
如果指定了此参数,getRegisteredContentScripts 将仅返回 ID 包含在此列表中的脚本。
CSSInjection
属性
-
css
字符串 可选
包含要注入的 CSS 的字符串。必须指定 files 和 css 中的一个。
-
文件
string[] 可选
要注入的 CSS 文件的路径(相对于扩展程序的根目录)。必须指定 files 和 css 中的一个。
-
源
StyleOrigin(可选)
注入的样式来源。默认为 'AUTHOR'。
-
用于指定要将 CSS 插入到的目标的详细信息。
ExecutionWorld
脚本要执行的 JavaScript 世界。
枚举
“ISOLATED”
指定隔离的世界,即此扩展程序独有的执行环境。
“MAIN”
指定 DOM 的主要世界,即与宿主网页的 JavaScript 共享的执行环境。
InjectionResult
属性
-
documentId
字符串
Chrome 106 及更高版本与注入关联的文档。
-
frameId
数值
Chrome 90 及更高版本与注入关联的帧。
-
结果
任何可选
脚本执行结果。
InjectionTarget
属性
RegisteredContentScript
属性
-
allFrames
布尔值 (可选)
如果指定为 true,则会注入到所有框架中,即使该框架不是标签页中最顶层的框架也是如此。系统会针对每个框架单独检查网址要求;如果不满足网址要求,则不会注入到子框架中。默认值为 false,表示仅匹配顶层框架。
-
css
string[] 可选
要注入到匹配页面中的 CSS 文件列表。这些脚本会按其在此数组中出现的顺序注入,在为网页构建或显示任何 DOM 之前注入。
-
excludeMatches
string[] 可选
排除此内容脚本本应注入到的网页。如需详细了解这些字符串的语法,请参阅匹配模式。
-
id
字符串
API 调用中指定的内容脚本的 ID。不得以“_”开头,因为该字符预留为生成的脚本 ID 的前缀。
-
js
string[] 可选
要注入到匹配网页中的 JavaScript 文件列表。这些参数会按照它们在此数组中出现的顺序注入。
-
matchOriginAsFallback
布尔值 (可选)
Chrome 119 及更高版本指示脚本是否可以注入到网址包含不受支持的方案(具体而言,是 about:、data:、blob: 或 filesystem:)的框架中。在这些情况下,系统会检查网址的来源,以确定是否应注入脚本。如果来源为 null(如 data: 网址的情况),则所用来源为创建当前框架的框架或启动对此框架的导航的框架。请注意,这可能不是父框架。
-
匹配
string[] 可选
指定此内容脚本将注入到哪些网页中。如需详细了解这些字符串的语法,请参阅匹配模式。必须为 registerContentScripts 指定。
-
persistAcrossSessions
布尔值 (可选)
指定此内容脚本是否会保留到未来的会话中。默认值为 true。
-
runAt
RunAt 可选
指定何时将 JavaScript 文件注入网页。首选值和默认值为 document_idle。
-
全球
ExecutionWorld(可选)
Chrome 102 及更高版本运行脚本的 JavaScript“世界”。默认为 ISOLATED。
ScriptInjection
属性
-
args
any[] 可选
Chrome 92 及更高版本要传递给所提供函数的实参。仅当指定了 func 参数时,此参数才有效。这些实参必须可序列化为 JSON 格式。
-
文件
string[] 可选
要注入的 JS 或 CSS 文件的路径(相对于扩展程序的根目录)。必须指定 files 或 func 中的一个。
-
injectImmediately
布尔值 (可选)
Chrome 102 及更高版本是否应尽快在目标中触发注入。请注意,这并不能保证在网页加载之前进行注入,因为当脚本到达目标时,网页可能已经加载完毕。
-
用于指定要将脚本注入到的目标的详细信息。
-
全球
ExecutionWorld(可选)
Chrome 95 及更高版本运行脚本的 JavaScript“世界”。默认为 ISOLATED。
-
func
void (可选)
Chrome 92 及更高版本要注入的 JavaScript 函数。此函数将被序列化,然后反序列化以进行注入。这意味着所有绑定参数和执行上下文都将丢失。必须指定 files 或 func 中的一个。
func 函数如下所示:
() => {...}
StyleOrigin
样式更改的来源。如需了解详情,请参阅样式来源。
枚举
"AUTHOR"
"USER"
方法
executeScript()
injection: ScriptInjection,
): Promise<InjectionResult[]>
将脚本注入到目标上下文。默认情况下,脚本将在 document_idle 运行,如果网页已加载,则立即运行。如果设置了 injectImmediately 属性,即使网页尚未完成加载,脚本也会立即注入。如果脚本的计算结果为 promise,浏览器将等待 promise 确定,并返回结果值。
参数
-
要注入的脚本的详细信息。
返回
-
Promise<InjectionResult[]>
Chrome 90 及更高版本返回一个在注入完成后解析的 Promise。生成的数组包含注入成功时每个帧的执行结果。
getRegisteredContentScripts()
filter?: ContentScriptFilter,
): Promise<RegisteredContentScript[]>
返回此扩展程序中与指定过滤条件匹配的所有动态注册的内容脚本。
参数
-
filter
用于过滤扩展程序动态注册的脚本的对象。
返回
-
Promise<RegisteredContentScript[]>
insertCSS()
injection: CSSInjection,
): Promise<void>
将 CSS 样式表插入到目标上下文中。如果指定了多个帧,则会忽略注入失败的情况。
参数
-
注入
要插入的样式的详细信息。
返回
-
Promise<void>
Chrome 90 及更高版本返回一个在插入完成后解析的 Promise。
registerContentScripts()
scripts: RegisteredContentScript[],
): Promise<void>
为相应扩展程序注册一个或多个内容脚本。
参数
-
包含要注册的脚本列表。如果在脚本解析/文件验证期间出现错误,或者指定的 ID 已存在,则不会注册任何脚本。
返回
-
Promise<void>
返回一个 Promise,该 Promise 会在脚本完全注册后解析,或在发生错误时拒绝。
removeCSS()
injection: CSSInjection,
): Promise<void>
从目标上下文中移除之前由相应扩展程序插入的 CSS 样式表。
参数
-
注入
要移除的样式的详细信息。请注意,css、files 和 origin 属性必须与通过 insertCSS 插入的样式表完全匹配。尝试移除不存在的样式表是一项空操作。
返回
-
Promise<void>
返回一个在移除完成时解析的 Promise。
unregisterContentScripts()
filter?: ContentScriptFilter,
): Promise<void>
取消注册相应扩展程序的内容脚本。
参数
-
filter
如果指定,则仅取消注册与过滤条件匹配的动态内容脚本。否则,系统会取消注册扩展程序的所有动态内容脚本。
返回
-
Promise<void>
返回一个 Promise,该 Promise 在脚本已取消注册时解析,或在发生错误时拒绝。
updateContentScripts()
scripts: RegisteredContentScript[],
): Promise<void>
更新相应扩展程序的一个或多个内容脚本。
参数
-
包含要更新的脚本的列表。仅当属性在此对象中指定时,才会针对现有脚本更新该属性。如果在脚本解析/文件验证期间出现错误,或者指定的 ID 与完全注册的脚本不对应,则不会更新任何脚本。
返回
-
Promise<void>
返回一个 Promise,该 Promise 在脚本更新后解析,或在发生错误时拒绝。