Chrome扩展仅在刷新YouTube页面后生效问题求助
问题描述
我为学习制作了一款Chrome扩展,功能是捕获多帧YouTube画面并合并(效果示例:多帧合并效果)。但该扩展仅在刷新页面后才能正常工作。我对JavaScript不太熟悉,推测扩展在页面跳转后被卸载,刷新YouTube页面时能看到加载状态。
以下是扩展的代码文件:
manifest.json
{"name": "some text that not on english","description": "some text that not on english","version": "0.1","manifest_version": 3,"action": {"default_popup": "popup.html","default_icon": {"16": "/icons/icons8-capture-16.png","32": "/icons/icons8-capture-32.png","48": "/icons/icons8-capture-48.png","128": "/icons/icons8-capture-128.png"}},"content_scripts":[{"js": ["contentscript.js" ],"matches":["https://www.youtube.com/watch*"],"run_at": "document_end"}],"permissions" : ["storage", "activeTab", "scripting","tabs"],"host_permissions": ["*://*/"],"icons": {"16": "/icons/icons8-capture-16.png","32": "/icons/icons8-capture-32.png","48": "/icons/icons8-capture-48.png","128": "/icons/icons8-capture-128.png"}}
popup.js
document.addEventListener('DOMContentLoaded', function () {var captureButton = document.getElementById('capture');var saveButton = document.getElementById('save'); captureButton.addEventListener('click', function () {chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {chrome.tabs.sendMessage(tabs[0].id, { action: 'capture' });});}); saveButton.addEventListener('click', function () {chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {chrome.tabs.sendMessage(tabs[0].id, { action: 'save' });});}); });
contentscript.js
let k=0;let obj=[];var image = 0;let imageheight = 0;let imagewidth = 0 ; function picture(){let canvas=document.createElement("canvas"),video=document.querySelector("video"),ctx=canvas.getContext("2d");canvas.width=parseInt(video.offsetWidth),canvas.height=parseInt(video.offsetHeight),ctx.drawImage(video,0,0,canvas.width,canvas.height);imageheight = canvas.height;imagewidth = canvas.width;var base64ImageData1=canvas.toDataURL("image/webp");return base64ImageData1;} function Imagepic(){var image = new Image();image.src=picture();obj[k] = image;k++;} function mergepic(){let canvas=document.createElement("canvas"),video=document.querySelector("video"),ctx=canvas.getContext("2d");let canvas3=document.createElement("canvas"),video3=document.querySelector("video"),ctx3=canvas3.getContext("2d");canvas3.width=parseInt(video3.offsetWidth),canvas3.height=parseInt(video3.offsetHeight*k);for (var i=0; i<obj.length; i++){console.log("a");ctx3.drawImage(obj[i],0,imageheight*i);}var base64ImageData=canvas3.toDataURL("image/webp"),o = new Date(0),p = new Date(video3.currentTime*1000),filename="📷Capture_"+new URL(document.location.href).searchParams.get("v")+"_"+document.title+"@"+new Date(p.getTime()-o.getTime()).toISOString().split("T")[1].split("Z")[0]+"\.webp",a=document.createElement("a");a.download=filename,a.href=base64ImageData,a.click();obj=[];k=0;} chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {if (request.action === 'capture') {Imagepic();} else if (request.action === 'save') {mergepic();}});
解决方案
问题出在YouTube是单页应用(SPA),页面内导航(比如从首页进视频页、视频间跳转)不会触发页面刷新,而你的content script仅在页面首次加载(刷新)时注入,跳转后扩展就失效了。
1. 更新manifest.json
添加background服务工作者,调整权限和注入逻辑:
{ "name": "非英文名称", "description": "非英文描述", "version": "0.1", "manifest_version": 3, "action": { "default_popup": "popup.html", "default_icon": { "16": "/icons/icons8-capture-16.png", "32": "/icons/icons8-capture-32.png", "48": "/icons/icons8-capture-48.png", "128": "/icons/icons8-capture-128.png" } }, "background": { "service_worker": "background.js" }, "permissions": ["storage", "activeTab", "scripting", "tabs"], "host_permissions": ["*://*.youtube.com/*"], "icons": { "16": "/icons/icons8-capture-16.png", "32": "/icons/icons8-capture-32.png", "48": "/icons/icons8-capture-48.png", "128": "/icons/icons8-capture-128.png" } }
2. 创建background.js
监听页面导航,动态注入content script:
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => { if (tab.url?.includes('youtube.com/watch') && changeInfo.status === 'complete') { try { // 检查脚本是否已注入 const [{result}] = await chrome.scripting.executeScript({ target: {tabId}, func: () => typeof chrome.runtime.onMessage.hasListener === 'function' }); if (!result) { await chrome.scripting.executeScript({ target: {tabId}, files: ['contentscript.js'] }); } } catch (err) { console.error('注入脚本失败:', err); } } });
3. 优化contentscript.js
避免重复注册监听器,修复图片加载问题:
let k = 0; let obj = []; let imageheight = 0; let imagewidth = 0; function picture() { const video = document.querySelector("video"); if (!video) return ''; const canvas = document.createElement("canvas"); const ctx = canvas.getContext("2d"); canvas.width = parseInt(video.offsetWidth); canvas.height = parseInt(video.offsetHeight); ctx.drawImage(video, 0, 0, canvas.width, canvas.height); imageheight = canvas.height; imagewidth = canvas.width; return canvas.toDataURL("image/webp"); } function Imagepic() { const imageSrc = picture(); if (!imageSrc) return; const image = new Image(); image.src = imageSrc; obj[k] = image; k++; } function mergepic() { const video = document.querySelector("video"); if (!video || obj.length === 0) return; const canvas3 = document.createElement("canvas"); const ctx3 = canvas3.getContext("2d"); canvas3.width = parseInt(video.offsetWidth); canvas3.height = parseInt(video.offsetHeight * k); // 等待所有图片加载完成再绘制 Promise.all(obj.map(img => new Promise(resolve => img.onload = resolve))) .then(() => { for (let i = 0; i < obj.length; i++) { ctx3.drawImage(obj[i], 0, imageheight * i); } const base64ImageData = canvas3.toDataURL("image/webp"); const videoTime = new Date(video.currentTime * 1000); const filename = `📷Capture_${new URL(document.location.href).searchParams.get("v")}_${document.title}@${videoTime.toISOString().split("T")[1].split("Z")[0]}.webp`; const a = document.createElement("a"); a.download = filename; a.href = base64ImageData; a.click(); obj = []; k = 0; }); } // 避免重复注册消息监听器 if (!chrome.runtime.onMessage.hasListeners()) { chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === 'capture') { Imagepic(); } else if (request.action === 'save') { mergepic(); } }); }
效果说明
- 动态注入:每次进入YouTube视频页(包括SPA跳转)都会自动注入content script,无需刷新页面。
- 监听器去重:防止重复注册导致多次执行逻辑。
- 图片加载优化:合并时等待所有捕获的图片加载完成,避免绘制空白内容。
内容的提问来源于stack exchange,提问作者banalena
相关产品推荐
相关产品推荐

