【问题标题】:How to automatically expand the selection to the entire linked text in Draft.js?如何自动将选择范围扩展到 Draft.js 中的整个链接文本?
【发布时间】:2019-06-25 23:56:40
【问题描述】:

我正在使用 Draft.js 开发一个富文本编辑器(太棒了!)。以下代码允许用户编辑链接,在逻辑上工作正常,但我对用户体验不满意。

如果用户选择链接的一部分并运行此代码,则此代码将该链接分成多个链接,这不是用户想要的。

例如,如果一个阶段“买这本书”与 URL-A 链接,并且用户选择“买这个”,并将其更改为 URL-B,则该部分将与 URL-B 链接,但“ book”仍然与 URL-A 链接。

理想情况下,当用户选择链接文本的一部分时,我想自动将选择扩展到整个链接,然后执行此代码。

但是,我不知道该怎么做(将选择扩展到整个链接)。

editLink = () => {
    const { editorState } = this.state;
    const selection = editorState.getSelection();
    if (selection.isCollapsed()) {
      return;
    }

    let url = ''; // default
    const content = editorState.getCurrentContent();
    const startKey = selection.getStartKey();
    const startOffset = selection.getStartOffset();
    const blockWithLinkAtBeginning = content.getBlockForKey(startKey);
    const linkKey = blockWithLinkAtBeginning.getEntityAt(startOffset);
    if (linkKey) {
      const linkInstance = content.getEntity(linkKey);
      url = linkInstance.getData().url;
    }

    let link = window.prompt("Paste the link", url);
    if (!link) {
      console.log("removing link");
      const newEditorState = RichUtils.toggleLink(editorState, selection, null);
      this.setState({ editorState: newEditorState });
      return;
    }
    console.log("adding a link", link);
    const contentWithEntity = content.createEntity('LINK', 'MUTABLE', { url: link });
    const entityKey = contentWithEntity.getLastCreatedEntityKey();
    const newEditorState = EditorState.set(editorState, { currentContent: contentWithEntity });
    const yetNewEditorState = RichUtils.toggleLink(newEditorState, newEditorState.getSelection(), entityKey);

    this.setState({ editorState: yetNewEditorState} );
  }

非常感谢任何帮助或建议。

【问题讨论】:

标签: reactjs draftjs


【解决方案1】:

有两种方法可以做到这一点。第一个可能是您正在尝试的 - 在当前链接之上应用一个新链接,从而覆盖它。这不是最好的方法,但可以做到。

第二个更简单。在ContentState 对象中,有一个方法replaceEntityData()。所以你可以像这样实现它:

editLink = () => {
    const { editorState } = this.state;
    const selection = editorState.getSelection();
    if (selection.isCollapsed()) {
      return;
    }

    let url = ''; // default
    const content = editorState.getCurrentContent();
    const startKey = selection.getStartKey();
    const startOffset = selection.getStartOffset();
    const block = content.getBlockForKey(startKey);
    const linkKey = block.getEntityAt(startOffset);

    let link = window.prompt("Paste the link", url);
    if (!link) { //REMOVING LINK
        var contentWithRemovedLink = content;
        block.findEntityRanges(charData => { //You need to use block.findEntityRanges() API to get the whole range of link

            const entityKey = charData.getEntity();
            if (!entityKey) return false;
            return entityKey === linkKey //Need to return TRUE only for your specific link. 
        }, (start, end) => {
                const entitySelection = new SelectionState({
                    anchorKey: block.getKey(),  //You already have the block key
                    focusKey: block.getKey(),
                    anchorOffset: start,   //Just use the start/end provided by the API
                    focusOffset: end })
                contentWithRemovedLink = Modifier.applyEntity(content, entitySelection, null)

            return;
        })

        const newEditorState = EditorState.set(
            editorState, { currentContent: contentWithRemovedLink });
        return;
    }
    console.log("adding a link", link);

    //CHANGING LINK
    const contentWithUpdatedLink = content.replaceEntityData(linkKey, { url: link });
    const newEditorState = EditorState.set(editorState, { currentContent: contentWithUpdatedLink });
    //Now do as you please.
  }

删除链接:

ContentBlock api 上有一个名为findEntityRanges() 的方法。该函数有两个参数:

  1. (char: CharacterMetadata) => boolean:字符元数据对象的过滤函数(每个连续的 ENTITY + INLINE_STYLE 组合都有一个唯一的CharacterMetatdata 对象。您可以从那里通过characterMetadata.getEntity() 访问实体。)。如果此函数执行为 TRUE,则执行 (2)。
  2. (start: number, end: number) => void。这使您可以访问执行 TRUE 的每个特定字符范围的开始和结束偏移量。现在你可以随心所欲地开始和结束。

之后,您可以使用包含整个链接的新 SelectionState 应用 NULL 实体。这将删除链接实体。

更改链接:

您已经拥有linkKey。只需调用 content.replaceEntityData(linkKey, {url: "MY NEW URL"}) 以使用新 URL 生成新的 ContentState。此处定义的 API:https://draftjs.org/docs/api-reference-content-state#replaceentitydata

【讨论】:

    猜你喜欢
    • 2018-04-15
    • 1970-01-01
    • 2015-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多