为框架页面设置全局键盘事件监听器时的竞态条件问题
搞定框架页面全局键盘事件异常的问题
我太懂这种frameset页面踩坑的感觉了!毕竟每个frame都是独立的小页面,直接在主页面绑全局监听很容易因为加载时机不对或者上下文隔离出问题,尤其是用户提前输入的时候。给你几个实用的解决方案:
1. 等所有frame加载完再统一绑定监听
主页面的frameset加载完不代表里面的frame内容都加载好了,这时候绑定事件肯定会失效。你可以在主页面写个逻辑,等所有frame都加载完成后再给每个frame(包括主窗口)绑键盘事件:
// 主页面的脚本,放head里或者frameset后面都行 function handleKeyPress(e) { // 这里写你的键盘事件处理逻辑,比如判断按键做对应操作 console.log('按下了:', e.key); } function bindAllKeyboardListeners() { // 先给主窗口绑 window.addEventListener('keydown', handleKeyPress); // 遍历所有frame,给每个frame的window也绑 const allFrames = window.frames; for (let i = 0; i < allFrames.length; i++) { try { // 跨域的frame会报错,加个try-catch避免卡死 allFrames[i].window.addEventListener('keydown', handleKeyPress); } catch (err) { console.warn(`没法给第${i}个frame绑事件:`, err); } } } // 监听所有frame的加载状态 let loadedFrameCount = 0; const totalFrames = window.frames.length; // 给每个frame加load监听 for (let i = 0; i < totalFrames; i++) { allFrames[i].window.addEventListener('load', () => { loadedFrameCount++; // 所有frame都加载完了再绑事件 if (loadedFrameCount === totalFrames) { bindAllKeyboardListeners(); } }); } // 如果没有frame,主页面加载完直接绑 window.addEventListener('load', () => { if (totalFrames === 0) { bindAllKeyboardListeners(); } });
2. 用加载遮罩阻止用户过早输入
如果用户总喜欢在页面没加载完就瞎点瞎输,不如直接加个加载遮罩,等所有内容就绪了再让用户操作:
/* 主页面的样式 */ .loading-mask { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255,255,255,0.9); display: flex; align-items: center; justify-content: center; z-index: 9999; font-size: 18px; }
<!-- 把遮罩放在frameset前面 --> <div class="loading-mask" id="loadingMask">页面加载中,请稍候...</div> <frameset rows="*" cols="250,*" framespacing="3" frameborder="yes" border="1" class="doc-result-frameset"> <!-- 你的frame内容 --> </frameset>
// 就在刚才的bindAllKeyboardListeners函数里加一行,隐藏遮罩 function bindAllKeyboardListeners() { // ...之前的绑定逻辑 document.getElementById('loadingMask').style.display = 'none'; }
3. 跨域frame的特殊处理
如果你的frame里有跨域的页面,直接绑事件会被浏览器的同源策略拦住。这时候得让每个子frame自己绑键盘事件,然后通过postMessage把事件信息传给主页面:
// 子frame里的脚本 window.addEventListener('keydown', (e) => { // 把按键信息发给主页面 window.parent.postMessage({ type: 'keyPressed', key: e.key }, '*'); }); // 主页面的脚本,加个message监听 window.addEventListener('message', (e) => { if (e.data.type === 'keyPressed') { // 这里处理子frame传过来的按键事件 handleKeyPress({ key: e.data.key }); } });
内容的提问来源于stack exchange,提问作者Vic Seedoubleyew
相关产品推荐
相关产品推荐

