如何检测 @lexical/react 编辑器是否获得焦点?

Mic*_*urz 5 reactjs lexicaljs

我想创建一个可以确定我的编辑器是否具有焦点的函数:

function hasFocus(editor: LexicalEditor) {
  const hasFocus = editor.getEditorState().read(() => {
      // return $...
  })
  
  return hasFocus
}
Run Code Online (Sandbox Code Playgroud)

我浏览了源代码和文档,但没有找到可以直接检测到这一点的方法。在我的测试中,Selection对象似乎无法可靠地确定编辑器是否专注于 DOM。

那么,如何检测编辑器焦点呢?

Mic*_*urz 9

我发现我可以订阅FOCUS_COMMANDBLUR_COMMAND在本地状态发生变化时更新它们:

const useEditorFocus = () => {
  const [editor] = useLexicalComposerContext()
  // Possibly use useRef for synchronous updates but no re-rendering effect
  const [hasFocus, setFocus] = useState(false)
  

  useEffect(
    () =>
      editor.registerCommand(
        BLUR_COMMAND,
        () => {
          setFocus(false)
          return false
        },
        COMMAND_PRIORITY_LOW
      ),
    []
  )

  useEffect(
    () =>
      editor.registerCommand(
        FOCUS_COMMAND,
        () => {
          setFocus(true)
          return false
        },
        COMMAND_PRIORITY_LOW
      ),
    []
  )

  return hasFocus
}
Run Code Online (Sandbox Code Playgroud)

这似乎足够了,但我仍然想知道是否可以直接从事实来源(EditorState)获取信息,而不是通过副作用来跟踪它。


zur*_*fyx 6

扩展你的答案

我们引入命令作为处理输入事件的主要机制,因为我们将默认通过阻止它们event.preventDefault(并且用户可能仍然想监听它们或覆盖它们)。

专注并不是绝对必要的,但遵循相同的命令模式感觉很自然。

// Commands are subscriptions so the default state is important!
const [hasFocus, setHasFocus] = useState(() => {
  return editor.getRootElement() === document.activeElement);
});

useLayoutEffect(() => {
  setHasFocus(editor.getRootElement() === document.activeElement);
  return mergeRegister(
    editor.registerCommand(FOCUS_COMMAND, () => { ... }),
    editor.registerCommand(BLUR_COMMAND, () => { ... }),
  );
}, [editor]);
Run Code Online (Sandbox Code Playgroud)

如果可能的话,您应该useState完全避免,因为 React 重新渲染的成本很高(如果您不需要在该值更改时显示不同的内容)。

请注意,EditorState 没有有关输入是否获得焦点的信息。