React contenteditable光标跳转到开头

Ste*_*son 7 contenteditable reactjs

我正在使用模块react-simple-contenteditable来编辑空白工作表中的填充.我必须使用内容可编辑元素而不是输入元素的原因是因为我希望包装问题的文本.例如,如果问题只有一个空白,它会将文本分为三部分,即空白部分,空白部分和之后的部分.如果我将外部两个表示为单独的divs(或输入字段),则文本不会像段落那样换行.相反,我必须有一个单独的contenteditable div包含左侧空白和自由文本的输入字段.

文本像我想要的那样包装,但是当我在contenteditable字段中键入文本时,光标会跳转到开头.我不明白为什么因为我在模块的github网站上尝试了这个例子并且它工作得很好,虽然我的实现有点复杂,但它的工作方式基本相同.

这是我的渲染函数,它使用<ContentEditable />:

render() {
    const textPieces =
      <div className='new-form-text-pieces'>
        {
          this.props.problem.textPieces.map( (textPiece, idx) => {
            if (textPiece.blank) {
              return (
                  <div data-blank={true} className='blank' key={ textPiece.id } style={{display: 'inline'}}>
                    <input
                      placeholder="Answer blank"
                      className='new-form-answer-input'
                      value={ this.props.problem.textPieces[idx].text }
                      onChange={ (event) => this.props.handleTextPiecesInput(this.props.problemIdx, idx, event.target.value) }
                    />
                    <button className='modify-blank remove-blank' onClick={ (event) => this.props.removeBlank(this.props.problemIdx, idx) }>-</button>

                  </div>
              );
            } else {
              let text = this.props.problem.textPieces[idx].text;
              const placeholder = idx === 0 ? 'Problem text' : '...continue text';
              // text = text === '' ? placeholder : text;
              if (text === '') {
                text = <span style={{color:'gray'}}>{placeholder}</span>;
              } else {

              }
              return (
                this.props.isTextSplit ?
                  <TextPiece
                    key={ textPiece.id }
                    problemIdx={this.props.problemIdx}
                    textPieceIdx={idx}
                    dropBlank={this.props.dropBlank}
                    moveBlank={this.props.moveBlank}
                  >
                    <div style={{display: 'inline-block', }}>{text}</div>
                  </TextPiece>
                : text

              );
            }
          })
        }
      </div>;



    return (
       this.props.isTextSplit ? textPieces :
        <ContentEditable
          html={ReactDOMServer.renderToStaticMarkup(textPieces)}
          className="my-class"
          tagName="div"
          onChange={ (event, value) => this.props.handleProblemChange(event, this.props.problemIdx, value) }
          contentEditable='plaintext-only'
        />
    );

  }
Run Code Online (Sandbox Code Playgroud)

这是onChange功能:

handleProblemChange(event, problemIdx) {
    const problems = cloneDeep(this.state.problems);
    event.target.children[0].childNodes.forEach( (textPieceNode, idx) => {
      if (textPieceNode.constructor === Text) {
        problems[problemIdx].textPieces[idx].text = textPieceNode.wholeText;
      } else {
        problems[problemIdx].textPieces[idx].text = textPieceNode.childNodes[0].value;
      }
    });
    this.setState({ problems });
  }
Run Code Online (Sandbox Code Playgroud)

这是它所指的国家,只是为了让事情变得清晰:

this.state = {
  problems: [
    {
      id: shortid.generate(),
      textPieces: [
        {
          text : "Three days was simply not a(n)",
          blank : false,
          id: shortid.generate(),
        },
        {
          text : "acceptable",
          blank : true,
          id: shortid.generate(),
        },
        {
          text : "amount of time to complete such a lot of work.",
          blank : false,
          id: shortid.generate(),
        }
      ]
    }
Run Code Online (Sandbox Code Playgroud)

非常感谢

klu*_*gjo 3

长话短说,没有简单的方法可以做到这一点。我自己也尝试过,并花了几天时间尝试。基本上,您必须保存光标位置并在更新后自行重新定位。所有这些都可以通过 window.getSelection() 来实现

https://developer.mozilla.org/en-US/docs/Web/API/Window/getSelection

但这可能会变得非常棘手,具体取决于您的内容发生了多少变化。

我最终使用了draftJS。这是 facebook 本身对 contenteditable div 的抽象。

https://draftjs.org/docs/overview.html#content

拿起的时间有点长,但你将能够做更多的事情