DraftJs:使用实体键替换实体

DraftJs: Replace an entity using its entity key

我正在使用 draftjs 创建一个富文本编辑器,但找不到任何资源来帮助我解决我的问题。

请先看看codesandbox

您可以看到包含 link(红色的 testtest)的文本。如果你点击它,你会在 table:

中看到 link 的一些信息
|  link src         | http://localhost:8080/testtest |
|  link text        | testtest                       |
|  link Entity key  | ab5a7c6d...                    |

我得到了当前的 link 键 () 感谢我的 getCurrentLinkKey 助手:

const getCurrentLinkKey = (
  editorState: EditorState,
  contentState?: ContentState
): string => {
  if (contentState === undefined) {
    contentState = editorState.getCurrentContent();
  }

  const startKey = editorState.getSelection().getStartKey();
  const startOffset = editorState.getSelection().getStartOffset();
  const blockWithLinkAtBeginning = contentState.getBlockForKey(startKey);

  return blockWithLinkAtBeginning.getEntityAt(startOffset);
};

然后使用此密钥,我可以使用 getCurrentLinkEntity 帮助程序获得 link Entity

const getCurrentLinkEntity = (
  editorState: EditorState
): EntityInstance | null => {
  const contentState = editorState.getCurrentContent();
  const linkKey = getCurrentLinkKey(editorState, contentState);

  if (linkKey) {
    return contentState.getEntity(linkKey);
  }

  return null;
};

使用 link Entity 我终于可以得到 srctext 值:

getCurrentLinkEntity(editorState).getData().url   // 
getCurrentLinkEntity(editorState).getData().text  // 

您可以在底部看到一个按钮 Insert link。如果您 select 整个 link testtest 并单击此按钮,link 将被替换。

此功能由 insertLink 助手处理:

const insertLink = (
  link: string,
  text: string,
  editorState: EditorState,
  setEditorState: (editorState: EditorState) => void
): void => {
  const contentStateWithEntity = editorState
    .getCurrentContent()
    .createEntity("LINK", "MUTABLE", { url: link, text });

  const entityKey = contentStateWithEntity.getLastCreatedEntityKey();

  const contentState = Modifier.replaceText(
    editorState.getCurrentContent(),
    editorState.getSelection(),
    text,
    editorState.getCurrentInlineStyle(),
    entityKey
  );

  const newEditorState = EditorState.set(editorState, {
    currentContent: contentStateWithEntity
  });
  const newEditorStateWithLink = RichUtils.toggleLink(
    newEditorState,
    newEditorState.getSelection(),
    entityKey
  );

  setEditorState(
    EditorState.push(newEditorStateWithLink, contentState, "insert-characters")
  );
};

但此函数只会用 google link 替换您的 selected 文本。我想要的是,如果您在 link 上并单击按钮,那么应该更新整个 link。所以我创造了 replaceLink 助手:

const replaceLink = (
  link: string,
  text: string,
  editorState: EditorState,
  setEditorState: (editorState: EditorState) => void
): void => {
  const contentStateWithEntity = editorState
    .getCurrentContent()
    .createEntity("LINK", "MUTABLE", { url: link, text });

  const entityKey = contentStateWithEntity.getLastCreatedEntityKey();

  const newEditorState = EditorState.set(editorState, {
    currentContent: contentStateWithEntity
  });

  const contentState = newEditorState
    .getCurrentContent()
    .replaceEntityData(getCurrentLinkKey(editorState), { entityKey });

  const newEditorStateWithLink = RichUtils.toggleLink(
    newEditorState,
    newEditorState.getSelection(),
    entityKey
  );

  setEditorState(
    EditorState.push(newEditorStateWithLink, contentState, "insert-characters")
  );
};

但遗憾的是,如果我单击 Replace link 按钮(触发 replaceLink 助手),link 不会更新,但 srctext 为空:

|  link src         |             |
|  link text        |             |
|  link Entity key  | a1e34047... |

所以有人知道如何使用它的实体密钥替换 link Entity

我的答案是使用 draftjs-utils 包并替换 link 但不使用其实体键 :

这个 replaceLink 助手的灵感来自 react-draft-wysiwyg 图书馆的作品:

export const replaceLink = (
  link: string,
  text: string,
  editorState: EditorState,
  setEditorState: (editorState: EditorState) => void
): void => {
  const currentContent = editorState.getCurrentContent();

  // Create new link entity
  const contentStateWithEntity = currentContent.createEntity(
    "LINK",
    "MUTABLE",
    { url: link, text }
  );

  // Get created link entity's key
  const entityKey = contentStateWithEntity.getLastCreatedEntityKey();

  let selection = editorState.getSelection();

  const entityRange = getEntityRange(
    editorState,
    getSelectionEntity(editorState)
  );

  const isBackward = selection.getIsBackward();

  if (isBackward) {
    selection = selection.merge({
      anchorOffset: entityRange.end,
      focusOffset: entityRange.start
    });
  } else {
    selection = selection.merge({
      anchorOffset: entityRange.start,
      focusOffset: entityRange.end
    });
  }

  const updatedEditorWithText = Modifier.replaceText(
    currentContent,
    selection,
    text,
    editorState.getCurrentInlineStyle(),
    entityKey
  );

  const newEditorState = EditorState.push(
    editorState,
    updatedEditorWithText,
    "insert-characters"
  );

  setEditorState(
    EditorState.push(newEditorState, updatedEditorWithText, "insert-characters")
  );
};

点击 codesandbox 观看直播。