update
似乎每个新窗口/iframe/etc都有自己的一组类,因此实例无法使用,因为它们实际上不是同一实例。不过,还不确定该解决方案,除了库不使用Instance OF检查。
tldr :实例在看似相同的实例/代码上行为不同。
我正在构建一个合并地图(MAPBOX)的React后台接口,并想添加一个功能以弹出地图,以便用户可以在单独的显示器上查看它。
使用React.CreatePortal,您可以将组件渲染到窗口。开放元素可正常工作。除了mapbox。不过,此问题不是直接与MAPBOX有关的,MapBox将其映射到一个容器中,您可以在实例化地图时提供该容器作为参数。MAPBOX检查此容器是否是字符串,还是:
instanceof HTMLElement
在正常呈现组件时起作用,但在将组件渲染到弹出/门户时会失败,突然 containe 检查失败。
我已经能够在代码框中复制此内容:https://codesandbox.io/s/qllpz89w39
问题 - 有人知道是什么原因导致这种行为? - 有没有办法将容器"铸造"到htmlelemt
源代码:
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
但是它没有用,所以我认为选项是:
- 实现一个单独的URL,该URL将返回带有MAPBOX的React应用程序,并通过
window.open()
打开其URL - 调整库
instanceof HTMLElement
检查以考虑一个窗口上下文(您应该以某种方式通过)
,但我相信正确的选项是选项#1,因为我真的不确定如果您要实施此类跨窗口JS代码,我真的不确定会有其他陷阱。