reactjs - React:当焦点子组件卸载时如何捕获焦点
问题描述
我有一个可以获得焦点的父组件。它使用这个焦点来提供键盘控制。该父组件可以生成一个子组件,该子组件同样可以获取焦点,以便它可以响应键盘事件。子组件侦听的键盘事件之一是<esc>
导致子组件被卸载。
当子组件卸载时,焦点返回到<body>
文档的。
我的父组件如何检测到这种情况何时发生并将焦点重新分配给它自己?
到目前为止我所知道的:
- React 的合成
onBlur
处理程序确实从它的孩子那里获得了冒泡的模糊事件(与非合成事件不同)。但是,当具有焦点的元素离开 DOM 时,不会触发模糊事件。 - React 没有实现
onFocusOut
监听器,但如果我直接使用 ref 注册一个监听器,我会收到一个事件,告诉我孩子已卸载。但是,我无法区分子focusout
卸载focusout
触发的事件和用户点击不同点击目标触发的事件。
编辑:我正在寻找一种不涉及父组件和子组件之间直接通信/耦合的解决方案。想象一下,在任意深嵌套的树上,可能有我任意多个这样的孩子。
解决方案
我最终使用 MutationObserver 解决了这个问题。
代码如下所示:
// It's possible for a child component to gain focus and then become
// unmounted. In that case, the browser will return focus to the `<body>`.
// In the following hook, use a `MutationObserver` to watch for that behavior
// and refocus the containing FocusTarget when it happens.
//
// I tried a number of other approaches using `focus/blur/focusin/focusout` on
// various DOM nodes, and was unable to find a solution which would trigger in
// this senario in Firefox. Therefore we use this `MutationObserver` approach.
useEffect(() => {
// Only create the `MutationObserver` within the currently focused target.
if (ref == null || windowId !== focusedWindowId) {
return;
}
const observer = new MutationObserver(mutations => {
// In the common case we won't have focused the body, so we can do this
// inexpensive check first to avoid calling the more expensive `O(n)`
// check of the individual mutations.
if (document.activeElement !== document.body) {
return;
}
if (mutations.some(mutation => mutation.removedNodes.length > 0)) {
ref.focus();
}
});
observer.observe(ref, {
subtree: true,
attributes: false,
childList: true
});
return () => observer.disconnect();
}, [windowId, focusedWindowId, ref]);
添加它的实际提交:https ://github.com/captbaritone/webamp/commit/2dca07ff0a97ad378a1a050513255d2ba129dbcd
推荐阅读
- python - 如何在 python 上使用 BeautifulSoup 和 requests 获取标题
- java - Java Android 删除回收站中的项目大纲
- javascript - 我怎样才能在 javascript 中具有 read().decode()(python) 功能?
- android - 活动永远不会变成请求状态“[DESTROYED, RESUMED, STARTED, CREATED]”(最后一个生命周期转换 =“PRE_ON_CREATE”)
- python-3.x - ImportError - Python3 paramiko /cryptography / libffi
- javascript - 没有类型提交的按钮提交表单
- java - 使用 jemalloc 查看可读的名称
- asp.net-mvc - Html 助手与 IIS 上的相对 url 混淆,在 IISExpress 和 Azure 中正常
- javascript - NextGen Mirth:循环遍历所有 OBR/OBX 段以输出到 Document Writer
- sql - BigQuery 中的重复数据删除