browser.scripting

说明

使用 chrome.scripting API 在不同上下文中执行脚本。

权限

scripting

可用性

Chrome 88 及更高版本 browser.*(自 Chrome 148 起) MV3 及更高版本

清单

如需使用 browser.scripting API,请在清单中声明 "scripting" 权限,以及要向其中注入脚本的网页的主机权限。使用 "host_permissions" 键或 "activeTab" 权限,后者可授予临时主机权限。以下示例使用了 activeTab 权限。

{
  "name": "Scripting Extension",
  "manifest_version": 3,
  "permissions": ["scripting", "activeTab"],
  ...
}

概念和用法

您可以使用 browser.scripting API 将 JavaScript 和 CSS 注入网站。这与您可以使用内容脚本执行的操作类似。但通过使用 browser.scripting 命名空间,扩展程序可以在运行时做出决策。

注入目标

您可以使用 target 参数指定要注入 JavaScript 或 CSS 的目标。

唯一的必填字段是 tabId。默认情况下,注入将在指定标签页的主框架中运行。

function getTabId() { ... }

browser.scripting
    .executeScript({
      target : {tabId : getTabId()},
      files : [ "script.js" ],
    })
    .then(() => console.log("script injected"));

如需在指定标签页的所有框架中运行,您可以将 allFrames 布尔值设置为 true。

function getTabId() { ... }

browser.scripting
    .executeScript({
      target : {tabId : getTabId(), allFrames : true},
      files : [ "script.js" ],
    })
    .then(() => console.log("script injected in all frames"));

您还可以通过指定各个框架 ID,注入到标签页的特定框架中。如需详细了解帧 ID,请参阅 browser.webNavigation API。

function getTabId() { ... }

browser.scripting
    .executeScript({
      target : {tabId : getTabId(), frameIds : [ frameId1, frameId2 ]},
      files : [ "script.js" ],
    })
    .then(() => console.log("script injected on target frames"));

注入的代码

扩展程序可以通过外部文件或运行时变量指定要注入的代码。

文件

文件指定为相对于扩展程序根目录的路径字符串。以下代码会将文件 script.js 注入标签页的主框架中。

function getTabId() { ... }

browser.scripting
    .executeScript({
      target : {tabId : getTabId()},
      files : [ "script.js" ],
    })
    .then(() => console.log("injected script file"));

运行时函数

使用 scripting.executeScript() 注入 JavaScript 时,您可以指定要执行的函数,而不是文件。此函数应为当前扩展程序上下文可用的函数变量。

function getTabId() { ... }
function getTitle() { return document.title; }

browser.scripting
    .executeScript({
      target : {tabId : getTabId()},
      func : getTitle,
    })
    .then(() => console.log("injected a function"));
function getTabId() { ... }
function getUserColor() { ... }

function changeBackgroundColor() {
  document.body.style.backgroundColor = getUserColor();
}

browser.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;
}

browser.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; }";

browser.scripting
    .insertCSS({
      target : {tabId : getTabId()},
      css : css,
    })
    .then(() => console.log("CSS injected"));

处理结果

执行 JavaScript 的结果会传递给扩展程序。每帧包含一个结果。主框架保证是结果数组中的第一个索引;所有其他框架都采用非确定性顺序。

function getTabId() { ... }
function getTitle() { return document.title; }

browser.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;
}

browser.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 browser.scripting.getRegisteredContentScripts();
    const scriptIds = scripts.map(script => script.id);
    return browser.scripting.unregisterContentScripts({ ids: scriptIds });
  } catch (error) {
    const message = [
      "An unexpected error occurred while",
      "unregistering dynamic content scripts.",
    ].join(" ");
    throw new Error(message, {cause : error});
  }
}

如需试用 browser.scripting API,请从 Chrome 扩展程序示例代码库中安装脚本示例。

类型

ContentScriptFilter

Chrome 96 及更高版本 browser.*(自 Chrome 148 起)

属性

CSSInjection

属性

  • css

    字符串 可选

    包含要注入的 CSS 的字符串。必须且只能指定 files 和 css 中的一个。

  • 文件

    string[] 可选

    要注入的 CSS 文件的路径(相对于扩展程序的根目录)。必须且只能指定 files 和 css 中的一个。

  • 源

    StyleOrigin 可选

    注入的样式来源。默认为 'AUTHOR'。

  • 指定要插入 CSS 的目标的详细信息。

ExecutionWorld

Chrome 95 及更高版本 browser.*(自 Chrome 148 起)

脚本在其中执行的 JavaScript 环境。

枚举

"ISOLATED"
指定隔离环境,即此扩展程序独有的执行环境。

"MAIN"
指定 DOM 的主世界,即与宿主页面的 JavaScript 共享的执行环境。

InjectionResult

属性

  • documentId

    字符串

    Chrome 106+ browser.*(自 Chrome 148 起)

    与注入关联的文档。

  • frameId

    数值

    Chrome 90 及更高版本 browser.*(自 Chrome 148 起)

    与注入关联的帧。

  • 结果

    any 可选

    脚本执行结果。

InjectionTarget

属性

  • allFrames

    布尔值 (可选)

    脚本是否应注入到标签页内的所有框架中。默认值为 false。如果指定了 frameIds,则此值不得为 true。

  • documentIds

    string[] 可选

    Chrome 106+ browser.*(自 Chrome 148 起)

    要注入的特定 documentId 的 ID。如果设置了 frameIds,则不得设置此字段。

  • frameIds

    number[] 可选

    要注入的特定框架的 ID。

  • tabId

    数值

    要注入的标签页的 ID。

RegisteredContentScript

Chrome 96 及更高版本 browser.*(自 Chrome 148 起)

属性

  • allFrames

    布尔值 (可选)

    如果指定为 true,则会注入到所有框架中,即使该框架不是标签页中最顶层的框架也是如此。系统会单独检查每个框架是否符合网址要求;如果不符合网址要求,系统不会将脚本注入子框架。默认值为 false,表示仅匹配顶层框架。

  • css

    string[] 可选

    要注入匹配网页的 CSS 文件列表。这些脚本会按照在此数组中出现的顺序注入,且注入时间早于为页面构建或显示任何 DOM 的时间。

  • excludeMatches

    string[] 可选

    排除原本会注入此内容脚本的网页。如需详细了解这些字符串的语法,请参阅匹配模式。

  • id

    字符串

    在 API 调用中指定的内容脚本的 ID。不得以“_”开头,因为该字符已预留为生成的脚本 ID 的前缀。

  • js

    string[] 可选

    要注入到匹配网页中的 JavaScript 文件列表。这些脚本会按照其在此数组中的显示顺序注入。

  • matchOriginAsFallback

    布尔值 (可选)

    Chrome 119 及更高版本 browser.*(自 Chrome 148 起)

    指明是否可以将脚本注入到网址包含不受支持的架构(具体而言,即 about:、data:、blob: 或 filesystem:)的框架中。在这些情况下,系统会检查网址的来源,以确定是否应注入脚本。如果源站为 null(例如 data: 网址),则使用的源站是创建当前框架的框架,或发起导航到此框架的框架。请注意,这可能不是父级框架。

  • 匹配

    string[] 可选

    指定要将此内容脚本注入到哪些网页中。如需详细了解这些字符串的语法,请参阅匹配模式。必须为 registerContentScripts 指定。

  • persistAcrossSessions

    布尔值 (可选)

    指定此内容脚本是否会保留到未来的会话中。默认值为 true。

  • runAt

    RunAt 可选

    指定何时将 JavaScript 文件注入网页。首选值和默认值为 document_idle。

  • 全球
    Chrome 102 及更高版本 browser.*(自 Chrome 148 起)

    要在其中运行脚本的 JavaScript“world”。默认为 ISOLATED。

ScriptInjection

属性

  • args

    any[] 可选

    Chrome 92 及更高版本 browser.*(自 Chrome 148 起)

    要传递给所提供函数的参数。仅当指定了 func 参数时,此参数才有效。这些参数必须可序列化为 JSON 格式。

  • 文件

    string[] 可选

    要注入的 JS 或 CSS 文件的路径(相对于扩展程序的根目录)。必须且只能指定 files 和 func 中的一个。

  • injectImmediately

    布尔值 (可选)

    Chrome 102 及更高版本 browser.*(自 Chrome 148 起)

    是否应尽快在目标中触发注入。请注意,这并不能保证在网页加载之前进行注入,因为在脚本到达目标时,网页可能已经加载。

  • 指定要将脚本注入到的目标的详细信息。

  • 全球
    Chrome 95 及更高版本 browser.*(自 Chrome 148 起)

    要在其中运行脚本的 JavaScript“world”。默认为 ISOLATED。

  • func

    void (可选)

    Chrome 92 及更高版本 browser.*(自 Chrome 148 起)

    要注入的 JavaScript 函数。此函数将被序列化,然后反序列化以进行注入。这意味着所有绑定参数和执行上下文都将丢失。必须且只能指定 files 和 func 中的一个。

    func 函数如下所示:

    () => {...}

StyleOrigin

样式更改的来源。如需了解详情,请参阅样式来源。

枚举

"AUTHOR"

"USER"

方法

executeScript()

browser.scripting.executeScript(
  injection: ScriptInjection,
)
: Promise<InjectionResult[]>

将脚本注入到目标上下文中。默认情况下,脚本将在 document_idle 运行,如果网页已加载,则会立即运行。如果设置了 injectImmediately 属性,脚本将立即注入,即使网页尚未加载完毕也是如此。如果脚本求值结果为 promise,浏览器将等待 promise 结算并返回结果值。

参数

返回

  • Promise<InjectionResult[]>

    Chrome 90 及更高版本 browser.*(自 Chrome 148 起)

    返回一个在注入完成后解析的 Promise。生成的数组包含成功注入的每个框架的执行结果。

getRegisteredContentScripts()

Chrome 96 及更高版本 browser.*(自 Chrome 148 起)
browser.scripting.getRegisteredContentScripts(
  filter?: ContentScriptFilter,
)
: Promise<RegisteredContentScript[]>

返回此扩展程序中与给定过滤条件匹配的所有动态注册的内容脚本。

参数

  • 过滤条件

    用于过滤扩展程序的动态注册脚本的对象。

返回

insertCSS()

browser.scripting.insertCSS(
  injection: CSSInjection,
)
: Promise<void>

将 CSS 样式表插入目标上下文。如果指定了多个框架,系统会忽略不成功的注入。

参数

返回

  • 承诺<void>

    Chrome 90 及更高版本 browser.*(自 Chrome 148 起)

    返回一个在插入完成后进行解析的 Promise。

registerContentScripts()

Chrome 96 及更高版本 browser.*(自 Chrome 148 起)
browser.scripting.registerContentScripts(
  scripts: RegisteredContentScript[],
)
: Promise<void>

为此扩展程序注册一个或多个内容脚本。

参数

  • 包含要注册的脚本列表。如果在脚本解析/文件验证期间出现错误,或者指定的 ID 已存在,则不会注册任何脚本。

返回

  • 承诺<void>

    返回一个 Promise,该 Promise 会在脚本完全注册后解析,或者在发生错误时拒绝。

removeCSS()

Chrome 90 及更高版本 browser.*(自 Chrome 148 起)
browser.scripting.removeCSS(
  injection: CSSInjection,
)
: Promise<void>

从目标上下文中移除此扩展程序之前插入的 CSS 样式表。

参数

  • 注入

    要移除的样式的详细信息。请注意,css、files 和 origin 属性必须与通过 insertCSS 插入的样式表完全匹配。尝试移除不存在的样式表是一项空操作。

返回

  • 承诺<void>

    返回一个 Promise,该 Promise 会在移除完成后进行解析。

unregisterContentScripts()

Chrome 96 及更高版本 browser.*(自 Chrome 148 起)
browser.scripting.unregisterContentScripts(
  filter?: ContentScriptFilter,
)
: Promise<void>

为此扩展程序取消注册内容脚本。

参数

  • 过滤条件

    如果指定,则仅取消注册与过滤条件匹配的动态内容脚本。否则,该扩展程序的所有动态内容脚本都会被取消注册。

返回

  • 承诺<void>

    返回一个 Promise,该 Promise 会在脚本取消注册后解析,或者在发生错误时拒绝。

updateContentScripts()

Chrome 96 及更高版本 browser.*(自 Chrome 148 起)
browser.scripting.updateContentScripts(
  scripts: RegisteredContentScript[],
)
: Promise<void>

为此扩展程序更新一个或多个内容脚本。

参数

  • 包含要更新的脚本列表。只有在此对象中指定的属性才会在现有脚本中更新。如果脚本解析/文件验证期间出现错误,或者指定的 ID 与完全注册的脚本不对应,则不会更新任何脚本。

返回

  • 承诺<void>

    返回一个 Promise,该 Promise 会在脚本更新后解析,或者在发生错误时拒绝。