手把手教你开发第一个 Chrome 扩展程序:网页字数统计插件
手把手教你开发第一个Chrome扩展程序:网页字数统计插件
前言
Chrome扩展程序(Chrome Extension)是基于Web技术(HTML、CSS、JavaScript)开发的浏览器增强工具,可实现自定义浏览体验、数据采集、功能增强等需求。本文将以网页字数统计插件为例,带你从0到1完成Chrome扩展开发,涵盖环境准备、核心功能实现、调试与发布全流程,采用最新的Manifest V3标准(2025年Chrome官方推荐版本),确保兼容性和安全性。
通过本教程,你将掌握:
- Chrome扩展的核心组成结构
- Manifest V3配置文件编写
- 内容脚本(Content Script)与页面交互
- 弹出页面(Popup)开发与数据展示
- 扩展调试与Chrome网上应用店发布流程
一、开发环境准备
1.1 基础工具
- 浏览器:Google Chrome 90+(Manifest V3最低要求版本)
- 代码编辑器:Visual Studio Code(推荐安装插件:Chrome Extension Manifest Helper、ESLint)
- 辅助工具:Chrome开发者工具(F12)、图标生成工具(如Iconifier)
1.2 项目结构创建
- 在电脑中新建文件夹,命名为
WordCountExtension
(扩展项目根目录) - 在根目录下创建以下文件/文件夹结构:
WordCountExtension/
├─ icons/ # 扩展图标文件夹
│ ├─ 16.png # 16x16像素图标(地址栏显示)
│ ├─ 48.png # 48x48像素图标(扩展管理页显示)
│ └─ 128.png # 128x128像素图标(应用商店显示)
├─ manifest.json # 扩展配置文件(核心)
├─ popup.html # 点击扩展图标弹出的页面
├─ popup.js # 弹出页面的逻辑脚本
└─ content.js # 注入网页的内容脚本(统计字数用)
提示:图标尺寸必须严格匹配,可使用在线图标生成工具将一张图片生成多尺寸版本,避免显示异常。
二、核心文件开发
2.1 配置文件:manifest.json(关键)
manifest.json
是Chrome扩展的"身份证",定义了扩展的名称、权限、组件结构等核心信息,Manifest V3相比V2有重大变更(如用Service Worker替代Background Page),需严格按最新规范编写:
{"manifest_version": 3, // 必须为3(V2将于2025年底停止支持)"name": "网页字数统计工具", // 扩展名称(显示在扩展栏和应用商店)"version": "1.0.0", // 版本号(更新时需递增,格式:主.次.修订)"description": "一键统计当前网页的文字数量,支持排除HTML标签和空白字符", // 描述(132字符内)"permissions": ["storage"], // 所需权限(storage用于保存用户设置)"host_permissions": ["<all_urls>"], // 允许注入的网页范围(<all_urls>表示所有网页)"action": { // 扩展图标相关配置"default_popup": "popup.html",// 点击图标弹出的页面"default_icon": { // 不同尺寸的图标"16": "icons/16.png","48": "icons/48.png","128": "icons/128.png"},"default_title": "统计当前网页字数" // 鼠标悬停图标时的提示文字},"content_scripts": [ // 注入网页的内容脚本{"matches": ["<all_urls>"], // 匹配的网页URL(与host_permissions对应)"js": ["content.js"], // 注入的JS文件"run_at": "document_end" // 注入时机(网页DOM加载完成后)}],"icons": { // 扩展管理页显示的图标"16": "icons/16.png","48": "icons/48.png","128": "icons/128.png"}
}
关键说明:
manifest_version:3
:必须指定为3,否则Chrome会拒绝加载host_permissions
:Manifest V3中单独列出网页访问权限,需明确声明content_scripts
:定义何时、向哪些网页注入脚本,run_at:document_end
避免操作未加载的DOM
2.2 内容脚本:content.js(统计网页字数)
content.js
会被注入到匹配的网页中,负责提取网页文本、统计字数,并与弹出页面通信。核心功能:
- 提取网页正文(排除HTML标签)
- 统计总字数、纯文字数(排除空白字符)
- 接收弹出页面的统计请求并返回结果
// content.js:注入网页的内容脚本// 1. 核心函数:统计网页字数
function countWords() {// 提取<body>内所有文本(排除HTML标签)const bodyText = document.body.innerText || '';// 统计总字符数(含空白字符)const totalChars = bodyText.length;// 统计纯文字数(排除空白字符:空格、换行、制表符)const pureText = bodyText.replace(/\s+/g, ''); // 正则替换所有空白字符const pureChars = pureText.length;// 统计单词数(以空格分隔,适用于英文网页)const words = bodyText.trim().split(/\s+/).filter(word => word.length > 0);const wordCount = words.length;return {totalChars, // 总字符数pureChars, // 纯文字数(无空白)wordCount, // 单词数url: window.location.href, // 当前网页URLtitle: document.title // 当前网页标题};
}// 2. 监听来自弹出页面的消息(接收统计请求)
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {// 判断请求类型if (request.action === 'countWords') {// 执行统计并返回结果const result = countWords();sendResponse(result); // 向popup.js发送统计结果}
});
技术细节:
document.body.innerText
:提取网页可见文本,自动排除HTML标签- 正则表达式
/\s+/g
:匹配所有空白字符(空格、换行、制表符),用于纯文字数统计 chrome.runtime.onMessage
:Manifest V3中用于组件间通信的API,替代V2的chrome.extension.onMessage
2.3 弹出页面:popup.html(用户交互界面)
popup.html
是用户点击扩展图标后看到的界面,需简洁直观,包含"统计"按钮和结果展示区域,采用Tailwind CSS简化样式开发(无需本地引入,通过CDN加载):
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>网页字数统计</title><!-- 引入Tailwind CSS(快速构建样式,无需写原生CSS) --><script src="https://cdn.tailwindcss.com"></script><!-- 设置页面宽度(Chrome弹出页默认宽度较窄,需手动指定) --><style>body { width: 320px; padding: 16px; }.result-item { margin: 8px 0; }.result-label { font-weight: 600; color: #374151; }.result-value { color: #111827; }</style>
</head>
<body><!-- 标题 --><h3 class="text-lg font-bold text-center text-gray-800 mb-6">网页字数统计</h3><!-- 统计按钮 --><button id="countBtn" class="w-full py-2 px-4 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors mb-6">开始统计当前网页</button><!-- 结果展示区域(默认隐藏) --><div id="resultContainer" class="hidden"><div class="result-item"><span class="result-label">网页标题:</span><span id="pageTitle" class="result-value truncate"></span></div><div class="result-item"><span class="result-label">总字符数:</span><span id="totalChars" class="result-value"></span></div><div class="result-item"><span class="result-label">纯文字数:</span><span id="pureChars" class="result-value"></span></div><div class="result-item"><span class="result-label">单词数(英文):</span><span id="wordCount" class="result-value"></span></div><!-- 保存结果按钮 --><button id="saveBtn" class="w-full mt-6 py-2 px-4 bg-green-500 text-white rounded-md hover:bg-green-600 transition-colors">保存结果到本地</button></div><!-- 引入弹出页面逻辑脚本(必须放在body末尾,确保DOM加载完成) --><script src="popup.js"></script>
</body>
</html>
设计说明:
- 宽度设置为320px:Chrome弹出页过宽会自动出现滚动条,320px是兼顾内容和体验的最佳宽度
- Tailwind CSS CDN:避免本地引入CSS文件,减少项目体积,适合简单界面
- 结果区域默认隐藏:点击统计按钮后才显示,避免空界面影响用户体验
2.4 弹出页面脚本:popup.js(交互逻辑)
popup.js
负责处理弹出页面的用户交互,包括:
- 点击"统计"按钮,向content.js发送统计请求
- 接收统计结果并更新界面
- 点击"保存"按钮,用Chrome Storage保存结果
// popup.js:弹出页面的逻辑脚本// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', () => {// 获取DOM元素const countBtn = document.getElementById('countBtn');const saveBtn = document.getElementById('saveBtn');const resultContainer = document.getElementById('resultContainer');const pageTitleEl = document.getElementById('pageTitle');const totalCharsEl = document.getElementById('totalChars');const pureCharsEl = document.getElementById('pureChars');const wordCountEl = document.getElementById('wordCount');// 1. 统计按钮点击事件countBtn.addEventListener('click', async () => {try {// 禁用按钮,防止重复点击countBtn.disabled = true;countBtn.textContent = '统计中...';// 获取当前活跃的标签页(用户正在浏览的标签页)const [currentTab] = await chrome.tabs.query({ active: true, currentWindow: true });// 向content.js发送消息(请求统计字数)// 参数1:发送的消息对象,参数2:目标标签页IDconst result = await chrome.tabs.sendMessage(currentTab.id, { action: 'countWords' });// 更新界面显示统计结果resultContainer.classList.remove('hidden');pageTitleEl.textContent = result.title;totalCharsEl.textContent = result.totalChars;pureCharsEl.textContent = result.pureChars;wordCountEl.textContent = result.wordCount;// 保存结果到全局变量,供保存按钮使用window.countResult = result;} catch (error) {// 错误处理(如网页未加载content.js、统计失败)alert('统计失败:' + (error.message || '请刷新网页后重试'));} finally {// 恢复按钮状态countBtn.disabled = false;countBtn.textContent = '开始统计当前网页';}});// 2. 保存按钮点击事件(使用Chrome Storage API)saveBtn.addEventListener('click', async () => {if (!window.countResult) {alert('请先执行统计操作');return;}try {// 禁用按钮saveBtn.disabled = true;saveBtn.textContent = '保存中...';// 获取已保存的历史记录const { history = [] } = await chrome.storage.local.get('history');// 添加当前统计结果(包含时间戳)const newRecord = {...window.countResult,timestamp: new Date().toLocaleString() // 本地时间};history.unshift(newRecord); // 添加到数组开头(最新的在前面)// 限制历史记录数量(最多保存20条)if (history.length > 20) {history.pop(); // 删除最早的记录}// 保存到Chrome本地存储(storage.local:仅当前设备可见)await chrome.storage.local.set({ history });alert('保存成功!已保存到历史记录');} catch (error) {alert('保存失败:' + error.message);} finally {// 恢复按钮状态saveBtn.disabled = false;saveBtn.textContent = '保存结果到本地';}});
});
关键API说明:
chrome.tabs.query
:获取当前活跃标签页信息,参数{active: true, currentWindow: true}
表示当前窗口的活跃标签chrome.tabs.sendMessage
:向指定标签页的content.js发送消息,Manifest V3中必须使用async/await
或回调处理结果chrome.storage.local
:本地存储API,需在manifest.json中声明"storage"
权限,数据仅保存在当前设备,无大小限制(相比localStorage
更适合扩展)
三、扩展加载与调试
3.1 加载未打包扩展到Chrome
开发过程中,需将本地项目加载到Chrome中测试,步骤如下:
- 打开Chrome浏览器,在地址栏输入
chrome://extensions/
进入扩展管理页 - 开启右上角的"开发者模式"(Developer mode)开关
- 点击"加载已解压的扩展程序"(Load unpacked)按钮
- 在弹出的文件选择框中,选择项目根目录
WordCountExtension
- 加载成功后,扩展栏会显示你的插件图标(若未显示,点击扩展栏的"拼图"图标,找到插件并固定)
常见问题:
- 加载失败提示"Manifest文件无效":检查manifest.json是否有语法错误(如逗号遗漏、引号不匹配),Manifest V3不支持注释,需删除所有
//
注释 - 图标不显示:检查
icons
文件夹路径是否正确,图标尺寸是否符合要求 - content.js未注入:检查
manifest.json
的content_scripts.matches
是否包含当前网页URL(如"<all_urls>"
表示所有网页)
3.2 调试技巧(关键)
Chrome提供强大的调试工具,帮助定位扩展中的bug,针对不同组件有不同的调试方式:
3.2.1 调试弹出页面(popup.html/popup.js)
- 点击扩展图标打开弹出页面
- 右键点击弹出页面空白处,选择"检查"(Inspect),打开开发者工具
- 在"Elements"面板查看DOM结构,"Console"面板查看日志,"Sources"面板调试popup.js代码
提示:弹出页面关闭后,调试工具也会关闭,如需保持调试状态,可在弹出页面中按F12
打开工具后,勾选"Keep"选项(在工具右上角)。
3.2.2 调试内容脚本(content.js)
- 打开任意网页(如百度首页)
- 按
F12
打开网页的开发者工具 - 切换到"Sources"面板,在左侧导航栏找到"Content scripts" → 你的扩展名称 → content.js
- 在代码行号处点击设置断点,刷新网页后即可调试
注意:默认情况下,Chrome开发者工具会忽略内容脚本,需在"Sources"面板的"Settings"(齿轮图标)中,取消勾选"Hide content scripts"。
3.2.3 查看扩展错误日志
- 进入扩展管理页(
chrome://extensions/
) - 开启"开发者模式"后,点击你的扩展下方的"查看视图"(Inspect views)
- 在打开的工具中,"Console"面板会显示扩展的所有错误日志(如权限问题、API调用错误)
四、功能测试与优化
4.1 核心功能测试
按以下步骤测试插件是否正常工作:
- 打开任意网页(如一篇博客文章)
- 点击扩展图标,打开弹出页面
- 点击"开始统计当前网页"按钮,查看是否显示正确的统计结果
- 点击"保存结果到本地"按钮,确认是否提示保存成功
- 打开扩展管理页,点击"查看视图" → "storage",检查是否保存了历史记录
4.2 常见问题优化
- 统计结果为0:检查网页是否加载了content.js,可在网页开发者工具的"Console"面板输入
chrome.runtime.sendMessage({action:'countWords'}, console.log)
测试是否返回结果 - 跨域问题:Manifest V3中
host_permissions
需明确声明,若统计特定网站失败,检查该网站是否在matches
列表中 - 性能优化:对于超长网页(如小说网站),统计可能耗时,可在content.js中添加进度提示,或分块处理文本
- 用户体验:添加加载状态(如按钮禁用、加载动画),避免用户重复点击;结果区域添加滚动条,适配长标题
五、打包与发布到Chrome网上应用店
5.1 打包扩展程序
开发完成后,需将项目打包为ZIP文件,用于发布到应用商店:
- 进入Chrome扩展管理页(
chrome://extensions/
) - 点击"打包扩展程序"(Pack extension)按钮
- 在"扩展程序根目录"中选择项目根目录
WordCountExtension
,无需填写"私有密钥文件"(首次打包会自动生成) - 点击"打包扩展程序",生成
WordCountExtension.crx
(打包后的扩展文件)和WordCountExtension.pem
(私有密钥,用于后续更新)
重要提示:私有密钥文件(.pem)需妥善保存,丢失后无法更新已发布的扩展程序。
5.2 发布到Chrome网上应用店
- 创建开发者账号:
-
- 访问Chrome开发者控制台
- 用Google账号登录,支付一次性注册费(20美元,2025年价格)
- 完成账号验证(需提供手机号)
- 准备发布材料:
-
- 打包好的ZIP文件(注意:ZIP文件需包含manifest.json在根目录,不能有多余文件夹)
- 扩展图标(128x128像素,无圆角,背景透明)
- 应用商店展示图(至少1张,尺寸推荐1280x800像素)
- 扩展描述(分短描述和长描述,需说明功能和使用方法,支持Markdown)
- 上传扩展:
-
- 在开发者控制台点击"新建项目",输入扩展名称
- 点击"上传新扩展",选择打包好的ZIP文件
- 检查manifest.json中的信息(名称、版本、权限),确认无误后提交
- 审核与发布:
-
- Chrome网上应用店审核周期通常为1-3个工作日
- 审核通过后,扩展会在应用商店上线,用户可搜索下载
- 审核失败:根据邮件提示修改(常见原因:权限过度申请、功能无法使用、描述与功能不符)
发布最佳实践:
- 权限最小化:仅申请必要的权限(如本插件仅需
storage
和<all_urls>
),避免用户不信任 - 描述清晰:在应用商店描述中说明扩展的使用场景和优势,附截图或GIF演示
- 版本管理:每次更新需递增
manifest.json
中的version
号,如从1.0.0到1.0.1
六、扩展功能扩展建议
本教程实现的字数统计插件是基础版本,你可以在此基础上扩展更多功能,提升实用性:
- 历史记录管理:在popup.html中添加历史记录标签页,展示所有保存的统计结果,支持删除和导出
- 自定义统计规则:添加设置页面,允许用户选择是否统计标点符号、是否排除特定标签(如
<script>
、<style>
) - 自动统计:在manifest.json中添加
background
服务 worker,实现网页加载完成后自动统计,无需手动点击 - 多语言支持:添加
_locales
文件夹,支持中文、英文等多语言界面 - 数据同步:将
chrome.storage.local
改为chrome.storage.sync
,实现多设备统计结果同步(需用户开启Chrome同步功能)
七、总结
通过本教程,你已掌握Chrome扩展开发的核心流程:从项目结构创建、Manifest V3配置、核心组件(Content Script、Popup)开发,到扩展加载调试、打包发布。Chrome扩展开发门槛低(基于Web技术),但功能强大,可根据实际需求灵活扩展。
关键知识点回顾:
- Manifest V3是当前推荐版本,需注意权限声明、组件通信方式的变化
- 内容脚本(Content Script)运行在网页上下文,负责与网页交互
- 弹出页面(Popup)是用户交互界面,通过
chrome.tabs.sendMessage
与内容脚本通信 - Chrome Storage API用于保存用户数据,需在manifest.json中声明权限
后续可深入学习Chrome扩展的高级功能,如后台服务 worker、上下文菜单、通知API等,开发更复杂的扩展程序。