Chrome 插件开发实战:5 分钟上手 + 原理深度解析

Chrome 插件开发实战:5 分钟上手 + 原理深度解析

本文带你从零做出第一个插件,再深入理解底层运行机制。

一、5 分钟做出你的第一个插件

Chrome 插件本质上就是一个文件夹,里面放几个文件。

最小结构(只需 2 个文件)

dart 复制代码
hello-extension/
├── manifest.json   ← 插件的"身份证"
└── popup.html      ← 点击图标弹出的页面

动手做

1. 创建 manifest.json

json 复制代码
{
  "manifest_version": 3,
  "name": "Hello 插件",
  "version": "1.0.0",
  "action": {
    "default_popup": "popup.html"
  }
}

2. 创建 popup.html

html 复制代码
<!DOCTYPE html>
<html>
<head>
  <style>
    body { width: 200px; padding: 20px; text-align: center; }
  </style>
</head>
<body>
  <h2>🎉 成功了!</h2>
</body>
</html>

3. 加载到 Chrome

  1. 地址栏输入 chrome://extensions/
  2. 打开右上角「开发者模式」
  3. 点击「加载已解压的扩展程序」
  4. 选择文件夹

点击工具栏图标,看到弹窗就成功了!


二、理解插件的运行机制

2.1 插件的三个运行环境

Chrome 插件有三个独立的运行环境,它们各司其职:

scss 复制代码
┌──────────────────────────────────────────────────────────────┐
│                       Chrome 浏览器                           │
│                                                              │
│  ┌────────────────┐                                          │
│  │    Popup       │  用户界面                                 │
│  │   (弹窗页面)    │  • 点击图标时创建,关闭即销毁              │
│  │                │  • 有自己独立的 DOM 和 JS 上下文           │
│  └───────┬────────┘                                          │
│          │                                                   │
│          │ chrome.scripting.executeScript()                  │
│          ▼                                                   │
│  ┌────────────────────────────────────────────────────────┐ │
│  │                    网页 (Web Page)                      │ │
│  │  ┌──────────────────────────────────────────────────┐  │ │
│  │  │              Content Script                       │  │ │
│  │  │              (注入的脚本)                          │  │ │
│  │  │                                                   │  │ │
│  │  │  ✅ 可以访问网页 DOM                               │  │ │
│  │  │  ✅ 可以读取 localStorage / Cookie                 │  │ │
│  │  │  ✅ 发起请求时自动携带该网站的登录态                │  │ │
│  │  │  ❌ 不能访问网页的 JS 变量                         │  │ │
│  │  └──────────────────────────────────────────────────┘  │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                              │
│  ┌────────────────┐                                          │
│  │  Background    │  后台服务                                 │
│  │ (Service Worker)│  • 监听浏览器事件(标签切换、安装等)      │
│  │                │  • 处理跨页面的逻辑                        │
│  │                │  • 按需唤醒,空闲时休眠                    │
│  └────────────────┘                                          │
└──────────────────────────────────────────────────────────────┘

2.2 为什么要有 Content Script?

这是很多新手困惑的点。看这个场景:

需求:做一个插件,点击按钮后获取当前网页的 Cookie

错误做法:直接在 popup.js 里读

javascript 复制代码
// ❌ 这样拿到的是插件自己的 Cookie,不是网页的
document.cookie  // 空的

正确做法:注入代码到网页执行

javascript 复制代码
// ✅ 把代码注入到网页上下文执行
chrome.scripting.executeScript({
  target: { tabId: tab.id },
  func: () => document.cookie  // 这行代码在网页里执行
});

原理图解

javascript 复制代码
Popup 的世界                    网页的世界
┌─────────────┐                ┌─────────────┐
│ popup.js    │                │ example.com │
│             │                │             │
│ document    │                │ document    │
│ .cookie     │                │ .cookie     │
│   ↓         │                │   ↓         │
│  空的       │   注入代码 →    │ "token=xxx" │
└─────────────┘                └─────────────┘
   独立沙箱                        网页上下文

2.3 三种环境的能力对比

能力 Popup Content Script Background
显示界面
访问网页 DOM
读取网页 Cookie
发请求带网页登录态
使用 Chrome APIs 部分
持久运行

三、权限系统详解

3.1 权限声明

在 manifest.json 中声明需要的权限:

json 复制代码
{
  "permissions": ["activeTab", "scripting", "storage"],
  "host_permissions": ["https://example.com/*"]
}

3.2 常用权限速查

权限 用途 什么时候需要
activeTab 访问当前标签页 获取页面 URL、标题
scripting 注入脚本到网页 操作网页内容
storage 存储数据 保存用户设置
cookies 读写 Cookie 管理登录态
tabs 管理所有标签页 批量操作标签
notifications 发送通知 提醒用户

3.3 host_permissions 的作用

json 复制代码
"host_permissions": ["https://example.com/*"]

这行配置决定了:

  • 你的插件能往哪些网站注入代码
  • 你的插件能访问哪些网站的 Cookie

最小权限原则 :只申请需要的域名,不要用 <all_urls>


四、数据通信机制

javascript 复制代码
// popup.js
const [result] = await chrome.scripting.executeScript({
  target: { tabId: tab.id },
  func: (param) => {
    // 这段代码在网页里执行
    console.log('收到参数:', param);
    return document.title;
  },
  args: ['hello']  // 传参
});

console.log('网页标题:', result.result);

4.2 各组件间通信

javascript 复制代码
// 发送消息
chrome.runtime.sendMessage({ action: 'getData' });

// 接收消息
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.action === 'getData') {
    sendResponse({ data: 'hello' });
  }
});

4.3 数据存储

javascript 复制代码
// 存储(异步)
await chrome.storage.local.set({ token: 'xxx' });

// 读取
const { token } = await chrome.storage.local.get('token');

// 监听变化
chrome.storage.onChanged.addListener((changes) => {
  console.log('数据变了:', changes);
});

五、实战案例:API 调用器

5.1 需求

做一个插件,在 erp.example.com 网站上一键调用 API,自动携带登录态。

5.2 难点分析

scss 复制代码
直接从 popup.js 发请求:
  popup.js → fetch(erp.example.com) → ❌ 跨域,没有 Cookie

解决方案:
  popup.js → 注入代码到网页 → 在网页里 fetch → ✅ 同源,有 Cookie

5.3 核心代码

javascript 复制代码
// popup.js
document.getElementById('btn').onclick = async () => {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  
  const [result] = await chrome.scripting.executeScript({
    target: { tabId: tab.id },
    func: async (apiParams) => {
      // ↓↓↓ 这段代码在网页上下文执行 ↓↓↓
      
      // 读取 Cookie 中的 token
      const getToken = () => {
        const match = document.cookie.match(/token=([^;]+)/);
        return match ? match[1] : '';
      };
      
      // 发起请求(自动携带 Cookie)
      const response = await fetch('/api/data', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${getToken()}`,
          'Content-Type': 'application/json'
        },
        credentials: 'include',
        body: JSON.stringify(apiParams)
      });
      
      return await response.json();
    },
    args: [{ key: 'value' }]
  });
  
  console.log('API 返回:', result.result);
};

5.4 manifest.json

json 复制代码
{
  "manifest_version": 3,
  "name": "API 调用器",
  "version": "1.0.0",
  "action": { "default_popup": "popup.html" },
  "permissions": ["activeTab", "scripting"],
  "host_permissions": ["https://erp.example.com/*"]
}

六、调试技巧

调试目标 方法
Popup 页面 右键插件图标 → 检查弹出内容
注入的代码 网页 F12 → Console
Background 扩展管理页 → 点击「Service Worker」
网络请求 网页 F12 → Network

热更新 :修改代码后,去 chrome://extensions/ 点刷新按钮


七、常见坑点

7.1 图标不显示

css 复制代码
❌ icon.svg   → Chrome 不支持 SVG
✅ icon.png   → 必须是 PNG,建议 128x128

7.2 代码不生效

javascript 复制代码
// ❌ 错误:executeScript 的 func 不能引用外部变量
const url = 'https://api.com';
chrome.scripting.executeScript({
  func: () => fetch(url)  // url 是 undefined!
});

// ✅ 正确:通过 args 传参
chrome.scripting.executeScript({
  func: (url) => fetch(url),
  args: ['https://api.com']
});

7.3 跨域问题

sql 复制代码
症状:fetch 报 CORS 错误
原因:从 popup.js 直接请求其他域名
解决:用 executeScript 注入到目标网页执行

八、发布到 Chrome 商店

  1. 注册开发者账号(一次性 $5)
  2. 打包成 zip(不含 node_modules)
  3. 上传到 Chrome Web Store
  4. 填写描述、截图、隐私政策
  5. 等待审核(1-3 天)

九、总结

css 复制代码
Chrome 插件 = manifest.json + 界面 + 逻辑

三个运行环境:
├── Popup      → 用户界面,点击图标显示
├── Content    → 注入网页,操作页面内容
└── Background → 后台服务,监听事件

核心技能:
├── chrome.scripting.executeScript → 注入代码到网页
├── chrome.storage → 存储数据
└── chrome.runtime.sendMessage → 组件间通信

掌握这些,你就能开发 90% 的 Chrome 插件了。

参考资料

相关推荐
攀登的牵牛花1 天前
前端向架构突围系列 - 架构方法(一):概述 4+1 视图模型
前端·设计模式·架构
Hashan1 天前
Vue 3 中 v-for 动态组件 ref 收集失败问题排查与解决
前端·vue.js·前端框架
bobringtheboys1 天前
[el-tag]使用多个el-tag,自动判断内容是否超出
前端·javascript·vue.js
ccccc__1 天前
基于vue3完成领域模型架构建设
前端
Cherry的跨界思维1 天前
【AI测试全栈:Vue核心】19、Vue3+ECharts实战:构建AI测试可视化仪表盘全攻略
前端·人工智能·python·echarts·vue3·ai全栈·ai测试全栈
尽欢i1 天前
用 return“瘦身“if-else:让代码少嵌套、好维护
前端·javascript
程序员Agions1 天前
小程序"邪修"秘籍:那些官方文档不会告诉你的骚操作
前端·javascript
Charlo1 天前
手把手配置 Ralph -- 火爆 X 的全自动 AI 编程工具
前端·后端·github
我真的叫奥运1 天前
scss mixin svg 颜色控制 以及与 png 方案对比讨论
前端·svg