让页面兼容 Portal
优化

让页面兼容 Portal

当页面被嵌入到其他环境中时,情况会有些不同。

Rene Wang·
以下内容来自这篇文章

一个带有键盘快捷键的主题提供者——按 Cmd+D 切换深色模式:

function ThemeProvider({ children }) {
	const [theme, setTheme] = useState("light");
 
	useEffect(() => {
		const toggle = (e) => {
			if (e.metaKey && e.key === "d") {
				e.preventDefault();
				setTheme((t) => (t === "dark" ? "light" : "dark"));
			}
		};
		window.addEventListener("keydown", toggle);
		return () => window.removeEventListener("keydown", toggle);
	}, []);
 
	return <div className={theme}>{children}</div>;
}

但如果有人将应用渲染在弹出窗口、iframe 或通过 createPortal 呈现时,该快捷键便会失效。因为监听器被绑定在父窗口上,而不是你的组件所在的窗口。此时应使用 ownerDocument.defaultView:

function ThemeProvider({ children }) {
	const [theme, setTheme] = useState("light");
	const ref = useRef(null);
 
	useEffect(() => {
		const win = ref.current?.ownerDocument.defaultView || window;
		const toggle = (e) => {
			if (e.metaKey && e.key === "d") {
				e.preventDefault();
				setTheme((t) => (t === "dark" ? "light" : "dark"));
			}
		};
		win.addEventListener("keydown", toggle);
		return () => win.removeEventListener("keydown", toggle);
	}, []);
 
	return (
		<div ref={ref} className={theme}>
			{children}
		</div>
	);
}

现在,无论在哪种窗口环境中,该快捷键都能正常工作。

继续探索