我们从零开始的、详细的、分步的教程,来创建一个基础的录屏插件。这个插件将能够:
点击浏览器工具栏的图标,弹出一个小窗口。
在小窗口中点击“开始录制”按钮,触发浏览器原生屏幕选择界面。
用户选择要录制的屏幕、窗口或标签页后,开始录制。
点击“停止录制”按钮,结束录制。
生成一个可下载的视频文件(通常是 .webm 格式)。
我们将使用 Manifest V3,这是当前 Chrome 扩展的最新标准。
第一步:创建项目结构
首先,在你的电脑上创建一个新的文件夹,比如 screen-recorder-extension。然后在这个文件夹里,创建以下文件和目录
icons/: 你可以先用任意图片作为占位符,或者从网上找一些免费图标。这些图标会显示在浏览器工具栏和扩展管理页面。
第二步:编写 manifest.json (清单文件)
这是扩展的核心配置文件,它告诉 Chrome 关于这个插件的所有信息,包括名称、权限、脚本等。manifest.json
{ "manifest_version": 3, "name": "简易录屏插件", "version": "1.0", "description": "一个简单的Chrome录屏插件,使用 getDisplayMedia API。", "permissions": [ "storage" ], "background": { "service_worker": "background.js" }, "action": { "default_popup": "popup.html", "default_icon": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } }, "icons": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } }关键点解释:
"manifest_version": 3: 声明我们使用 Manifest V3。
"permissions": ["storage"]: 我们请求 storage 权限,用来在不同脚本之间(比如 popup 和 background)同步录制状态。
"background": { "service_worker": "background.js" }: 指定 background.js 作为我们的 Service Worker。在 V3 中,后台脚本在需要时运行,而不是持续存在,这对于处理录制这种需要持久状态的任务至关重要。
"action": { ... }: 定义了用户在浏览器工具栏上看到和交互的内容。点击图标时,会弹出 popup.html。
第三步:创建用户界面 (popup.html 和 popup.js)
这是用户直接交互的部分。
popup.html
<!DOCTYPE html> <html> <head> <title>录屏插件</title> <style> body { width: 200px; font-family: sans-serif; text-align: center; } button { width: 120px; margin: 5px; padding: 10px; } #status { font-weight: bold; margin: 10px 0; } #downloadLink { display: none; } </style> </head> <body> <h3>简易录屏</h3> <p id="status">空闲</p> <button id="startBtn">开始录制</button> <button id="stopBtn" disabled>停止录制</button> <a id="downloadLink" download="recording.webm">下载视频</a> </body> <script src="popup.js"></script> </html>popup.js
这个脚本负责处理 popup.html 中的按钮点击事件,并与后台脚本 background.js 通信。
const startBtn = document.getElementById('startBtn'); const stopBtn = document.getElementById('stopBtn'); const status = document.getElementById('status'); const downloadLink = document.getElementById('downloadLink'); // 更新UI状态 function updateUI(isRecording, videoUrl = null) { startBtn.disabled = isRecording; stopBtn.disabled = !isRecording; status.textContent = isRecording ? '正在录制...' : '空闲'; if (videoUrl) { downloadLink.href = videoUrl; downloadLink.style.display = 'block'; status.textContent = '录制完成!'; } else { downloadLink.style.display = 'none'; } } // 监听开始按钮点击 startBtn.addEventListener('click', () => { // 向 background.js 发送消息,请求开始录制 chrome.runtime.sendMessage({ type: 'START_RECORDING' }, (response) => { if (response && response.success) { updateUI(true); } else { console.error("无法开始录制:", response.error); status.textContent = '错误:无法开始'; } }); }); // 监听停止按钮点击 stopBtn.addEventListener('click', () => { // 向 background.js 发送消息,请求停止录制 chrome.runtime.sendMessage({ type: 'STOP_RECORDING' }); }); // 监听来自 background.js 的消息,例如录制已停止 chrome.runtime.onMessage.addListener((message) => { if (message.type === 'RECORDING_STOPPED') { updateUI(false, message.url); } }); // 当 popup 打开时,检查当前录制状态 chrome.storage.local.get(['isRecording', 'videoUrl'], (result) => { updateUI(result.isRecording, result.videoUrl); });第四步:编写核心逻辑 (background.js)
这是插件的大脑,它在后台运行,处理实际的屏幕捕获和录制工作。background.js
let mediaRecorder; let recordedChunks = []; let stream; // 监听来自 popup.js 的消息 chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.type === 'START_RECORDING') { startRecording().then(() => { sendResponse({ success: true }); }).catch(err => { sendResponse({ success: false, error: err.message }); }); return true; // 表示我们将异步发送响应 } else if (request.type === 'STOP_RECORDING') { stopRecording(); sendResponse({ success: true }); } }); async function startRecording() { try { // 1. 获取屏幕捕捉的 MediaStream stream = await navigator.mediaDevices.getDisplayMedia({ video: { mediaSource: 'screen' }, audio: true // 如果需要录制系统或麦克风声音 }); // 2. 创建 MediaRecorder 实例 mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm' }); // 3. 清空之前的数据块 recordedChunks = []; // 4. 监听 dataavailable 事件,收集数据块 mediaRecorder.ondataavailable = (event) => { if (event.data.size > 0) { recordedChunks.push(event.data); } }; // 5. 监听 stop 事件,当录制停止时处理数据 mediaRecorder.onstop = () => { const blob = new Blob(recordedChunks, { type: 'video/webm' }); const url = URL.createObjectURL(blob); // 将录制状态和视频URL存入storage chrome.storage.local.set({ isRecording: false, videoUrl: url }); // 向 popup 发送消息,通知录制已停止并附上URL chrome.runtime.sendMessage({ type: 'RECORDING_STOPPED', url: url }); // 你也可以选择直接打开下载页面 // chrome.tabs.create({ url: url }); }; // 6. 开始录制 mediaRecorder.start(); // 7. 更新状态 await chrome.storage.local.set({ isRecording: true, videoUrl: null }); // 当用户手动停止屏幕共享时(例如点击浏览器自带的停止共享按钮) stream.getVideoTracks()[0].onended = () => { stopRecording(); }; } catch (error) { console.error('Error starting recording:', error); await chrome.storage.local.set({ isRecording: false }); throw error; } } function stopRecording() { if (mediaRecorder && mediaRecorder.state !== 'inactive') { mediaRecorder.stop(); } // 停止所有轨道,这样浏览器上的 "正在共享屏幕" 提示才会消失 if (stream) { stream.getTracks().forEach(track => track.stop()); } // 清理 stream = null; mediaRecorder = null; }关键 API 解释:
navigator.mediaDevices.getDisplayMedia(): 这是现代浏览器提供的标准 API,用于请求用户授权捕获屏幕、窗口或标签页。它会返回一个 MediaStream 对象。
MediaRecorder: 这个 API 接收一个 MediaStream,并将其录制成一个媒体文件。
mediaRecorder.ondataavailable: 当 MediaRecorder 收集到一块数据时,这个事件会被触发。我们将这些数据块(chunks)收集起来。
mediaRecorder.onstop: 当录制停止时,这个事件被触发。在这里,我们将所有收集到的数据块合并成一个 Blob 对象。
URL.createObjectURL(blob): 将 Blob 对象转换成一个临时的 URL,这个 URL 可以用于 <a> 标签的 href 属性,从而实现下载。
chrome.runtime.sendMessage: 用于在扩展的不同部分之间(如 popup 和 background)发送消息。
chrome.storage.local: 用于在扩展中存储少量数据,它可以在扩展的不同生命周期中保持存在。
第五步:加载和测试插件
打开 Chrome 浏览器,在地址栏输入 chrome://extensions 并回车。
在右上角,打开 “开发者模式” 的开关。
点击左上角的 “加载已解压的扩展程序” 按钮。
在弹出的文件选择器中,选择你创建的 screen-recorder-extension 整个文件夹。
如果一切顺利,你的插件图标就会出现在浏览器的工具栏上。
测试流程:
点击插件图标,弹出窗口。
点击“开始录制”。浏览器会弹出一个窗口,让你选择要录制的屏幕、应用窗口或标签页。
选择一个目标,点击“共享”。
此时,插件的 UI 会更新为“正在录制...”,并且浏览器的标签页或屏幕上会有正在共享的提示。
再次点击插件图标,然后点击“停止录制”。
录制停止,UI 更新,并出现一个“下载视频”的链接。
点击链接,即可下载你刚才录制的 webm 视频文件。
可能的改进和扩展方向
这个基础版本已经可以工作了,但还有很多可以优化的空间:
录制选项:在 popup.html 中添加选项,让用户选择是否录制麦克风声音、系统声音。
暂停和继续:使用 mediaRecorder.pause() 和 mediaRecorder.resume() 实现暂停/继续功能。
倒计时:开始录制前增加一个 3 秒倒计时。
更好的状态管理:使用 chrome.storage 更精细地管理状态,确保即使 popup 关闭,状态也能正确同步。
格式转换:录制的 webm 格式兼容性不如 mp4。你可以研究使用 ffmpeg.wasm 在浏览器端将 webm 转换为 mp4,但这会大大增加复杂性。
录制特定标签页:使用 chrome.tabCapture.capture() API 可以更精确地录制某个标签页的内容,且无需用户每次都选择。这需要额外的 "tabCapture" 权限。
网友回复