Bearbeiten Sie 2015
Jemand hat mit meiner Lösung ein NPM-Projekt erstellt: https://github.com/lovasoa/react-contenteditable
Bearbeiten 06/2016: Ich habe gerade ein neues Problem festgestellt, das auftritt, wenn der Browser versucht, das HTML, das Sie ihm gerade gegeben haben, neu zu formatieren, was dazu führt, dass die Komponente immer wieder neu gerendert wird. Sehen
Edit 07/2016: Hier ist mein Produktionsinhalt. Bearbeitbare Implementierung. Es gibt einige zusätzliche Optionen react-contenteditable
, die Sie möglicherweise möchten, darunter:
- Verriegelung
- Imperative API zum Einbetten von HTML-Fragmenten
- Fähigkeit, den Inhalt neu zu formatieren
Zusammenfassung:
Die Lösung von FakeRainBrigand hat für mich einige Zeit ganz gut funktioniert, bis ich neue Probleme bekam. ContentEditables sind ein Schmerz und nicht wirklich einfach zu handhaben ...
Diese JSFiddle demonstriert das Problem.
Wie Sie sehen können Clear
, wird der Inhalt nicht gelöscht , wenn Sie einige Zeichen eingeben und auf klicken . Dies liegt daran, dass wir versuchen, den inhaltsbearbeitbaren Wert auf den letzten bekannten virtuellen Dom-Wert zurückzusetzen.
So scheint es, dass:
- Sie müssen
shouldComponentUpdate
Caret-Positionssprünge verhindern
- Sie können sich nicht auf den VDOM-Differenzierungsalgorithmus von React verlassen, wenn Sie
shouldComponentUpdate
diese Methode verwenden.
Sie benötigen also eine zusätzliche Zeile, damit Sie bei jeder shouldComponentUpdate
Rückgabe von yes sicher sind, dass der DOM-Inhalt tatsächlich aktualisiert wird.
Die Version hier fügt also ein hinzu componentDidUpdate
und wird:
var ContentEditable = React.createClass({
render: function(){
return <div id="contenteditable"
onInput={this.emitChange}
onBlur={this.emitChange}
contentEditable
dangerouslySetInnerHTML={{__html: this.props.html}}></div>;
},
shouldComponentUpdate: function(nextProps){
return nextProps.html !== this.getDOMNode().innerHTML;
},
componentDidUpdate: function() {
if ( this.props.html !== this.getDOMNode().innerHTML ) {
this.getDOMNode().innerHTML = this.props.html;
}
},
emitChange: function(){
var html = this.getDOMNode().innerHTML;
if (this.props.onChange && html !== this.lastHtml) {
this.props.onChange({
target: {
value: html
}
});
}
this.lastHtml = html;
}
});
Der virtuelle Dom bleibt veraltet und es ist möglicherweise nicht der effizienteste Code, aber zumindest funktioniert er :) Mein Fehler ist behoben
Einzelheiten:
1) Wenn Sie shouldComponentUpdate setzen, um Caret-Sprünge zu vermeiden, wird die inhaltsbearbeitbare Datei nie erneut gerendert (zumindest bei Tastenanschlägen).
2) Wenn die Komponente bei einem Tastendruck nie erneut gerendert wird, behält React einen veralteten virtuellen Dom für diese inhaltsbearbeitbare Datei bei.
3) Wenn React eine veraltete Version von contenteditable in seinem virtuellen Dom-Baum beibehält, und wenn Sie versuchen, die contenteditable auf den Wert zurückzusetzen, der im virtuellen Dom veraltet ist, berechnet React während des virtuellen Dom-Diff, dass keine Änderungen an vorgenommen wurden bewerben Sie sich beim DOM!
Dies geschieht meistens, wenn:
- Sie haben anfangs eine leere inhaltsbearbeitbare Datei (shouldComponentUpdate = true, prop = "", vorherige vdom = N / A),
- Der Benutzer gibt Text ein und Sie verhindern das Rendern (shouldComponentUpdate = false, prop = text, previous vdom = "").
- Nachdem der Benutzer auf eine Validierungsschaltfläche geklickt hat, möchten Sie dieses Feld leeren (shouldComponentUpdate = false, prop = "", previous vdom = "").
- Da sowohl das neu produzierte als auch das alte Vdom "" sind, berührt React das Dom nicht.
initialValue
instate
und verwenden Sie es inrender
, aber ich lasse nicht aktualisiert es weiter reagieren.