将父窗口DIV拖入iframe后,如何获取被拖拽元素的引用?
解决父窗口DIV拖拽到iframe后获取元素引用的问题
核心原因
跨文档上下文(父窗口与iframe)的拖拽操作中,dataTransfer默认不会传递DOM元素引用,且不同文档的事件对象无法直接获取源元素,因此需要手动传递标识或通过跨文档通信实现。
同域场景解决方案(最直接)
如果父窗口与iframe同域,可以通过以下步骤实现:
- 父窗口配置拖拽事件
给要拖拽的DIV添加dragstart事件,将元素的唯一ID存入dataTransfer:
// 父窗口代码 const draggableDiv = document.getElementById('your-draggable-div'); draggableDiv.setAttribute('draggable', 'true'); draggableDiv.addEventListener('dragstart', (ev) => { // 存入元素ID,自定义格式也可以,比如"custom-div-id:xxx" ev.dataTransfer.setData('text/plain', draggableDiv.id); });
- iframe中获取源元素
在iframe的drop事件里,通过父窗口的document获取对应ID的元素:
// iframe代码 window.addEventListener('load', e => { let frm = document.body; frm.addEventListener("drop", droppedOn); // 必须阻止dragover的默认行为,否则drop事件不会触发 frm.addEventListener("dragover", (ev) => ev.preventDefault()); }); function droppedOn(ev) { ev.preventDefault(); // 取出父窗口传入的元素ID const divId = ev.dataTransfer.getData('text/plain'); // 访问父窗口的DOM元素 const sourceDiv = window.parent.document.getElementById(divId); if (sourceDiv) { console.log('获取到拖拽的DIV:', sourceDiv); // 后续操作,比如克隆到iframe中 const clonedDiv = sourceDiv.cloneNode(true); document.body.appendChild(clonedDiv); } }
跨域场景解决方案
如果父窗口与iframe不同域,直接访问父窗口DOM会被同源策略阻止,需用postMessage通信:
- 父窗口记录拖拽元素并监听消息
// 父窗口代码 let currentDraggedDiv = null; const draggableDiv = document.getElementById('your-draggable-div'); draggableDiv.setAttribute('draggable', 'true'); draggableDiv.addEventListener('dragstart', (ev) => { currentDraggedDiv = draggableDiv; }); // 监听iframe发来的消息 window.addEventListener('message', (ev) => { if (ev.origin === 'https://your-iframe-domain.com' && ev.data.type === 'GET_DRAGGED_DIV') { // 传递元素的必要信息(不能直接传DOM元素,传序列化数据) ev.source.postMessage({ type: 'DRAGGED_DIV_INFO', data: { id: currentDraggedDiv.id, innerHTML: currentDraggedDiv.innerHTML, style: window.getComputedStyle(currentDraggedDiv).cssText } }, ev.origin); } });
- iframe发送请求并接收数据
// iframe代码 window.addEventListener('load', e => { let frm = document.body; frm.addEventListener("drop", droppedOn); frm.addEventListener("dragover", (ev) => ev.preventDefault()); }); function droppedOn(ev) { ev.preventDefault(); // 向父窗口发送获取拖拽元素信息的请求 window.parent.postMessage({ type: 'GET_DRAGGED_DIV' }, 'https://your-parent-domain.com'); } // 监听父窗口返回的消息 window.addEventListener('message', (ev) => { if (ev.origin === 'https://your-parent-domain.com' && ev.data.type === 'DRAGGED_DIV_INFO') { const divData = ev.data.data; console.log('拖拽元素信息:', divData); // 可以根据数据在iframe中重建元素 const newDiv = document.createElement('div'); newDiv.id = divData.id; newDiv.innerHTML = divData.innerHTML; newDiv.style.cssText = divData.style; document.body.appendChild(newDiv); } });
关键注意点
- 必须在
dragover事件中调用preventDefault(),否则drop事件不会触发。 - 跨域场景下,
postMessage必须指定正确的目标域,避免安全风险。 - 如果不需要原元素引用,只是需要内容,也可以在父窗口
dragstart时直接传递元素的HTML或其他序列化数据。
内容的提问来源于stack exchange,提问作者Andrew Foulds
相关产品推荐
相关产品推荐

