永久性顶层界面

Web 功能: moveBefore()

使用 appendChild() 或 insertBefore() 等传统方法在 DOM 中移动打开的 <dialog>、popover 或全屏元素时,浏览器会隐式地从 DOM 中移除该元素,然后重新插入。此移除操作会重置状态,导致打开的模态窗口、弹出式窗口和全屏元素突然关闭。

如需在不中断用户体验或不关闭顶层元素的情况下重新设置其父级,请改用原子 moveBefore() API。

重新设置打开的顶层元素的父级

moveBefore() 接受两个参数:要移动的节点,以及要在其前面插入的参考节点(或 null,用于附加到新父节点的末尾)。

const newParent = document.getElementById('new-container');
const dialogElement = document.getElementById('my-dialog');

// MANDATORY: Use moveBefore to ensure the <dialog> or popover stays open.
// Passing null appends it to the end of newParent.
newParent.moveBefore(dialogElement, null);

后备策略

由于 moveBefore() 是一项渐进增强功能,因此您必须先使用功能检测,然后再调用它。对于旧版浏览器,您必须回退到传统的重定父级。

强制性:对于不受支持的浏览器中的 <dialog> 元素,传统移动操作会关闭对话框。如果您需要保持其打开状态,则必须在移动后手动重新打开。

const targetParent = document.getElementById('target-container');
const popoverOrDialog = document.getElementById('my-top-layer-element');

// Check if moveBefore is supported
if ('moveBefore' in Element.prototype) {
  targetParent.moveBefore(popoverOrDialog, null);
} else {
  // Fallback: traditional move.
  // Note: This WILL close <dialog>, popover, and fullscreen elements.
  const wasOpen = popoverOrDialog.hasAttribute('open') || popoverOrDialog.matches(':popover-open');
  targetParent.insertBefore(popoverOrDialog, null);
  
  // Manually restore state if possible
  if (wasOpen && typeof popoverOrDialog.showModal === 'function') {
    popoverOrDialog.showModal();
  } else if (wasOpen && typeof popoverOrDialog.showPopover === 'function') {
    popoverOrDialog.showPopover();
  }
}