本文补充一下插件的界面组件。

1. 扩展图标(Action)

在 Chrome 工具栏上显示扩展图标,可单击触发弹出页面或执行操作。

通过 manifest.json 配置:

"action": {
  "default_icon": "icon.png",
  "default_popup": "popup.html",
  "default_title": "My Extension"
}

支持 chrome.action API 控制图标状态,如动态更改图标或禁用。官方文档:👉点击这里

1.1 设置扩展图标

可以动态更改扩展图标:

chrome.action.setIcon({ path: "icons/new_icon.png" });

示例: 在 service-worker.js 中监听 chrome.runtime.onInstalled 事件,设置图标:

//service-worker.js
chrome.runtime.onInstalled.addListener(() => {
  chrome.action.setIcon({ path: "icons/installed_icon.png" });
});

1.2 设置扩展标题

可以更改扩展图标的鼠标悬停提示:

chrome.action.setTitle({ title: "新的提示信息" });

示例: 当用户点击扩展图标时,更新标题:

//在用户点击操作图标时触发。请注意,如果操作包含弹出式窗口,此事件将不会触发。
chrome.action.onClicked.addListener(() => {
  chrome.action.setTitle({ title: "你点击了扩展!" });
});

1.3 监听扩展图标点击事件

如果扩展未设置 default_popup ,点击扩展图标时可触发 onClicked 事件:

chrome.action.onClicked.addListener((tab) => {
  console.log("扩展图标被点击,当前标签页:", tab);
});

注意:
如果 default_popup 被设置,则不会触发 onClicked 事件,必须清空 default_popup 才能使用此 API。

1.4 设置弹出页面

可以动态更改扩展图标点击后显示的弹出页面:

chrome.action.setPopup({ popup: "new_popup.html" });

示例:在特定条件下动态切换弹出页面:

chrome.runtime.onInstalled.addListener(() => {
  chrome.storage.local.get("useNewPopup", (data) => {
    let popup = data.useNewPopup ? "new_popup.html" : "popup.html";
    chrome.action.setPopup({ popup });
  });
});

1.5 禁用或启用扩展图标

禁用扩展图标:

chrome.action.disable();

启用扩展图标:

chrome.action.enable();

示例: 只有在特定网站上才启用扩展:

chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
  if (tab.url.includes("example")) {
    chrome.action.enable(tabId);
  } else {
    chrome.action.disable(tabId);
  }
});

1.6 动态修改扩展徽章

扩展图标支持 徽章(Badge),可以在图标上显示数字或文本。因为badge空间有限,所以只支持4个以下的字符(英文4个,中文2个)。

chrome.action.setBadgeText({ text: "5" }); // 显示“5”
chrome.action.setBadgeBackgroundColor({ color: "#FF0000" }); // 设置红色背景

示例: 监听消息,动态更新徽章:

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.type === "updateBadge") {
    chrome.action.setBadgeText({ text: message.text });
  }
});

1.7 注意事项

  • 如果 default_popup 被设置,则 onClicked 事件不会触发。
  • onClicked 事件的监听器必须在 service-worker.js 中运行。

2. 右键菜单(Context Menus)

在 Chrome 扩展中,chrome.contextMenus API允许开发者向 右键菜单(Context Menu) 添加自定义选项,增强扩展的交互功能。

官方文档:👉点击这里
chrome.contextMenus 主要用于向右键菜单添加扩展功能,适用于:

  • 网页右键菜单(普通页面)
  • 选中文本右键菜单
  • 图片、视频、链接右键菜单
  • 工具栏上的扩展右键菜单
  • 开发者工具(DevTools)右键菜单

通过 manifest.json 配置:

"permissions": ["contextMenus"],

💡 关键点

  • contextMenus 权限 必须 声明,否则无法使用 API。
  • 由于是在 service-worker.js 运行的,必须在扩展安装时创建菜单。

2.1 创建右键菜单

service-worker.js 添加菜单项:

//service-worker.js
chrome.runtime.onInstalled.addListener(() => {
  chrome.contextMenus.create({
    id: "sampleMenu",
    title: "点击执行操作",
    contexts: ["page"], // 仅在页面空白处右键时可见
  });
});

参数解析 官方文档👉点击查看

参数作用
id菜单项唯一 ID
title菜单显示的名称
contexts指定在哪些情况下显示菜单
documentUrlPatterns仅在匹配的 URL 下显示
targetUrlPatterns仅在匹配的链接或媒体 URL 下显示
parentId父菜单ID,创建子菜单使用

2.2 监听菜单点击事件

//service-worker.js
chrome.contextMenus.onClicked.addListener((info, tab) => {
  if (info.menuItemId === "sampleMenu") {
    console.log("右键菜单被点击", info, tab);
  }
});

2.3 添加不同类型的右键菜单

2.3.1 针对选中文字

//service-worker.js
chrome.contextMenus.create({
  id: "searchGoogle",
  title: "在 Google 搜索:%s",
  contexts: ["selection"] // 选中文本时显示
});

监听事件,打开 Google 搜索:

//service-worker.js
chrome.contextMenus.onClicked.addListener((info, tab) => {
  if (info.menuItemId === "searchGoogle") {
    let query = encodeURIComponent(info.selectionText);
    let url = `https://www.google/search?q=${query}`;
    chrome.tabs.create({ url });
  }
});

2.3.2 针对图片

chrome.contextMenus.create({
  id: "saveImage",
  title: "保存图片",
  contexts: ["image"]
});

监听点击事件:

chrome.contextMenus.onClicked.addListener((info, tab) => {
  if (info.menuItemId === "saveImage") {
    console.log("图片 URL:", info.srcUrl);
  }
});

2.3.3 针对链接

chrome.contextMenus.create({
  id: "copyLink",
  title: "复制链接",
  contexts: ["link"]
});
chrome.contextMenus.onClicked.addListener((info, tab) => {
  if (info.menuItemId === "copyLink") {
    navigator.clipboard.writeText(info.linkUrl).then(() => {
      console.log("链接已复制:", info.linkUrl);
    });
  }
});

2.3.4 仅在特定网站生效

chrome.contextMenus.create({
  id: "exampleOnly",
  title: "仅在 example 显示",
  contexts: ["page"],
  documentUrlPatterns: ["*://*.example/*"] // 仅在 example 显示
});

2.3.5 创建子菜单

chrome.contextMenus.create({ id: "parent", title: "父菜单", contexts: ["page"] });
chrome.contextMenus.create({ id: "child1", title: "子菜单 1", parentId: "parent", contexts: ["page"] });
chrome.contextMenus.create({ id: "child2", title: "子菜单 2", parentId: "parent", contexts: ["page"] });

2.4 删除或更新菜单

删除菜单

chrome.contextMenus.remove("sampleMenu");

删除所有菜单

chrome.contextMenus.removeAll();

更新菜单

chrome.contextMenus.update("sampleMenu", {
  title: "新菜单名称"
});

2.5 在 DevTools 添加右键菜单

如果你想在 开发者工具 中添加右键菜单:

//manifest.json
{
  "devtools_page": "devtools.html"
}

在 devtools.js:

chrome.contextMenus.create({
  id: "devToolsMenu",
  title: "DevTools 右键菜单",
  contexts: ["all"]
});

3. override(覆盖特定页面)

在 Chrome 扩展中,Override API 允许开发者替换特定的 Chrome 内置页面,如:

  • 新标签页(New Tab Page, chrome://newtab/)
  • 历史记录页面(History, chrome://history/)
  • 书签管理页面(Bookmarks, chrome://bookmarks/)

注意点:

  • 只能覆盖 newtab, history, bookmarks
  • 必须在 manifest.json 配置 chrome_url_overrides
  • 只能加载本地 HTML 文件,不能指向外部 URL
//manifest.json
{
  "chrome_url_overrides": {
    "newtab": "newtab.html",
    "history": "history.html",
    "bookmarks": "bookmarks.html"
  }
}

4. option(插件选项界面)

Options Page 是 Chrome 扩展提供的设置界面,允许用户在扩展的管理界面(chrome://extensions/)中自定义扩展的行为和存储配置。

主要作用:

  • 让用户修改扩展的设置
  • 保存和读取数据(使用 chrome.storage)
  • 提供交互式 UI
  • 允许用户手动输入或选择配置项
    所谓options页,就是插件的设置页面,有2个入口,一个是右键图标有一个“选项”菜单,还有一个在插件管理页面:

4.1 编写页面

//manifest.json
"options_page": "options/index.html",

注意事项:

  • options_page 指定 options.html 作为选项页面。
  • 必须声明 storage 权限,以便存储和读取用户的设置数据。

options/index.html 页面

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>chrome-devtools-demo</title>
</head>
<body>
    <div id="app"></div>
    <script type="module" src="devtools.js"></script>
    <script type="module" src="../popup/main.js"></script>
</body>
</html>

options.js 暂时可以先不写,先建一个文件就行
main.js 修改下:

import { createApp } from 'vue';
import Antd from 'ant-design-vue';
import App from './App.vue';
import Devtools from '../devtools/Devtools.vue';
import Options from '../options/Options.vue';
import 'ant-design-vue/dist/reset.css';

const app = createApp(App);
const devtools=createApp(Devtools);
const options=createApp(Options);

if (window.location.pathname === '/devtools/index.html') {
    devtools.use(Antd).mount('#app')
}else if(window.location.pathname === '/options/index.html') {
    options.use(Antd).mount('#app');
}else{
    app.use(Antd).mount('#app');
}

4.2 处理用户输入(存储和读取设置)

使用 chrome.storage.sync.get() 加载已有的设置,如果没有,则使用默认值。

// 加载已有的设置
chrome.storage.sync.get(["settingA", "settingB"], (data) => {
    a.value = data.settingA?? true; // 默认启用
    b.value = data.settingB?? "#ff0000"; // 默认红色
});

使用 chrome.storage.sync.set() 保存用户设置。
chrome.storage API 在上一章节已经讲解过用法,这边不再赘述。

4.3 在 Popup 页面中使用 Options Page

chrome.runtime.openOptionsPage()
-允许从 Popup 页面或 service-worker.js 脚本打开 options.html。
-避免用户手动进入 chrome://extensions/ 找到 Options。

5. 桌面通知

Chrome 扩展的 chrome.notifications API 允许扩展程序向用户显示桌面通知,这些通知可以是:

  • 文字通知
  • 图像通知
  • 进度条通知
  • 按钮交互通知

主要作用:

  • 向用户提供重要提醒(如下载完成、消息推送)。
  • 结合 chrome.alarms 定时发送通知。
  • 在后台服务 service worker 运行时向用户提供信息。

官方文档👉点击这里
在 manifest.json 中添加 notifications 权限:

"permissions": ["notifications"]

注意点:

  • notifications 是必需权限,否则无法使用 chrome.notifications API。
  • 必须在 service-worker.js 中运行通知,PopupContent Script 不能直接创建通知。

5.1 发送基本文本通知

//service-worker.js    
chrome.notifications.create("test-notification", {
    type: "basic",
    iconUrl: chrome.runtime.getURL("icons/icon_16x16.png"),
    title: "欢迎使用扩展",
    message: "这是你的第一个桌面通知!",
    priority: 2
});

代码解析
chrome.notifications.create(id, options, callback)

  • id: 通知的唯一 ID(可省略,系统自动生成)。
  • options:
    • type: “basic”(基础通知)。
    • iconUrl: 通知图标(必须是扩展内的 png)。
    • title: 通知标题。
    • message: 通知内容。
    • priority: 通知优先级(0~2)。

Chrome 扩展可能会错误解析 iconUrl,所以你可以尝试用 chrome.runtime.getURL() 转换路径:

5.2 发送图片通知

chrome.notifications.create("image-notification", {
    type: "image",
    iconUrl: chrome.runtime.getURL("icons/icon_16x16.png"),
    title: "图片通知示例",
    message: "这是一个带图片的通知!",
    imageUrl: chrome.runtime.getURL("icons/icon_16x16.png"),
    priority: 1
});

5.3 发送带进度条的通知

let progress = 0;
let interval = setInterval(() => {
    if (progress > 100) {
        clearInterval(interval);
        return;
    }
    chrome.notifications.create("progress-notification", {
        type: "progress",
        iconUrl: chrome.runtime.getURL("icons/icon_16x16.png"),
        title: "下载进度",
        message: `当前进度: ${progress}%`,
        progress: progress
    });
    progress += 10;
}, 1000);

5.4 发送带交互按钮的通知

chrome.notifications.create("interactive-notification", {
    type: "basic",
    iconUrl: chrome.runtime.getURL("icons/icon_16x16.png"),
    title: "是否接受?",
    message: "点击按钮进行操作。",
    buttons: [
        { title: "接受 ✅" },
        { title: "拒绝 ❌" }
    ]
});

监听按钮点击事件

chrome.notifications.onButtonClicked.addListener((notificationId, buttonIndex) => {
    if (notificationId === "interactive-notification") {
        if (buttonIndex === 0) {
            console.log("用户点击了 '接受'");
        } else {
            console.log("用户点击了 '拒绝'");
        }
    }
});

5.5 监听通知点击事件

chrome.notifications.onClicked.addListener((notificationId) => {
    if (notificationId === "test-notification") {
        console.log("用户点击了通知!");
    }
});

5.6 关闭通知

chrome.notifications.clear("test-notification", (wasCleared) => {
    console.log(wasCleared ? "通知已关闭" : "通知不存在");
});

5.7 定时发送通知(结合 chrome.alarms)

chrome.alarms.create("reminder", { delayInMinutes: 1, periodInMinutes: 10 });

chrome.alarms.onAlarm.addListener((alarm) => {
    if (alarm.name === "reminder") {
        chrome.notifications.create({
            type: "basic",
            iconUrl: "icon.png",
            title: "定时提醒",
            message: "10 分钟过去了,该休息一下了!"
        });
    }
});

代码解析

  • chrome.alarms.create() 创建定时器:
  • delayInMinutes : 延迟 1 分钟后触发。
  • periodInMinutes : 每 10 分钟 触发一次。

chrome.alarms.onAlarm.addListener() 监听定时器,当时间到达时发送通知。

5.8 从 Popup 触发通知

popup.js 不能直接创建通知,只能向 service-worker.js 发送消息。
service-worker.js 监听 chrome.runtime.onMessage 并创建通知。
上一章节已经讲过消息通信,这边不再赘述。

6. devtools(开发者工具)

第一章已经讲过,这边不再赘述。

7. 国际化接口

插件根目录新建一个名为 _locales 的文件夹,再在下面新建一些语言的文件夹,如 enzh_CNzh_TW ,然后再在每个文件夹放入一个messages.json。例如:

_locales/en/messages.json
_locales/zh_CN/messages.json

同时必须在清单文件中设置default_locale。

  "default_locale": "en"

_locales\en\messages.json内容:

{
  "name": {
    "message": "chrome-extensions-demo",
    "description": "name"
  }
}

_locales\zh_CN\messages.json内容:

{
  "name": {
    "message": "谷歌插件示例",
    "description": "name"
  }
}

在manifest.json和CSS文件中通过__MSG_messagename__引入,如:

 "name": "__MSG_name__",

JS则直接通过 chrome.i18n.getMessage("name")
官方文档👉点击这里
补充说明:chrome.i18n.getMessage("messageName", [substitutions])

  • messageName : 要获取的消息的名称,它对应于在 _locales 目录下 messages.json 文件中的键。
  • substitutions (可选): 替换字符串数组,用于替换 messages.json 中的占位符。

假设你有一个 _locales/zh_CN/messages.json 文件,内容如下:

//第一种写法
{
  "click_here": {
    "message": "点击这里:$1 和 $2"
  }
}

//第二种写法
{
  "name": {
    "message": "谷歌插件示例",
    "description": "name"
  },
  "click_here": {
    "message": "点击这里:$string1$ 和 $string2$",
    "placeholders": {
      "string1": {
        "content": "$1",
        "example": "描述使用示例"
      },
      "string2": {
        "content": "$2",
        "example": "描述使用示例"
      }
    }
  }
}

在这个例子中,click_here 是消息的名称,而 $1 和 $2 是占位符,用来替换动态内容。
然后在你的 JavaScript 代码中,你可以使用 chrome.i18n.getMessage 来获取并替换这些占位符:

let message = chrome.i18n.getMessage("click_here", ["字符串1", "字符串2"]);
console.log(message);