背景
最近研究拖拽生成页面,遇到一个跨iframe拖拽的功能的问题。在此记录下心得。
页面里面的 iframe 在没有跨域的情况下,SortableJS 是支持跨iframe拖拽的,官方仓库给了例子。如果跨域了,我们拿不到 iframe 的 contentDocument,无法监听事件,所以 Sortable 默认情况下是不能工作的。
思路 - 模拟拖拽
理论上 Sortable 是通过监听事件来完成拖拽的功能,我们手动构造 drag 事件,通知 Sortable,也是可以完成任务的。
实践 - 模拟拖拽
拖拽需要处理三个事件节点
- dragstart
- dragover
- dragend
dragstart
Sortable 一开始不会在 dom 节点加上 draggable 属性,必须点击了才会,所以模拟时,需要先触发一个 pointdown 事件,然后触发 dargstrat 事件
var downEvent = new PointerEvent("pointerdown", {
// pointerId: 1,
bubbles: true,
cancelable: true,
// pointerType: "touch",
width: 100,
height: 100,
isPrimary: true,
});
var startE = new DragEvent("dragstart", { bubbles: true });
dragover
父页面的 dragover 事件不会传递到 iframe 内(废话),所以我们只能在 iframe 内监听 mousemove 事件, 然后构造一个 dragover 事件,传递给dom,告诉 Sortable 我们拖动了Sortable元素到该dom上面,看看是不是需要改变位置。
document.addEventListener("mousemove", (e) => {
console.log(e.type);
if (e.target.classList.contains("list-group-item")) {
e.target.dispatchEvent(
new DragEvent("dragover", { clientY: e.clientY, bubbles: true }) ); // 用mousemove代替
}
})
dragend
触发被拖拽 dom 的 dragend 事件即可
dragEl.dispatchEvent(new DragEvent("dragend"));
父子页面通讯
在页面中模拟拖拽成功后,接下来就是分开成两个页面,通过 postMessage 通讯
隐藏的 Sortable 实例
这里把隐藏的 Sortable 实例称作影子节点
, 在父页面开始拖拽某个 dom 时,iframe 内部需要同时触发一个 pull mode 的拖拽开始事件,并且将父页面拖拽的 dom 的 innerHTML 写入到影子节点
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。