如何让按键统计JS脚本稳定运行并正确封装为Chrome扩展
问题原因与修复方案
核心故障点
- 剪贴板API参数错误:
navigator.clipboard.writeText传入的是window.getSelection()返回的Selection对象,而非字符串,会直接触发参数错误,未捕获的异常会导致后续代码静默跳过。 - 异步逻辑不规范:剪贴板读写都是异步操作,当前嵌套then的写法未处理异常也未保证执行顺序,频繁触发时容易出现竞态,触发浏览器的操作频率限制后会直接静默失效。
- 事件绑定不稳定:将快捷键事件绑定在
body节点上,当页面动态替换body内容、或其他脚本阻止了keydown事件冒泡时,绑定的事件会直接丢失。 - 无异常捕获逻辑:未对异步操作、DOM操作做异常捕获,只要某一步出现报错(比如
#insert节点不存在、剪贴板权限不足),就会导致后续全部逻辑中断,出现代码块随机跳过的现象。 - 内存存储限制:当前
storage变量存在于内存中,页面刷新、扩展popup关闭都会导致数据丢失,若存在重复绑定事件的情况,还会出现变量覆盖的问题。
修复后的完整代码
document.addEventListener("DOMContentLoaded", function() { // 绑定在document上避免节点替换导致事件丢失 document.addEventListener("keydown", copy_paste); }); console.log('It connected'); // 可以根据需要换成chrome.storage.local实现持久化存储 let storage = {}; async function copy_paste(e) { // 匹配快捷键,加阻止默认避免冲突 if (e.ctrlKey && e.key.toLowerCase() === "q") { e.preventDefault(); try { // 把Selection对象转成字符串 const selectedText = window.getSelection().toString().trim(); if (!selectedText) return; // 无选中文本直接跳过 // 按顺序执行剪贴板读写 await navigator.clipboard.writeText(selectedText); const text = await navigator.clipboard.readText(); // 更新计数 storage[text] = (storage[text] || 0) + 1; mySort(storage); } catch (err) { // 捕获错误避免中断后续逻辑,可自行加日志排查 console.error('操作失败:', err); } } } function show(arrStorage) { try { const parent = document.getElementById("insert"); // 节点不存在直接跳过,避免报错 if (!parent) return; parent.innerHTML = ""; for (let i = 0; i < arrStorage.length; i++) { const para = document.createElement("h4"); para.innerText = `${arrStorage[i][0]} : ${arrStorage[i][1]}`; parent.appendChild(para); } } catch (err) { console.error('渲染失败:', err); } } function mySort(storage) { const arrStorage = Object.entries(storage).sort((a, b) => b[1] - a[1]); show(arrStorage); }
额外适配注意事项
- 若作为Chrome扩展使用,需要在manifest.json中声明
clipboardRead、clipboardWrite权限,避免权限不足导致操作失败。 - 如果是作为content script注入到页面,需要添加防抖逻辑避免事件重复绑定,同时可以用
chrome.storage.local替换内存storage实现跨页面持久化。 - 快捷键触发需要在页面激活的状态下操作,若焦点在地址栏、浏览器控件上时事件不会触发。
内容的提问来源于stack exchange,提问作者FuQ
相关产品推荐
相关产品推荐

