概览
开发者工具扩展程序可为 Chrome 开发者工具添加功能。它可以添加新的界面面板和侧边栏,与检查的网页互动,获取有关网络请求的信息等。查看精选的开发者工具扩展程序。开发者工具扩展程序可以访问一组额外的开发者工具专用扩展程序 API:
DevTools 扩展程序的结构与其他扩展程序一样:它可以包含后台页面、内容脚本和其他项。此外,每个开发者工具扩展程序都有一个开发者工具页面,该页面可以访问开发者工具 API。

开发者工具页面
每次打开开发者工具窗口时,系统都会创建扩展程序开发者工具页面的一个实例。开发者工具页面在开发者工具窗口的生命周期内存在。开发者工具页面可以访问开发者工具 API 和一组有限的扩展 API。具体来说,开发者工具页面可以:
- 使用
devtools.panelsAPI 创建面板并与之互动。 - 使用
devtools.inspectedWindowAPI 获取有关检查窗口的信息并评估检查窗口中的代码。 - 使用
devtools.networkAPI 获取有关网络请求的信息。
开发者工具页面无法直接使用大多数扩展程序 API。它有权访问内容脚本有权访问的相同子集 extension 和 runtime API。与内容脚本类似,DevTools 页面可以使用消息传递与后台页面通信。如需查看示例,请参阅注入内容脚本。
创建开发者工具扩展程序
如需为扩展程序创建开发者工具页面,请在扩展程序清单中添加 devtools_page 字段:
{
"name": ...
"version": "1.0",
"minimum_chrome_version": "10.0",
"devtools_page": "devtools.html",
...
}
系统会为每个打开的开发者工具窗口创建一个扩展程序清单中指定的 devtools_page 实例。网页可以使用 devtools.panels API 将其他扩展程序页面作为面板和侧边栏添加到开发者工具窗口。
chrome.devtools.* API 模块仅适用于在开发者工具窗口中加载的网页。内容脚本和其他扩展程序页面没有这些 API。因此,这些 API 仅在开发者工具窗口的生命周期内可用。
还有一些 DevTools API 仍处于实验阶段。请参阅 chrome.experimental.* API,其中列出了实验性 API 以及有关如何使用这些 API 的指南。
开发者工具界面元素:面板和侧边栏窗格
除了常见的扩展程序界面元素(例如浏览器操作、上下文菜单和弹出式窗口)之外,开发者工具扩展程序还可以向开发者工具窗口添加界面元素:
- 面板是指顶级标签页,例如“元素”“来源”和“网络”面板。
- 侧边栏窗格会显示与面板相关的补充界面。“元素”面板上的“样式”“计算样式”和“事件监听器”窗格是边栏窗格的示例。(请注意,侧边栏窗格的外观可能与图片不符,具体取决于您使用的 Chrome 版本以及开发者工具窗口的停靠位置。)

每个面板都是一个独立的 HTML 文件,可以包含其他资源(JavaScript、CSS、图片等)。创建基本面板的示例如下:
chrome.devtools.panels.create("My Panel",
"MyPanelIcon.png",
"Panel.html",
function(panel) {
// code invoked on panel creation
}
);
在面板或侧边栏窗格中执行的 JavaScript 可以访问与开发者工具页面相同的 API。
为“元素”面板创建基本边栏窗格的示例如下:
chrome.devtools.panels.elements.createSidebarPane("My Sidebar",
function(sidebar) {
// sidebar initialization code here
sidebar.setObject({ some_data: "Some data to show" });
});
您可以通过以下几种方式在边栏窗格中显示内容:
- HTML 内容。调用
setPage可指定要在窗格中显示的 HTML 网页。 - JSON 数据。将 JSON 对象传递给
setObject。 - JavaScript 表达式。向
setExpression传递表达式。开发者工具会在检查的网页的上下文中评估表达式,并显示返回值。
对于 setObject 和 setExpression,该窗格都会显示在开发者工具控制台中显示的值。不过,setExpression 可让您显示 DOM 元素和任意 JavaScript 对象,而 setObject 仅支持 JSON 对象。
在扩展组件之间通信
以下部分介绍了一些典型场景,用于在开发者工具扩展程序的不同组件之间进行通信。
注入内容脚本
开发者工具页面无法直接调用 tabs.executeScript。如需从开发者工具页面注入内容脚本,您必须使用 inspectedWindow.tabId 属性检索受检查窗口的标签页 ID,然后向后台页面发送消息。从后台网页调用 tabs.executeScript 以注入脚本。
以下代码段展示了如何使用 executeScript 注入内容脚本。
// DevTools page -- devtools.js
// Create a connection to the background page
var backgroundPageConnection = chrome.runtime.connect({
name: "devtools-page"
});
backgroundPageConnection.onMessage.addListener(function (message) {
// Handle responses from the background page, if any
});
// Relay the tab ID to the background page
chrome.runtime.sendMessage({
tabId: chrome.devtools.inspectedWindow.tabId,
scriptToInject: "content_script.js"
});
背景页的代码:
// Background page -- background.js
chrome.runtime.onConnect.addListener(function(devToolsConnection) {
// assign the listener function to a variable so we can remove it later
var devToolsListener = function(message, sender, sendResponse) {
// Inject a content script into the identified tab
chrome.tabs.executeScript(message.tabId,
{ file: message.scriptToInject });
}
// add the listener
devToolsConnection.onMessage.addListener(devToolsListener);
devToolsConnection.onDisconnect.addListener(function() {
devToolsConnection.onMessage.removeListener(devToolsListener);
});
});
在检查窗口中评估 JavaScript
您可以使用 inspectedWindow.eval 方法在检查的网页的上下文中执行 JavaScript 代码。您可以从 DevTools 页面、面板或侧边栏窗格调用 eval 方法。
默认情况下,表达式是在网页主框架的上下文中进行评估的。现在,您可能已经熟悉开发者工具的命令行 API 功能,例如元素检查 (inspect(elem))、函数中断 (debug(fn))、复制到剪贴板 (copy()) 等。inspectedWindow.eval() 使用与在开发者工具控制台中输入的代码相同的脚本执行上下文和选项,从而允许在 eval 中访问这些 API。例如,SOAK 使用它来检查元素:
chrome.devtools.inspectedWindow.eval(
"inspect($$('head script[data-soak=main]')[0])",
function(result, isException) { }
);
或者,您也可以使用 inspectedWindow.eval() 的 useContentScriptContext: true 选项,在与内容脚本相同的上下文中评估表达式。使用 useContentScriptContext: true 调用 eval 不会创建内容脚本上下文,因此您必须先加载上下文脚本,然后才能调用 eval,方法是调用 executeScript 或在 manifest.json 文件中指定内容脚本。
上下文脚本上下文存在后,您可以使用此选项注入其他内容脚本。
eval 方法在适当的上下文中使用时非常强大,但使用不当则非常危险。如果您不需要访问所检查网页的 JavaScript 上下文,请使用 tabs.executeScript 方法。如需详细了解注意事项并比较这两种方法,请参阅 inspectedWindow。
将所选元素传递给内容脚本
内容脚本无法直接访问当前所选元素。不过,您使用 inspectedWindow.eval 执行的任何代码都可以访问开发者工具控制台和命令行 API。例如,在评估的代码中,您可以使用 $0 访问所选元素。
如需将所选元素传递给内容脚本,请执行以下操作:
- 在内容脚本中创建一个方法,该方法将所选元素作为实参。
- 使用
useContentScriptContext: true选项通过 DevTools 页面调用inspectedWindow.eval方法。
内容脚本中的代码可能如下所示:
function setSelectedElement(el) {
// do something with the selected element
}
从 DevTools 页面调用该方法,如下所示:
chrome.devtools.inspectedWindow.eval("setSelectedElement($0)",
{ useContentScriptContext: true });
useContentScriptContext: true 选项指定表达式必须在与内容脚本相同的上下文中进行评估,因此它可以访问 setSelectedElement 方法。
获取参考面板的 window
如需从开发者工具面板中进行 postMessage,您需要引用其 window 对象。在 panel.onShown 事件处理脚本中获取面板的 iframe 窗口:
onShown.addListener(function callback)
extensionPanel.onShown.addListener(function (extPanelWindow) {
extPanelWindow instanceof Window; // true
extPanelWindow.postMessage( // …
});
从内容脚本到 DevTools 页面的消息传递
DevTools 页面和内容脚本之间的消息传递是通过后台页面间接进行的。
当向内容脚本发送消息时,后台网页可以使用 tabs.sendMessage 方法,该方法会将消息定向到特定标签页中的内容脚本,如注入内容脚本中所述。
当从内容脚本发送消息时,没有现成的方法可将消息传递到与当前标签页关联的正确开发者工具页面实例。作为一种解决方法,您可以让开发者工具页面与后台页面建立长期连接,并让后台页面维护一个从标签页 ID 到连接的映射,以便将每条消息路由到正确的连接。
// background.js
var connections = {};
chrome.runtime.onConnect.addListener(function (port) {
var extensionListener = function (message, sender, sendResponse) {
// The original connection event doesn't include the tab ID of the
// DevTools page, so we need to send it explicitly.
if (message.name == "init") {
connections[message.tabId] = port;
return;
}
// other message handling
}
// Listen to messages sent from the DevTools page
port.onMessage.addListener(extensionListener);
port.onDisconnect.addListener(function(port) {
port.onMessage.removeListener(extensionListener);
var tabs = Object.keys(connections);
for (var i=0, len=tabs.length; i < len; i++) {
if (connections[tabs[i]] == port) {
delete connections[tabs[i]]
break;
}
}
});
});
// Receive message from content script and relay to the devTools page for the
// current tab
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
// Messages from content scripts should have sender.tab set
if (sender.tab) {
var tabId = sender.tab.id;
if (tabId in connections) {
connections[tabId].postMessage(request);
} else {
console.log("Tab not found in connection list.");
}
} else {
console.log("sender.tab not defined.");
}
return true;
});
DevTools 页面(或面板或侧边栏窗格)会建立如下连接:
// Create a connection to the background page
var backgroundPageConnection = chrome.runtime.connect({
name: "panel"
});
backgroundPageConnection.postMessage({
name: 'init',
tabId: chrome.devtools.inspectedWindow.tabId
});
从注入的脚本到开发者工具页面的消息传递
虽然上述解决方案适用于内容脚本,但直接注入到网页中的代码(例如通过附加 <script> 标记或通过 inspectedWindow.eval)需要采用不同的策略。在这种情况下,runtime.sendMessage 将不会按预期将消息传递给后台脚本。
作为一种解决方法,您可以将注入的脚本与充当中间人的内容脚本相结合。如需将消息传递给内容脚本,您可以使用 window.postMessage API。以下是一个示例,假设使用上一部分中的后台脚本:
// injected-script.js
window.postMessage({
greeting: 'hello there!',
source: 'my-devtools-extension'
}, '*');
// content-script.js
window.addEventListener('message', function(event) {
// Only accept messages from the same frame
if (event.source !== window) {
return;
}
var message = event.data;
// Only accept messages that we know are ours
if (typeof message !== 'object' || message === null ||
!message.source === 'my-devtools-extension') {
return;
}
chrome.runtime.sendMessage(message);
});
现在,消息将从注入的脚本流向内容脚本、后台脚本,最后流向开发者工具页面。
您还可以考虑此处介绍的两种替代的消息传递技术。
检测开发者工具何时打开和关闭
如果您的扩展程序需要跟踪开发者工具窗口是否处于打开状态,您可以向后台页面添加 onConnect 监听器,并从开发者工具页面调用 connect。由于每个标签页都可以打开自己的开发者工具窗口,因此您可能会收到多个连接事件。如需跟踪是否有任何开发者工具窗口处于打开状态,您需要统计连接和断开连接事件,如下所示:
// background.js
var openCount = 0;
chrome.runtime.onConnect.addListener(function (port) {
if (port.name == "devtools-page") {
if (openCount == 0) {
alert("DevTools window opening.");
}
openCount++;
port.onDisconnect.addListener(function(port) {
openCount--;
if (openCount == 0) {
alert("Last DevTools window closing.");
}
});
}
});
DevTools 页面会创建如下连接:
// devtools.js
// Create a connection to the background page
var backgroundPageConnection = chrome.runtime.connect({
name: "devtools-page"
});
开发者工具扩展程序示例
浏览以下开发者工具扩展程序示例的源代码:
- Polymer Devtools 扩展程序 - 使用在宿主网页中运行的许多辅助程序来查询 DOM/JS 状态,以便发送回自定义面板。
- React DevTools 扩展程序 - 使用 Blink 的子模块来重复使用开发者工具界面组件。
- Ember Inspector - 共享的扩展程序核心,包含适用于 Chrome 和 Firefox 的适配器。
- Coquette-inspect - 一款基于 React 的简洁扩展程序,可将调试代理注入到宿主页面中。
- 我们的 开发者工具扩展程序库和扩展程序示例中提供了更多值得安装、试用和学习的应用。
更多信息
如需了解扩展程序可使用的标准 API,请参阅 chrome.* API 和 Web API。
欢迎提供反馈意见!您的意见和建议有助于我们改进 API。
示例
您可以在示例中找到使用开发者工具 API 的示例。