handleKeyCommand - "space" 的默认回退功能不起作用

handleKeyCommand - default fallback function for "space" is not working

需要的场景:键入单词后跟解析单词,如果匹配预定义缩写列表则自动替换。

实现方式:自定义 keyBindingFn 属性 其中 space 创建自定义命令 "cc-space"。 handleKeyCommand 事件识别 "cc-space",评估最后输入的单词并执行上述功能。

错误:当文档中建议不匹配 handleKeyCommand returns "not-handled" 以允许 "default command" 时,这似乎被忽略为编辑器当其他一切都按预期工作时,从不在让通时插入 space。

import React from "react"
import { Editor, EditorState, SelectionState, Modifier, getDefaultKeyBinding, KeyBindingUtil } from "draft-js"

const myKeyBindingFn = event => {
  const { hasCommandModifier } = KeyBindingUtil
  if (event.keyCode === 32 && !hasCommandModifier(event)) {
    return "cc-space"
  }
  return getDefaultKeyBinding(event)
}

export default class Note extends React.Component {
  constructor(props) {
    super(props)
    this.state = { editorState: EditorState.createEmpty() }
    this.onChange = this.onChange.bind(this)
    this.handleBeforeInput = this.handleBeforeInput.bind(this)
    this.handleKeyCommand = this.handleKeyCommand.bind(this)
  }

  onChange(editorState) {
    this.setState({ editorState })
  }

  handleBeforeInput(chars, editorState) {
    this.setState({ editorState })
  }

  handleKeyCommand(command, editorState) {
    console.log("command", command)
    if (command === "cc-space") {
      const selectionState = editorState.getSelection()
      const anchorKey = selectionState.getAnchorKey()
      const contentState = editorState.getCurrentContent()
      const currentContentBlock = contentState.getBlockForKey(anchorKey)
      const lastWordEntered = currentContentBlock.getText()

      if (lastWordEntered === "hml") {
        const selectionWord = new SelectionState({
          anchorKey: currentContentBlock.getKey(),
          anchorOffset: 0,
          focusKey: currentContentBlock.getKey(),
          focusOffset: lastWordEntered.length
        })
        const newContentState = Modifier.replaceText(contentState, selectionWord, "heimilislæknir ")
        const nextEditorState = EditorState.push(editorState, newContentState, "insert-characters") // editorState.getLastChangeType()
        this.setState({ editorState: nextEditorState }, this.focus)
        return "handled"
      }
    }
    return "not-handled"
  }

  render() {
    return (
      <Editor
        editorState={this.state.editorState}
        onChange={this.onChange}
        handleBeforeInput={this.handleBeforeInput}
        handleKeyCommand={this.handleKeyCommand}
        keyBindingFn={myKeyBindingFn}
        spellCheck={false}
        autocorrect="off"
      />
    )
  }
}

当您使用自定义按键绑定功能myKeyBindingFn时,您应该为该自定义事件提供自定义逻辑。

例如,如果您从 myKeyBindingFn 中删除 return "cc-space",space 将正常工作。

因此,当用户输入 space:

时,您可以定义自己的逻辑

import React from "react";
import {
  Editor,
  EditorState,
  SelectionState,
  Modifier,
  getDefaultKeyBinding,
  KeyBindingUtil
} from "draft-js";

const myKeyBindingFn = event => {
  const { hasCommandModifier } = KeyBindingUtil;

  if (event.keyCode === 32 && !hasCommandModifier(event)) {
    return "cc-space";
  }
  return getDefaultKeyBinding(event);
};

export default class Note extends React.Component {
  constructor(props) {
    super(props);
    this.state = { editorState: EditorState.createEmpty() };
    this.onChange = this.onChange.bind(this);
    this.handleBeforeInput = this.handleBeforeInput.bind(this);
    this.handleKeyCommand = this.handleKeyCommand.bind(this);
  }

  onChange(editorState) {
    this.setState({ editorState });
  }

  handleBeforeInput(chars, editorState) {
    this.setState({ editorState });
  }

  handleKeyCommand(command, editorState) {
    console.log("command", command);
    if (command === "cc-space") {
      const selectionState = editorState.getSelection();
      const anchorKey = selectionState.getAnchorKey();
      const contentState = editorState.getCurrentContent();
      const currentContentBlock = contentState.getBlockForKey(anchorKey);
      const lastWordEntered = currentContentBlock.getText();

      if (lastWordEntered === "hml") {
        const selectionWord = new SelectionState({
          anchorKey: currentContentBlock.getKey(),
          anchorOffset: 0,
          focusKey: currentContentBlock.getKey(),
          focusOffset: lastWordEntered.length
        });
        const newContentState = Modifier.replaceText(
          contentState,
          selectionWord,
          "heimilislæknir "
        );
        const nextEditorState = EditorState.push(
          editorState,
          newContentState,
          "insert-characters"
        ); // editorState.getLastChangeType()
        this.setState({ editorState: nextEditorState }, this.focus);
        return "handled";
      } else {
        // There are no any matches.
        // We have to implement custom logic to space:

        const newContentState = Modifier.insertText(
          contentState,
          selectionState,
          " "
        );
        const nextEditorState = EditorState.push(
          editorState,
          newContentState,
          "insert-characters"
        );
        this.setState({ editorState: nextEditorState });
      }
    }
    return "not-handled";
  }

  render() {
    return (
      <Editor
        editorState={this.state.editorState}
        onChange={this.onChange}
        handleBeforeInput={this.handleBeforeInput}
        handleKeyCommand={this.handleKeyCommand}
        keyBindingFn={myKeyBindingFn}
        spellCheck={false}
        autocorrect="off"
      />
    );
  }
}

您也可以 return cc-space 仅在必要时才触发事件,而不是实施自定义逻辑来插入 space 字符:

import React from "react";
import {
  Editor,
  EditorState,
  SelectionState,
  Modifier,
  getDefaultKeyBinding,
  KeyBindingUtil
} from "draft-js";

export default class Note extends React.Component {
  constructor(props) {
    super(props);
    this.state = { editorState: EditorState.createEmpty() };
    this.onChange = this.onChange.bind(this);
    this.handleBeforeInput = this.handleBeforeInput.bind(this);
    this.handleKeyCommand = this.handleKeyCommand.bind(this);
  }

  // we move this method to class, becouse we have to get this.state.editorState to recognize the last word
  myKeyBindingFn = event => {
    const { hasCommandModifier } = KeyBindingUtil;

    if (event.keyCode === 32 && !hasCommandModifier(event)) {
      const selectionState = this.state.editorState.getSelection();
      const anchorKey = selectionState.getAnchorKey();
      const contentState = this.state.editorState.getCurrentContent();
      const currentContentBlock = contentState.getBlockForKey(anchorKey);
      const lastWordEntered = currentContentBlock.getText();

      if (lastWordEntered === "hml") {
        // return cc-space only if it's necessary
        return "cc-space";
      }
    }
    // in any other cases we return defaultKeyBinding
    return getDefaultKeyBinding(event);
  };

  onChange(editorState) {
    this.setState({ editorState });
  }

  handleBeforeInput(chars, editorState) {
    this.setState({ editorState });
  }

  handleKeyCommand(command, editorState) {
    console.log("command", command);
    if (command === "cc-space") {
      const selectionState = editorState.getSelection();
      const anchorKey = selectionState.getAnchorKey();
      const contentState = editorState.getCurrentContent();
      const currentContentBlock = contentState.getBlockForKey(anchorKey);
      const lastWordEntered = currentContentBlock.getText();

      if (lastWordEntered === "hml") {
        const selectionWord = new SelectionState({
          anchorKey: currentContentBlock.getKey(),
          anchorOffset: 0,
          focusKey: currentContentBlock.getKey(),
          focusOffset: lastWordEntered.length
        });
        const newContentState = Modifier.replaceText(
          contentState,
          selectionWord,
          "heimilislæknir "
        );
        const nextEditorState = EditorState.push(
          editorState,
          newContentState,
          "insert-characters"
        ); // editorState.getLastChangeType()
        this.setState({ editorState: nextEditorState }, this.focus);
        return "handled";
      }
    }
    return "not-handled";
  }

  render() {
    return (
      <Editor
        editorState={this.state.editorState}
        onChange={this.onChange}
        handleBeforeInput={this.handleBeforeInput}
        handleKeyCommand={this.handleKeyCommand}
        keyBindingFn={this.myKeyBindingFn}
        spellCheck={false}
        autocorrect="off"
      />
    );
  }
}

P.S。 lastWordEntered 包含整个文本,而不是输入的单词。也许,你只想得到一个词——你可以从这里得到解决方案 https://github.com/facebook/draft-js/issues/506