You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome扩展录屏:如何在页面导航/刷新后保持录制及注入脚本存活?

实现页面导航/刷新时保持屏幕录制及悬浮按钮存活的方案

核心思路

将录制逻辑脱离内容脚本,迁移到后台Service Worker(扩展的后台持久进程),同时通过全局注册内容脚本实现悬浮按钮在所有页面自动注入,再借助扩展的消息机制同步录制状态。


1. 重构录制逻辑到后台Service Worker

内容脚本会随页面卸载销毁,因此必须把录制的核心逻辑放在后台:

1.1 后台初始化与状态维护

在background.js(Service Worker)中维护全局录制状态:

let mediaRecorder = null;
let recordedChunks = [];
let currentStream = null;

// 监听来自内容脚本的消息
chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
  switch (message.type) {
    case 'START_RECORDING':
      await startRecording(sender.tab.id);
      sendResponse({ status: 'started' });
      break;
    case 'STOP_RECORDING':
      const blob = await stopRecording();
      sendResponse({ status: 'stopped', blobUrl: URL.createObjectURL(blob) });
      break;
    case 'GET_RECORD_STATUS':
      sendResponse({ isRecording: !!mediaRecorder?.state === 'recording' });
      break;
  }
  return true; // 保持消息通道开放,支持异步响应
});

1.2 实现录制启停逻辑

使用chrome.tabCapture捕获当前标签页流(或chrome.desktopCapture捕获屏幕/窗口,适合跨页面不间断录制):

async function startRecording(tabId) {
  // 停止已有录制
  if (mediaRecorder?.state === 'recording') {
    await stopRecording();
  }

  // 捕获当前标签页的媒体流(若要支持跨页面不间断录制,建议改用desktopCapture捕获窗口/屏幕)
  currentStream = await chrome.tabCapture.capture({
    audio: true,
    video: true,
    videoConstraints: {
      mandatory: {
        chromeMediaSource: 'tab',
        maxWidth: window.screen.width,
        maxHeight: window.screen.height
      }
    }
  });

  // 初始化MediaRecorder
  mediaRecorder = new MediaRecorder(currentStream);
  recordedChunks = [];

  mediaRecorder.ondataavailable = (e) => {
    if (e.data.size > 0) recordedChunks.push(e.data);
  };

  mediaRecorder.onstop = () => {
    currentStream.getTracks().forEach(track => track.stop());
    currentStream = null;
  };

  mediaRecorder.start();
}

async function stopRecording() {
  return new Promise((resolve) => {
    mediaRecorder.onstop = () => {
      const blob = new Blob(recordedChunks, { type: 'video/webm' });
      resolve(blob);
    };
    mediaRecorder.stop();
  });
}

1.3 处理页面导航时的流续接(可选)

如果需要录制标签页的导航过程(而非固定屏幕/窗口),可监听标签页更新事件,在页面加载完成后重新捕获流:

chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
  // 仅当当前正在录制,且页面导航完成时重新捕获流
  if (mediaRecorder?.state === 'recording' && changeInfo.status === 'complete') {
    // 停止旧流
    currentStream?.getTracks().forEach(track => track.stop());
    // 重新捕获新页面的流
    currentStream = await chrome.tabCapture.capture({ audio: true, video: true });
    // 替换MediaRecorder的流(注意:部分浏览器不支持动态换流,可考虑多段录制后合并)
    mediaRecorder.stream = currentStream;
  }
});

2. 实现全局悬浮按钮的持久化注入

通过chrome.scripting.registerContentScripts注册全局内容脚本,确保每个页面加载时自动注入按钮:

2.1 在后台注册内容脚本

在background.js的初始化逻辑中注册:

// 注册全局内容脚本
chrome.runtime.onInstalled.addListener(async () => {
  await chrome.scripting.registerContentScripts([{
    id: 'recorder-button',
    matches: ['<all_urls>'], // 匹配所有页面
    js: ['content.js'],
    runAt: 'document_start', // 页面加载初期注入
    persistAcrossSessions: true
  }]);
});

2.2 内容脚本实现悬浮按钮

在content.js中创建悬浮按钮,并与后台同步状态:

// 创建悬浮按钮
function createRecorderButton() {
  const button = document.createElement('button');
  button.id = 'ext-recorder-btn';
  button.style.cssText = `
    position: fixed;
    bottom: 20px;
    right: 20px;
    padding: 12px 24px;
    background: #ff4444;
    color: white;
    border: none;
    border-radius: 24px;
    font-size: 14px;
    cursor: pointer;
    z-index: 999999;
    box-shadow: 0 2px 8px rgba(0,0,0,0.2);
  `;

  // 初始获取录制状态,更新按钮文本
  updateButtonStatus(button);

  // 点击按钮触发录制启停
  button.addEventListener('click', async () => {
    const status = await chrome.runtime.sendMessage({ type: 'GET_RECORD_STATUS' });
    if (status.isRecording) {
      const result = await chrome.runtime.sendMessage({ type: 'STOP_RECORDING' });
      // 下载录制文件
      const a = document.createElement('a');
      a.href = result.blobUrl;
      a.download = `recording-${Date.now()}.webm`;
      a.click();
      URL.revokeObjectURL(result.blobUrl);
    } else {
      await chrome.runtime.sendMessage({ type: 'START_RECORDING' });
    }
    updateButtonStatus(button);
  });

  document.body.appendChild(button);
}

// 更新按钮文本与样式
async function updateButtonStatus(button) {
  const status = await chrome.runtime.sendMessage({ type: 'GET_RECORD_STATUS' });
  if (status.isRecording) {
    button.textContent = '停止录制';
    button.style.background = '#cc0000';
  } else {
    button.textContent = '开始录制';
    button.style.background = '#ff4444';
  }
}

// 页面加载完成后创建按钮(避免document.body未就绪)
if (document.readyState === 'complete') {
  createRecorderButton();
} else {
  window.addEventListener('load', createRecorderButton);
}

3. 配置manifest.json权限

确保扩展声明所需权限:

{
  "manifest_version": 3,
  "name": "屏幕录制工具",
  "version": "1.0",
  "background": {
    "service_worker": "background.js"
  },
  "permissions": [
    "scripting",
    "tabs",
    "tabCapture"
  ],
  "action": {
    "default_popup": "popup.html"
  }
}

关键说明

  • 录制逻辑后台化:Service Worker不受页面生命周期影响,确保录制过程不中断。
  • 全局内容脚本注册:通过registerContentScripts实现悬浮按钮在所有页面自动注入,无需手动触发。
  • 状态同步:借助chrome.runtime.sendMessage实现内容脚本与后台的实时状态交互,保证按钮显示与实际录制状态一致。
  • 跨页面录制可选方案:若需要完全不间断的录制(如跨标签页导航),建议改用chrome.desktopCapture让用户选择录制整个屏幕或浏览器窗口,而非单个标签页。

内容的提问来源于stack exchange,提问作者Aviato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 19:23:21