admin 管理员组

文章数量: 1184232

 1. 前言

这篇文章将通过一个简单的改变网页背景颜色的扩展程序,带你了解 Chrome 扩展程序的开发流程以及核心概念。

2. 前提条件

  • 了解前端开发,熟悉使用 html,css,javascript。

PS: 我开发的一款AI助手插件已发布至 chrome 应用商店,你可以通过搜索‘顾得助手’安装。或者通过github下载体验最新功能:https://github/herogus/good_ai_chrome_extension 。

3. 核心概念

3.1 整体概览

简而言之,chrome 扩展程序的核心内容主要是以下几个文件:manifest.json、popup.html、content.js、background.js。首先我们先了解这几个文件在浏览器中的位置。

popup.html 和 内容脚本(content.js),内容脚本的日志输出在网页控制台。

background.js

3.2 manifest.json

manifest.json 是 扩展的核心配置文件,用于声明扩展的基本信息、权限、功能模块、脚本资源等。浏览器通过它来识别、加载和运行你的扩展。

:此文件是必须文件,否则导入的扩展程序到chrome 时会报 “无法加载清单文件”。

3.2.1 主要作用:

作用

说明

描述扩展

指定扩展名称、版本、描述等基础信息

定义入口

指定背景脚本(background)、内容脚本(content)、popup 页面、options 页面等

请求权限

声明扩展需要访问的权限(如 storage、tabs、activeTab、scripting)

指定资源

列出图标、页面、脚本、样式等资源文件

控制行为

控制扩展的运行时行为,比如注入哪些页面、加载时机、默认语言等

声明兼容性

指定 manifest版本(如 2 或 3),必须是 V3,Google 已停止对 V2 的支持。

3.2.2 常见配置与说明

下面是以 Manifest V3 版本为例,一个功能完整的扩展程序配置清单:

{
    "manifest_version": 3,
    "name": "我的扩展",
    "version": "1.0.0",
    "description": "这是一个功能完整的 Chrome 扩展",

    "icons": {
        "16": "icons/icon-16.png",
        "48": "icons/icon-48.png",
        "128": "icons/icon-128.png"
    },

    "permissions": [
        "storage",
        "tabs",
        "scripting"
    ],

    "host_permissions": [
        "*://*/*"
    ],

    "background": {
        "service_worker": "background.js"
    },

    "action": {
        "default_popup": "popup.html",
        "default_icon": {
            "16": "icons/icon-16.png",
            "48": "icons/icon-48.png",
            "128": "icons/icon-128.png"
        }
    },

    "options_ui": {
        "page": "options.html",
        "open_in_tab": true
    },

    "content_scripts": [{
        "matches": ["*://*/*"],
        "js": ["content.js"],
        "run_at": "document_idle"
    }],

    "web_accessible_resources": [{
        "resources": [
            "imgs/*",
            "styles/*",
            "scripts/*"
        ],
        "matches": ["*://*/*"]
    }]
}
3.2.2.1 字段说明

字段

二级字段

字段值

字段说明

manifest_version

-

3

清单版本号。必须是 3(V3 是当前标准)。

name

-

"我的扩展"

扩展程序的名称,显示在扩展管理页、Chrome 商店等。

version

-

"1.0.0"

扩展程序的版本号,例如 "1.0.0",用于版本管理和 Chrome 应用商店的更新检测。

description

-

"这是一个功能完整的 Chrome 扩展"

扩展程序的简要描述,说明功能或目的,显示在扩展管理页面和应用商店。

icons

-

-

icons 用来指定不同大小的图标及路径,用于扩展列表、通知、工具栏等。推荐PNG格式。

16

"icons/icon-16.png"

定义16x16像素图标,用于扩展栏或标签页显示。

48

"icons/icon-48.png"

定义48x48像素图标,用于Chrome扩展管理页面显示(chrome://extensions/)。

128

"icons/icon-128.png"

定义128x128像素图标,用于Chrome网上应用店的显示。

permissions

-

["storage", "tabs", "scripting"]

定义基础权限。

storage表示允许使用chrome.storage API存储和检索数据。

tabs表示允许访问和操作浏览器标签页,比如:获取标签页URL、标题,或创建/关闭标签页。

scripting表示允许脚本注入。

host_permissions

-

["*://*/*"]

主机权限,指定可访问的网页 URL,例如:"*://*/*"、"https://*/*"

"*://*/*" 表示所有网页。

background

-

-

后台脚本设置(V3 使用 service_worker)

service_worker

"background.js"

指定后台脚本文件。

action

-

-

定义扩展图标的行为(工具栏按钮)

default_popup

"popup.html"

指定点击扩展图标时弹出的页面路径,提供交互式UI,如设置面板或功能入口。

default_icon

{ "16": "icons/icon-16.png", "48": "icons/icon-48.png", "128": "icons/icon-128.png" }

定义工具栏中显示的图标及路径,优先于icons字段,用于扩展栏显示。

options_ui

-

-

用于配置扩展程序设置界面。

page

"options.html"

设置页面的 HTML 文件路径。

open_in_tab

true

控制选项页面显示方式。

true表示在新标签页打开,推荐;

false表示嵌入式显示。

content_scripts

-

-

网页注入脚本设置(运行在页面上下文中)。

matches

["*://*/*"]

指定内容脚本运行的网页URL模式。

如:"*://*/*"表示所有页面生效。

如何配置见拓展2。

js

["content.js"]

注入的 JS 文件列表。

run_at

"document_idle"

指定脚本注入时机。

document_idle表示页面DOM加载完成后注入,适合大多数内容脚本场景。

document_start 表示在 DOM 创建之前注入,适合拦截页面脚本或注入变量。

document_end表示在 DOM 加载完成后,可操作 DOM 元素但不保证全部加载。

web_accessible_resources

-

-

允许网页访问扩展的资源(如图片、JS、样式)。

resources

["imgs/*", "styles/*", "scripts/*"]

允许网页或内容脚本加载的资源路径。

matches

["*://*/*"]

可访问这些资源的网页 URL 范围。

"*://*/*"表示所有网页可加载这些资源。

3.2.2.2 拓展1permissions 的常用值列表

权限名

类型

说明

storage

基础

使用 chrome.storage存储数据

tabs

基础

访问、操作浏览器标签页

activeTab

基础

临时访问当前激活的标签页,常用于注入脚本

scripting

基础

使用 chrome.scripting API 注入脚本和样式

contextMenus

界面

创建自定义右键菜单项

notifications

界面

显示系统通知

downloads

网络

触发文件下载、监听下载进度

clipboardRead

输入输出

读取剪贴板内容(仅 HTTPS 有效)

clipboardWrite

输入输出

写入剪贴板内容

history

浏览器

读取用户浏览器历史记录

webRequest

网络

拦截和查看网络请求(需 host 权限)

webRequestBlocking

网络

同步阻塞请求(用于拦截器、防广告)

declarativeNetRequest

网络

替代 webRequest的规则型请求拦截(推荐 V3)

proxy

网络

修改浏览器代理设置

cookies

网络

读取和设置网站 Cookies(需配合 host 权限)

bookmarks

界面

读取、添加、删除用户书签

windows

界面

管理浏览器窗口

topSites

浏览器

读取最常访问网站列表

pageCapture

浏览器

将页面保存为 MHTML 格式

idle

系统

检测用户是否空闲

alarms

系统

设置定时任务(周期性操作)

system.cpu

系统

获取 CPU 使用情况(需额外授权)

system.memory

系统

获取内存使用信息

system.display

系统

获取屏幕信息

management

高级

查看或卸载扩展程序(需额外授权)

debugger

高危

调试页面(用户安装时需手动确认)

nativeMessaging

高级

与本地程序通信(需额外安装原生宿主)

3.2.2.3 拓展2matches 配置格式

语法:

<scheme>://<host><path>
  • scheme(协议):http, https, file, ftp, chrome-extension

  • host(域名):可以使用 * 通配符,如 *.google

  • path(路径):可以使用 * 通配任意路径

常用示例:

示例

匹配的页面

"https://*/*"

所有 HTTPS 页面

"http://*.example/*"

example 及其所有子域的 HTTP 页面

"*://mail.google/*"

Gmail 页面(支持 http 和 https)

""

所有网页(强权限,包括 http、https、file、ftp 等)

"file://*"

所有本地文件(需用户勾选“允许访问文件网址”)

配置示例:

"content_scripts": [
  {
    "matches": ["https://*.baidu/*", "https://*.google/*"],
    "js": ["content.js"],
    "run_at": "document_end"
  }
]

3.3 background.js

在 Chrome 扩展中,background.js 是“后台脚本”,用于在浏览器后台常驻运行逻辑,处理事件监听、持久状态管理、消息通信等。

3.3.1 主要作用

作用

说明

📩 消息通信

与 content script、popup、options 页面通信

🧭 事件监听

监听浏览器事件,如 tabs.onUpdated,runtime.onMessage等

📌 状态管理

保持扩展的长期运行状态(如登录状态、缓存)

🧠 定时任务

使用 chrome.alarms 实现周期性执行

🧱 动态注入脚本

使用 chrome.scripting.executeScript 向页面注入代码

⏱ 延迟加载功能

服务工作线程在需要时被唤醒处理事件(V3 特性)

3.3.2 如何配置

在 manifest.json 中,通常通过如下方式声明:

"background": {
  "service_worker": "background.js"
}

3.3.3 注意事项(V3)

  • 不支持使用 window、document 等 DOM API

  • 无法直接访问页面内容,需要通过 tabs 或 scripting 注入

  • 服务工作线程非持续运行,空闲时会被系统回收(如无事件监听器)

3.4 content.js

content.js 是 Chrome 扩展中的 内容脚本(Content Script),作用是注入到网页中,可以直接读取和操作网页 DOM,就像你在控制台编写的脚本一样。

3.4.1 能做什么?

内容脚本是运行在网页上下文中的脚本,能够:

✅ 能做的

🚫 不能做的

操作页面 DOM、CSS

访问 Chrome 扩展 API(如 chrome.tabs)

获取网页上的文本、按钮、链接等

使用 alert、prompt弹窗(部分网站会拦截)

监听用户点击、滚动等交互事件

使用 window.localStorage 可能被沙箱限制

向 background、popup 通信

直接访问后台页面变量

3.4.2 如何配置

在 manifest.json 中,通常通过如下方式声明:

"content_scripts": [
  {
    "matches": ["https://*/*"],
    "js": ["content.js"],
    "run_at": "document_end"
  }
]

3.4.3 注意事项

  • content.js 无法使用像 chrome.tabs, chrome.runtime.onInstalled 等后台 API

  • 每次页面刷新会重新注入脚本(除非 run_at 配置了 document_start)

  • 若要访问页面中变量(如 window.xxx),可能需通过注入 script 标签的方式间接实现

3.4.4 与backgroud.js通信

content.js 向 background.js 发送消息:

chrome.runtime.sendMessage({ type: 'HELLO' }, (response) => {
  console.log('收到回复:', response);
});

background.js 接收:

chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  if (msg.type === 'HELLO') {
    sendResponse('你好,我是后台脚本');
  }
});

3.5 popup.html

在 Chrome 扩展程序中,popup.html 是点击扩展图标时弹出的弹窗界面,可以视为一个迷你网页,它可以包含 HTML、CSS、JS,并可与 background.js、content.js 进行通信。

3.5.1 能做什么?

场景

示例

插件控制面板

打开/关闭功能、切换设置

实时信息展示

当前页面标题、剪贴板内容等

功能触发按钮

注入脚本、发消息、清理页面

输入表单

表单提交、关键字设置等

3.5.2 如何配置

在 manifest.json 中,通常通过如下方式声明:

"action": {
  "default_popup": "popup.html",
  "default_icon": "icons/icon-48.png"
}

3.5.3 注意事项

  • popup.html 是一个 独立页面,与网页和后台是隔离的

  • 不会自动拥有网页上下文(如 DOM、变量),若需要获取需注入内容脚本

  • 页面关闭速度快,操作需尽快完成或在 background 中延续处理逻辑

3.6 通信方式

Chrome 扩展的三个核心脚本:popup(弹窗页面)background(后台脚本)和content script(内容脚本)运行在不同的上下文中,它们之间通过消息传递(Message Passing)机制来通信。

3.6.1 通信方式概览

+------------+           +---------------+           +--------------+
|  popup.html|  <----->  | background.js |  <----->  | content.js   |
+------------+           +---------------+           +--------------+
  • popup ↔ background:直接用 chrome.runtime.sendMessage / onMessage 双向通信

  • background ↔ content:用 chrome.tabs.sendMessage / onMessage 进行通信

  • popup ↔ content:不能直接通信,需通过 background 作为中转(或者使用 chrome.tabs.sendMessage,前提是 popup 访问的是对应 tab)

3.6.2 popup ↔ background 通信

发送消息:

// popup.js
chrome.runtime.sendMessage({ greeting: "hello from popup" }, (response) => {
  console.log("background 回复:", response.reply);
});

接收消息:

// background.js
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  if (msg.greeting === "hello from popup") {
    sendResponse({ reply: "hi popup!" });
  }
});

3.6.3 background ↔ content 通信

background 向 content 发送消息

// background.js
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
  chrome.tabs.sendMessage(tabs[0].id, { greeting: "hello from background" }, (response) => {
    console.log("content 回复:", response.reply);
  });
});

content 接收消息

// content.js
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  if (msg.greeting === "hello from background") {
    sendResponse({ reply: "hi background!" });
  }
});

3.6.4 popup ↔ content 通信

3.6.4.1 直接传递

注意:这种方式要求 content script 已经注入对应页面。

popup 直接发送消息给 content

// popup.js
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
  chrome.tabs.sendMessage(tabs[0].id, { greeting: "hello from popup" }, (response) => {
    console.log("content 回复:", response.reply);
  });
});

content 接收消息

// content.js
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  if (msg.greeting === "hello from popup") {
    sendResponse({ reply: "hi popup!" });
  }
});
3.6.4.2 通过background中转

popup ↔ background ↔ content 中转消息,步骤如下:

  1. popup 发送消息给 background

  2. background 转发消息给 content

  3. content 处理后返回消息给 background

  4. background 把结果返回给 popup

4. 简单的例子

这是一个简单的例子,提供改变页面背景颜色功能。示例内容使用 javascript 编写。

4.1 用例介绍

流程图

4.2 目录结构

hello-extension/
├── background.js
├── content/
│   └── content.js
├── icons/
│   └── icon.png
├── manifest.json
└── popup/
    ├── popup.html
    └── popup.js

注:icon.png 像素大小为 128*128。

4.3 完整代码

manifest.json

{
  "manifest_version": 3,
  "name": "hello world",
  "version": "1.0.0",
  "description": "通过弹出页面改变网页背景颜色",
  "permissions": [
    "activeTab",
    "tabs"
  ],
  "host_permissions": [
    "*://*/*"
  ],
  "action": {
    "default_popup": "popup/popup.html",
    "default_icon": "icons/icon.png"
  },
  "content_scripts": [
    {
      "matches": ["*://*/*"],
      "js": ["content/content.js"],
      "run_at": "document_idle"
    }
  ],
  "background": {
    "service_worker": "background.js"
  }
}

background.js,不参与事件消息传递。

chrome.runtime.onInstalled.addListener(() => {
    console.log('扩展程序已安装');
});

content.js

console.log('内容脚本已加载于:', window.location.href);

function applyBackgroundColor(color, callback) {
  if (document.body) {
    console.log('Body 存在,应用颜色:', color);
    document.body.style.backgroundColor = color + ' !important';
    // 动态插入 style 标签以提高优先级
    const style = document.createElement('style');
    style.textContent = `body { background-color: ${color} !important; }`;
    document.head.appendChild(style);
    callback({ status: '背景颜色已更改' });
  } else {
    console.warn('Body 未找到,延迟尝试');
    setTimeout(() => applyBackgroundColor(color, callback), 100);
  }
}

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  console.log('收到消息:', message);
  if (message.action === 'changeBackground') {
    applyBackgroundColor(message.color, sendResponse);
  }
  return true;
});

popup.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>背景颜色切换器</title>
  <style>
    body {
      font-family: Arial, sans-serif, 'Microsoft YaHei', 'SimSun';
      width: 300px;
      padding: 10px;
      text-align: center;
    }
    h2 {
      font-size: 16px;
      margin: 0 0 10px;
    }
    input[type="color"] {
      width: 100%;
      height: 40px;
      margin: 10px 0;
    }
    button {
      padding: 8px;
      background-color: #4CAF50;
      color: white;
      border: none;
      width: 100%;
      cursor: pointer;
    }
    button:hover {
      background-color: #45a049;
    }
    #error {
      color: red;
      font-size: 12px;
      margin-top: 10px;
    }
  </style>
</head>
<body>
  <h2>选择网页背景颜色</h2>
  <input type="color" id="colorPicker" value="#ffffff">
  <button id="changeColorBtn">应用颜色</button>
  <div id="error"></div>
  <script src="popup.js"></script>
</body>
</html>

popup.js

document.addEventListener('DOMContentLoaded', () => {
    console.log('Popup 脚本已加载');
    const colorPicker = document.getElementById('colorPicker');
    const changeColorBtn = document.getElementById('changeColorBtn');
    const errorDiv = document.getElementById('error');

    changeColorBtn.addEventListener('click', () => {
        const color = colorPicker.value;
        console.log('选择颜色:', color);
        chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
            if (!tabs[0]) {
                console.error('未找到活动标签页');
                errorDiv.textContent = '错误:未找到活动标签页';
                return;
            }
            console.log('向标签页发送消息:', tabs[0].id);
            chrome.tabs.sendMessage(tabs[0].id, { action: 'changeBackground', color: color }, (response) => {
                if (chrome.runtime.lastError) {
                    console.error('消息发送失败:', chrome.runtime.lastError.message);
                    errorDiv.textContent = '错误:无法连接到内容脚本,可能未注入';
                    return;
                }
                if (response) {
                    console.log('收到响应:', response);
                    errorDiv.textContent = response.status;
                } else {
                    console.warn('未收到响应');
                    errorDiv.textContent = '错误:未收到内容脚本响应';
                }
            });
        });
    });
});

4.4 测试

将整个项目拖动到浏览器扩展程序界面。

打开 www.baidu ,点击‘扩展程序’

先选择颜色,再点击应用按钮。

效果

5. 后记

这是简单的使用原生js写的插件用例,后续我将介绍如何使用vue3开发。

6. 参考文档

  • chrome extensions 开发文档
  • Permissions 文档

本文标签: 上手 带你 也行 一篇文章 程序开发