更新
似乎每个新窗口/ iframe / etc等都有其自己的类集,因此instanceof不能工作,因为它们实际上不是同一实例。 不过,除了库不使用instanceof进行检查之外,尚不确定该解决方案。
TLDR :instanceof在看似相同的实例/代码上的行为不同。
我正在构建一个包含地图(地图框)的React后台界面,并希望添加一个功能以弹出地图,以便用户可以在单独的显示器上查看它。
使用React.createPortal,您可以将组件呈现到window.open元素中,效果很好。除了地图框。 问题不仅仅在于mapbox,mapbox会将其地图渲染到容器中,您在实例化地图时将此容器作为参数提供。 Mapbox检查此容器是字符串还是
instanceof HTMLElement
正常渲染组件时可以使用,但是将组件渲染到弹出窗口/门户时会失败,容器检查会突然失败。
我已经能够在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>
);
}
答案 0 :(得分:0)
非常有趣,所以正如您自己说的那样,新窗口具有自己的一组类,而它们的引用不匹配。即:
window.HTMLElement !== popupWindow.HTMLElement
在您的codeandbox示例中,您可以更改检查内容,如下所示,您将看到条件将在弹出窗口中开始满足,并在主窗口中失败:
if (el instanceof popupWindow.HTMLElement) {
setValue("HTMLElement");
} else {
setValue("Unknown");
}
我的初衷是尝试重新分配popupWindow.HTMLElement
:
popupWindow.HTMLElement = HTMLElement
但是它没有用,所以我认为选项是:
window.open()
打开它的URL instanceof HTMLElement
的检查,以考虑到窗口上下文(您应该以某种方式将其传递到此处)但是我相信正确的选择是选择#1,因为我真的不确定如果要实现这种跨窗口JS代码不会有其他麻烦。