Chrome扩展:如何通过代码让文档获焦以实现剪贴板粘贴?
解决Chrome扩展切换标签后执行粘贴脚本的文档失焦问题
问题场景
开发Chrome扩展时,通过快捷键(如alt+o)切换到指定标签页并触发剪贴板粘贴操作,标签页成功激活但执行粘贴脚本时抛出异常:
DOMException: Document is not focused.
原因是chrome.tabs.update仅激活标签页,无法立即让页面文档获得焦点,而navigator.clipboard.read和剪贴板事件触发需要文档处于聚焦状态。
解决方案
方案1:等待文档聚焦后执行粘贴
在内容脚本的粘贴函数中,添加等待逻辑,确保文档获得焦点后再执行操作:
// paste.js 修改后 async function pasteContent() { try { // 等待文档聚焦,轮询检查或监听事件 if (!document.hasFocus()) { await new Promise(resolve => { const onFocus = () => { document.removeEventListener('focus', onFocus); resolve(); }; document.addEventListener('focus', onFocus); }); } // 原粘贴逻辑 const wizElement = document.querySelector('c-wiz') const clipboardItems = await navigator.clipboard.read() const firstItem = clipboardItems[0] const blob = await firstItem.getType('image/png') const file = new File([blob], 'image.png', { type: 'image/png' }) const dataTransfer = new DataTransfer() dataTransfer.items.add(file) const pasteEvent = new ClipboardEvent('paste', { bubbles: true, cancelable: true, clipboardData: dataTransfer, }) wizElement.dispatchEvent(pasteEvent) } catch (e) { console.log(e) } }
方案2:利用标签激活事件+消息传递
通过监听标签激活事件,确保标签完全激活后再通知内容脚本执行粘贴,避免过早注入脚本:
// background.js 修改后 async function switchToTabAndPasteContent() { const tab = (await chrome.tabs.query({})).filter(tab => tab.title.toLowerCase().includes('my page'))[0] await chrome.windows.update(tab.windowId, { focused: true }) await chrome.tabs.update(tab.id, { active: true }) // 监听标签激活完成事件 const activationListener = async (activeInfo) => { if (activeInfo.tabId === tab.id) { chrome.tabs.onActivated.removeListener(activationListener) // 向内容脚本发送粘贴指令 await chrome.tabs.sendMessage(tab.id, { action: 'triggerPaste' }) } } chrome.tabs.onActivated.addListener(activationListener) }
// paste.js 添加消息监听 chrome.runtime.onMessage.addListener((message) => { if (message.action === 'triggerPaste') { pasteContent() } }) async function pasteContent() { // 原粘贴逻辑... }
方案3:在Background中读取剪贴板(需额外权限)
将剪贴板读取逻辑移至Background Service Worker,避免内容脚本因失焦无法读取剪贴板,再将内容传递给页面执行粘贴:
// manifest.json 添加权限 { "permissions": [ "tabs", "scripting", "activeTab", "clipboardRead" ], // 其他配置... }
// background.js 修改后 async function switchToTabAndPasteContent() { const tab = (await chrome.tabs.query({})).filter(tab => tab.title.toLowerCase().includes('my page'))[0] await chrome.windows.update(tab.windowId, { focused: true }) await chrome.tabs.update(tab.id, { active: true }) // 在Background读取剪贴板 try { const clipboardItems = await navigator.clipboard.read() const firstItem = clipboardItems[0] const blob = await firstItem.getType('image/png') // 将Blob转为Base64传递给内容脚本 const reader = new FileReader() reader.onload = async () => { const base64Data = reader.result.split(',')[1] await chrome.scripting.executeScript({ target: { tabId: tab.id }, func: (base64) => pasteFromBase64(base64), args: [base64Data] }) } reader.readAsDataURL(blob) } catch (e) { console.log(e) } }
// paste.js 添加Base64转文件并粘贴的函数 function pasteFromBase64(base64) { try { const wizElement = document.querySelector('c-wiz') const byteChars = atob(base64) const byteArr = new Uint8Array(byteChars.length) for (let i = 0; i < byteChars.length; i++) { byteArr[i] = byteChars.charCodeAt(i) } const blob = new Blob([byteArr], { type: 'image/png' }) const file = new File([blob], 'image.png', { type: 'image/png' }) const dataTransfer = new DataTransfer() dataTransfer.items.add(file) const pasteEvent = new ClipboardEvent('paste', { bubbles: true, cancelable: true, clipboardData: dataTransfer, }) wizElement.dispatchEvent(pasteEvent) } catch (e) { console.log(e) } }
内容的提问来源于stack exchange,提问作者vdegenne
相关产品推荐
相关产品推荐

