在 iframe 中渲染 React 组件时如何正确引用本地文档

问题描述 投票:0回答:1

我有一个调用

document
全局的组件。当我在 iframe 中渲染此组件时,它使用当前(父)文档作为参考,而不是 iframe 的文档。

export const Modal: FC<ModalProps> = ({ opened, ...props }) => {
  // ...

  useEffect(() => {
    // Prevent background scrolling when the modal is opened.
    // This line locks scroll on the main DOM, but I only want it to be blocked on the iframe.
    document.body.style.overflow = opened ? "hidden" : "";
  }, [opened]); 

  // ...
}

我可以渲染

Modal
组件,以便
document
引用 iframe 文档(而不是主 DOM)吗?

我使用这个自定义组件在单独的 iframe 中渲染 React 元素:

import { FC, DetailedHTMLProps, IframeHTMLAttributes, useEffect, useMemo, useState } from "react";

import { createPortal } from "react-dom";

export const IFrame: FC<DetailedHTMLProps<IframeHTMLAttributes<HTMLIFrameElement>, HTMLIFrameElement>> = ({ children, style, ...props }) => {
  const [contentRef, setContentRef] = useState<HTMLIFrameElement | null>(null);
  const headNode = useMemo(() => contentRef?.contentWindow?.document?.head, [contentRef]);
  const mountNode = useMemo(() => contentRef?.contentWindow?.document?.body, [contentRef]);

  // Setup head.
  useEffect(() => {
    if (headNode) {
      // Inherit parent styles (like compiled css modules or local fonts).
      for (const style of Array.from(document.head.querySelectorAll("link"))) {
        headNode.appendChild(style.cloneNode(true));
      }
      for (const style of Array.from(document.head.querySelectorAll("style"))) {
        headNode.appendChild(style.cloneNode(true));
      }
    }
  }, [headNode]);

  return (
    <>
      <iframe
        {...props}
        style={{ border: "none", ...style }}
        ref={setContentRef}
      />
      {mountNode ? createPortal(children, mountNode) : null}
    </>
  );
});

我还尝试创建一个新的根并渲染其中的子级,但它也不起作用。

useEffect(() => {
  if (mountNode) {
    const root = createRoot(mountNode);
    root.render(children);

    return () => {
      root.unmount();
    };
  }
}, [mountNode]);

return (
  <iframe
    {...props}     
    style={{ border: "none", ...style }}
    ref={setContentRef}
  />
);
reactjs iframe react-dom
1个回答
0
投票

由于没有其他人尝试过这一点,请原谅这个答案中的一些猜测。

我认为这里发生的是,当您将内容放入 React 的

<iframe>
元素中时,它会使用
srcdoc
属性创建内容,而不是更正常的
src
。这会导致您的 iframe 内容与您的父页面存在于同一 DOM 上下文中。

要解决这个问题,我认为您要么需要强制 React 将新页面加载到您的 iframe 中,要么将您之后的上下文数据存储在此组件内,并将 setState 方法传递给您的子节点。

© www.soinside.com 2019 - 2024. All rights reserved.