嵌套iFrame场景下如何获取浏览器视口的DragEvent.clientY
解决拖拽经过iFrame时获取浏览器视口clientY的问题
当拖拽元素经过iFrame时,event.clientY会返回相对于iFrame内部视口的坐标,要拿到浏览器视口的坐标,可以用以下两种方案:
方案一:通过屏幕坐标转换计算
利用event.screenY(鼠标相对于屏幕的绝对位置)结合浏览器窗口的偏移量,直接转换为浏览器视口的坐标,无需修改iFrame内容:
<div onDrag={(e) => { // 兼容不同浏览器的窗口顶部偏移量 const screenTop = window.screenTop || window.screenY; // 计算浏览器标题栏+边框的高度 const browserChromeHeight = window.outerHeight - window.innerHeight; // 转换为浏览器视口的clientY const browserClientY = e.screenY - screenTop - browserChromeHeight; console.log(browserClientY); }} draggable={true} style={{ width: "100px", height: "100px", background: "black", display: "flex", alignItems: "center", justifyContent: "center", }} > <iframe style={{ width: "50px", height: "50px", background: "white" }} /> </div>
方案二:监听iFrame内部拖拽事件并转换坐标
如果需要更精准的结果,且iFrame同域可操作,可以在iFrame内部监听拖拽事件,通过postMessage传递坐标到父页面,再结合iFrame在浏览器视口的位置计算最终值:
父页面代码
<div onDrag={(e) => { // 处理非iFrame区域的拖拽 console.log(e.clientY); }} draggable={true} style={{ width: "100px", height: "100px", background: "black", display: "flex", alignItems: "center", justifyContent: "center", }} > <iframe id="targetIframe" srcdoc="<script> // iFrame内部监听拖拽事件 document.addEventListener('dragover', (e) => { e.preventDefault(); // 允许拖拽元素经过 // 向父页面传递iFrame内部的clientY window.parent.postMessage({ type: 'dragOverIframe', clientY: e.clientY }, '*'); }); </script>" style={{ width: "50px", height: "50px", background: "white" }} /> </div> <script> // 监听iFrame传递的消息 window.addEventListener('message', (event) => { if (event.data.type === 'dragOverIframe') { const iframe = document.getElementById('targetIframe'); // 获取iFrame相对于浏览器视口的位置 const iframeRect = iframe.getBoundingClientRect(); // 转换为浏览器视口的clientY const browserClientY = event.data.clientY + iframeRect.top; console.log(browserClientY); } }); </script>
注意事项
- 若iFrame是跨域的,无法直接注入内部脚本,此时只能使用方案一。
- 方案一在浏览器窗口缩放、多显示器场景下可能存在微小偏差,但绝大多数普通场景下足够使用。
内容的提问来源于stack exchange,提问作者Chay
相关产品推荐
相关产品推荐

