更新
似乎每个新窗口/ iframe / etc都有自己的一组类,因此instanceof不会工作,因为它们实际上并不是同一个实例。虽然不确定解决方案,但库不使用instanceof进行检查。
TLDR:instanceof在看似相同的实例/代码上表现不同。
我正在构建一个React后台界面,它包含一个地图(mapbox),并希望添加一个功能来弹出地图,以便用户可以在单独的显示器上查看它。
使用React.createPortal,您可以将组件渲染到一个可以很好地工作的window.open元素。除了mapbox。问题不是直接与mapbox有关,mapbox将其映射到容器中,在实例化地图时将此容器作为参数提供。 Mapbox检查此容器是否为字符串,或者:
instanceof HTMLElement
这在正常渲染Component时有效,但在将组件渲染到弹出/门户时失败,突然容器检查失败。
我已经能够在codeandbox中重现这个:https://codesandbox.io/s/qllpz89w39
问题 - 有没有人知道导致这种行为的原因是什么? - 有没有办法将容器“转换”为HTMLElement
源代码:
import React from "react";
import ReactDOM from "react-dom";
function App() {
return (
<div className="App">
<h1>Weird bug</h1>
<PortalTest t="Normal" />
<WithPortal>
<PortalTest t="In Portal" />
</WithPortal>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
function WithPortal({ children }) {
const div = document.createElement("div");
const popupWindow = window.open(
"",
"test",
"width=600px,height=640px,left=100,top=100,toolbar=no,menubar=no,location=no"
);
if (!popupWindow) {
return (
<div style={{ background: "red", padding: "16px", color: "white" }}>
<h1>Popup blocked</h1>
<p>Please allow popups for codesandbox to see the full script</p>
</div>
);
}
popupWindow.document.body.appendChild(div);
return ReactDOM.createPortal(children, div);
}
function PortalTest({ t }) {
const ref = React.useRef(null);
const [value, setValue] = React.useState("idle");
const [el, setEl] = React.useState(null);
React.useEffect(
() => {
if (el) {
if (el instanceof HTMLElement) {
setValue("HTMLElement");
} else {
setValue("Unknown");
}
}
},
[el]
);
function setRef(x) {
setEl(x);
}
return (
<div ref={setRef}>
<h3>{t}</h3>
Found ref type: {value}
</div>
);
}
非常有趣,因为你自己说一个新窗口有自己的一组类,它们的引用不匹配。即:
window.HTMLElement !== popupWindow.HTMLElement
在您的codesandbox示例中,您可以按如下方式更改检查,您将看到它将在弹出窗口中开始实现并在主窗口中失败:
if (el instanceof popupWindow.HTMLElement) {
setValue("HTMLElement");
} else {
setValue("Unknown");
}
我的第一个目的是尝试重新分配popupWindow.HTMLElement
:
popupWindow.HTMLElement = HTMLElement
但它不起作用,所以我认为选项是:
window.open()
打开它instanceof HTMLElement
检查以考虑窗口上下文(你应该以某种方式通过那里)但我认为正确的选项是选项#1,因为如果你打算实现这样的跨窗口JS代码,我真的不确定是否会有其他陷阱。