如何限制Draft.js的最大长度

20

如何在Draft.js中限制最大字符数?

我可以使用以下方式获取状态的长度,但如何停止更新组件?

var length = editorState.getCurrentContent().getPlainText('').length;
5个回答

25

你需要定义 handleBeforeInputhandlePastedText 属性。在处理函数中,你需要检查当前内容的长度加上粘贴文本的长度是否达到了最大值,如果是,则应该返回字符串'handled'

更新于 2018 年 3 月 21 日:升级至 React/React-DOM(版本号为 16.2.0)和 Draft.js(版本号为 0.10.5)的最新版本。

工作示例 - https://jsfiddle.net/Ln1hads9/11/

const {Editor, EditorState} = Draft;

const MAX_LENGTH = 10;

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      editorState: EditorState.createEmpty()
    };
  }
  render() {
    return (
      <div className="container-root">
        <Editor
          placeholder="Type away :)"
          editorState={this.state.editorState}
          handleBeforeInput={this._handleBeforeInput}
          handlePastedText={this._handlePastedText}
          onChange={this._handleChange}
        />
      </div>
    );
  }

  _getLengthOfSelectedText = () => {
    const currentSelection = this.state.editorState.getSelection();
    const isCollapsed = currentSelection.isCollapsed();

    let length = 0;

    if (!isCollapsed) {
      const currentContent = this.state.editorState.getCurrentContent();
      const startKey = currentSelection.getStartKey();
      const endKey = currentSelection.getEndKey();
      const startBlock = currentContent.getBlockForKey(startKey);
      const isStartAndEndBlockAreTheSame = startKey === endKey;
      const startBlockTextLength = startBlock.getLength();
      const startSelectedTextLength = startBlockTextLength - currentSelection.getStartOffset();
      const endSelectedTextLength = currentSelection.getEndOffset();
      const keyAfterEnd = currentContent.getKeyAfter(endKey);
      console.log(currentSelection)
      if (isStartAndEndBlockAreTheSame) {
        length += currentSelection.getEndOffset() - currentSelection.getStartOffset();
      } else {
        let currentKey = startKey;

        while (currentKey && currentKey !== keyAfterEnd) {
          if (currentKey === startKey) {
            length += startSelectedTextLength + 1;
          } else if (currentKey === endKey) {
            length += endSelectedTextLength;
          } else {
            length += currentContent.getBlockForKey(currentKey).getLength() + 1;
          }

          currentKey = currentContent.getKeyAfter(currentKey);
        };
      }
    }

    return length;
  }

  _handleBeforeInput = () => {
    const currentContent = this.state.editorState.getCurrentContent();
    const currentContentLength = currentContent.getPlainText('').length;
    const selectedTextLength = this._getLengthOfSelectedText();

    if (currentContentLength - selectedTextLength > MAX_LENGTH - 1) {
      console.log('you can type max ten characters');

      return 'handled';
    }
  }

  _handlePastedText = (pastedText) => {
    const currentContent = this.state.editorState.getCurrentContent();
    const currentContentLength = currentContent.getPlainText('').length;
    const selectedTextLength = this._getLengthOfSelectedText();

    if (currentContentLength + pastedText.length - selectedTextLength > MAX_LENGTH) {
      console.log('you can type max ten characters');

      return 'handled';
    }
  }

  _handleChange = (editorState) => {
    this.setState({ editorState });
  }
}

ReactDOM.render(<Container />, document.getElementById('react-root'))

1
{btsdaf} - devonj
1
@devonJS 很好的观点,谢谢!这个情况最初没有提供。我已经更新了答案,目前我们在将一些内容粘贴到编辑器时会检查所选文本的长度。 - Mikhail Shabrikov
1
@MikhailShabrikov - 当您插入单个字符时,可能需要检查选择长度。目前,您不允许选择所有文本并按键,但允许粘贴。 - Setthase
1
@codename 谢谢,好的建议。我已经修复了,请检查更新后的 fiddle。 - Mikhail Shabrikov
1
有没有人可以向Draft.js提交PR,以添加一个类似于maxlength的属性。那一堆方法是限制所见即所得输入长度的荒谬方式。 - Firanolfind
显示剩余2条评论

4

迈克尔的方法是正确的,但是处理程序返回值不正确。 'not_handled' 是一个穿透案例,允许编辑器组件正常处理输入。在这种情况下,我们希望停止编辑器处理输入。

在早期版本的DraftJS中,看起来字符串的存在在处理代码中被评估为'true',因此上述代码表现正确。在后续的DraftJS版本中,上面的fiddle不起作用-我没有声望在这里发布多个Fiddle,但是请尝试使用v0.10的DraftJS复制迈克尔的代码。

为了更正这个问题,请在您不想让编辑器继续处理输入时返回'handled'或'true'。

修正返回值的fiddle

例如:

_handleBeforeInput = () => {
  const currentContent = this.state.editorState.getCurrentContent();
  const currentContentLength = currentContent.getPlainText('').length

  if (currentContentLength > MAX_LENGTH - 1) {
    console.log('you can type max ten characters');
    return 'handled';
  }
}

请参阅DraftJS文档中关于可取消处理程序的更多信息。

2

这是一个有点老的帖子,但我想为那些面临字符限制和粘贴文本时遇到问题的人分享一个解决方案...

根据Mikhail的上述代码,我很快就组合了一些东西来处理这个用例,它对我有效 - 尽管我没有尝试过优化它。

基本上,处理粘贴文本看起来像这样:

      const __handlePastedText = (pastedText: any) => {
        const currentContent = editorState.getCurrentContent();
        const currentContentLength = currentContent.getPlainText('').length;
        const selectedTextLength = _getLengthOfSelectedText();
    
        if (currentContentLength + pastedText.length - selectedTextLength > MAX_LENGTH) {
            const selection = editorState.getSelection()
            const isCollapsed = selection.isCollapsed()
            const tempEditorState = !isCollapsed ? _removeSelection() : editorState
            _addPastedContent(pastedText, tempEditorState)
          return 'handled';
        }
        return 'not-handled'
      }

我们有一个辅助函数来处理在粘贴新字符之前删除选择的操作,该函数返回新的编辑器状态:

      const _removeSelection = () => {
        const selection = editorState.getSelection()
        const startKey = selection.getStartKey()
                const startOffset = selection.getStartOffset()
                const endKey = selection.getEndKey()
                const endOffset = selection.getEndOffset()
                if (startKey !== endKey || startOffset !== endOffset) {
                    const newContent = Modifier.removeRange(editorState.getCurrentContent(), selection, 'forward')
                    const tempEditorState = EditorState.push(
                        editorState,
                        newContent,
                        "remove-range"
                    )
                    setEditorState(
                        tempEditorState
                    )
                    return tempEditorState
                }
                return editorState
      }

最后是添加���有限制的粘贴文本的函数:

      const _addPastedContent = (input: any, editorState: EditorState) => {
        const inputLength = editorState
        .getCurrentContent()
        .getPlainText().length;
        let remainingLength = MAX_LENGTH - inputLength;

        const newContent = Modifier.insertText(
            editorState.getCurrentContent(),
            editorState.getSelection(),
            input.slice(0,remainingLength)
        ); 
        setEditorState(
            EditorState.push(
                editorState,
                newContent,
                "insert-characters"
            )
        )
      }

示例链接: https://codesandbox.io/s/objective-bush-1h9x6


1

正如Mikhail所提到的,您需要处理输入和粘贴文本。以下是两个处理程序。请注意,粘贴处理程序将保留未超出限制的文本。

function handleBeforeInput(text: string, state: EditorState): DraftHandleValue {
    const totalLength = state.getCurrentContent().getPlainText().length + text.length;
    return totalLength > MAX_LENGTH ? 'handled' : 'not-handled';
  }

function handlePastedText(text: string, _: string, state: EditorState): DraftHandleValue {
    const overflowChars = text.length + state.getCurrentContent().getPlainText().length - MAX_LENGTH;

    if (overflowChars > 0) {
      if (text.length - overflowChars > 0) {
        const newContent = Modifier.insertText(
          state.getCurrentContent(),
          state.getSelection(),
          text.substring(0, text.length - overflowChars)
        );
        setEditorState(EditorState.push(state, newContent, 'insert-characters'));
      }
      return 'handled';
    } else {
      return 'not-handled';
    }
  }

0

让我们花一秒钟来思考一下。是什么被称为进行更改的呢?你的onChange,对吧?很好。我们也知道length。正确吗?我们连接上“工人”,也就是onChange

const length = editorState.getCurrentContent().getPlainText('').length;

// Your onChange function:   
onChange(editorState) {
 const MAX_LENGTH = 10;
 const length = editorState.getCurrentContent().getPlainText('').length;

 if (length <= MAX_LENGTH) {
  this.setState({ editorState }) // or this.setState({ editorState: editorState })
 }
} else {
 console.log(`Sorry, you've exceeded your limit of ${MAX_LENGTH}`)
}

我没有尝试过这个,但我的第六感告诉我它可以正常工作。


不完全是,onchange 的工作仅仅是设置状态,它会对编辑器状态的任何更改产生冲突,而不仅仅是额外字符。 - Omkar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接