React contenteditable光标跳转到开头

时间:2017-11-13 05:19:44

标签: reactjs contenteditable

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

文本像我想要的那样包装,但是当我在contenteditable字段中键入文本时,光标会跳到开头。我不明白为什么,因为我在module's github site上尝试了这个例子而且效果很好,虽然我的实现有点复杂,但它的工作原理基本相同。

这是我的渲染函数,使用<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'
        />
    );

  }

以下是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 });
  }

以下是它所指的状态,只是为了让事情变得清晰:

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(),
        }
      ]
    }

非常感谢

1 个答案:

答案 0 :(得分:1)

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

来实现

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

但根据您的内容发生了多大变化,它可能变得非常棘手。

我最终使用了draftJS。这是Facebook自己对可信任div的抽象。

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

稍微长一点,但你可以做更多的事情