主题
运行上下文与通信
Chrome 扩展的页面逻辑分布在多个上下文中:popup、content script 和 service worker。它们互相隔离,应按职责拆分,而不是共享全局状态。
Popup
Popup 是点击工具栏图标后打开的扩展页面,适合承载短时操作和设置入口。它在关闭后会销毁,不应把需要长期保存的状态只放在内存中。
json
{
"action": {
"default_popup": "popup.html"
}
}Popup 可以通过 chrome.tabs 查询标签页,再调用 chrome.tabs.update() 或 chrome.windows.update() 激活目标标签页和窗口。
Content script
内容脚本运行在匹配网页中,负责 DOM 查询和页面展示。例如为文章标题后插入阅读时长:
js
const article = document.querySelector('article')
if (article) {
const wordCount = [...article.textContent.matchAll(/[^\s]+/g)].length
const readingTime = Math.max(1, Math.round(wordCount / 200))
const badge = document.createElement('p')
badge.textContent = `预计阅读 ${readingTime} 分钟`
article.querySelector('h1')?.insertAdjacentElement('afterend', badge)
}它不应承担需要跨页面保存、网络调度或高权限 API 调用的职责。
Service worker
MV3 的后台逻辑由 service worker 承担,适合响应安装、工具栏点击、定时任务和消息等事件。它可能被浏览器随时停止并在新事件到来时重启,因此关键状态应存入 chrome.storage,不要只依赖模块变量。
json
{
"background": {
"service_worker": "service-worker.js",
"type": "module"
}
}js
chrome.runtime.onInstalled.addListener(({ reason }) => {
if (reason === 'install') {
chrome.storage.local.set({ enabled: false })
}
})一次性消息
内容脚本、popup 和 service worker 不能直接访问彼此的变量,可用 chrome.runtime.sendMessage() 与 chrome.runtime.onMessage 交换 JSON 可序列化数据。
js
// content.js
const { tip } = await chrome.runtime.sendMessage({ type: 'get-tip' })
// service-worker.js
chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
if (message.type === 'get-tip') {
chrome.storage.local.get('tip').then(sendResponse)
return true
}
})异步调用 sendResponse 时需要返回 true,以保持消息通道有效。长时间、双向的通信使用 chrome.runtime.connect() 或 chrome.tabs.connect() 创建 Port。
安全边界
内容脚本会接触不受信任的网页。service worker 收到的消息应校验消息类型与字段;来自页面、用户输入或网络响应的数据不要直接写入 innerHTML,避免把高权限能力暴露给网页。
