2017-11-13 11 views
5

Korzystam z modułu react-simple-contenteditable, aby umożliwić edycję wypełnienia pustego arkusza roboczego. Powodem, dla którego muszę użyć edytowalnego elementu zawartości zamiast elementu wejściowego, jest to, że chcę zawinąć tekst problemu. Na przykład, jeśli problem ma jedno puste miejsce, dzieli tekst na trzy sekcje część przed pustym, puste i część po. Gdybym miał reprezentować zewnętrzne dwa jako oddzielne div s (lub pola wejściowe), to tekst nie byłby zawijany jak akapit. Zamiast tego, muszę mieć jeden contenteditable div, który zawiera pole wejściowe dla pustego i dowolnego tekstu po obu stronach.Reaktywny kursor z możliwością reagowania przeskakuje do początku

Tekst jest zawijany tak, jak chcę, ale gdy wpiszesz tekst w polu contenteditable, kursor przeskoczy na początek. Nie rozumiem dlaczego, ponieważ próbowałem przykładu na module's github site i działa idealnie, i chociaż moja implementacja jest nieco bardziej skomplikowana, działa zasadniczo tak samo.

Oto moja renderowanie funkcja, która wykorzystuje <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' 
     /> 
    ); 

    } 

Oto onChange funkcja:

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 }); 
    } 

A oto stan odnosi się tylko do rzeczy oczywiste:

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

Wielkie dzięki

Odpowiedz

1

Krótko mówiąc, nie ma prostego sposobu na zrobienie tego. Próbowałem tego sam i spędziłem wiele dni próbując. Zasadniczo musisz zapisać pozycję kursora i zmienić jej położenie po aktualizacji. Wszystko to można osiągnąć window.getSelection()

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

Ale to może się naprawdę trudne w zależności od tego ile treść uległa zmianie.

Skończyło się na używaniu wersji draftJS. Co jest abstrakcją nad contenteditable div przez facebooka.

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

trochę dłużej, aby podnieść, ale będzie w stanie zrobić dużo więcej

+0

Dzięki za odpowiedź! Ponownie przyjrzę się DraftJS, wygląda to dość skomplikowanie. Czy można go zaimplementować tylko dla prostych pól, takich jak to, co robię, czy jest to po prostu dla edycji tekstu sformatowanego, jak to jest reklamowane? –

+0

Może zrobić jedno i drugie. Chociaż nie jest to proste, założę się, że jest prostsze niż zarządzanie stanem kursora. – klugjo

+0

Wracając do tego teraz ... Przeszukałem dokumentację DraftJS i nie mogę znaleźć odpowiedzi na inne pytanie, więc pomyślałem, że być może wiesz: czy mogę utworzyć elementy html zawartości wewnętrznej? Oprócz tekstu, który można edytować, potrzebuję tekstu z ramką wokół niego. –

Powiązane problemy