Изменить 2015
Кто-то сделал проект на NPM с моим решением: https://github.com/lovasoa/react-contenteditable
Редактировать 06/2016: Я только что столкнулся с новой проблемой, которая возникает, когда браузер пытается «переформатировать» HTML-код, который вы ему только что дали, что приводит к постоянному повторному рендерингу компонента. Видеть
Изменить 07/2016: вот моя реализация ContentEditable. У него есть несколько дополнительных опций react-contenteditable
, которые могут вам понадобиться, в том числе:
- блокировка
- императивный API, позволяющий встраивать html-фрагменты
- возможность переформатировать контент
Резюме:
Решение FakeRainBrigand некоторое время работало у меня нормально, пока у меня не возникли новые проблемы. ContentEditables - это боль, и с ними не так просто справиться с React ...
Этот JSFiddle демонстрирует проблему.
Как видите, когда вы вводите какие-то символы и щелкаете по Clear
, содержимое не очищается. Это потому, что мы пытаемся сбросить contenteditable до последнего известного значения виртуального dom.
Так кажется, что:
- Вам нужно
shouldComponentUpdate
предотвратить скачки позиции курсора
- Вы не можете полагаться на алгоритм сравнения VDOM React, если используете
shouldComponentUpdate
этот способ.
Таким образом, вам нужна дополнительная строка, чтобы всякий раз, когда shouldComponentUpdate
возвращает да, вы были уверены, что содержимое DOM действительно обновлено.
Итак, версия здесь добавляет componentDidUpdate
и становится:
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;
}
});
Виртуальный дом остается устаревшим, и, возможно, это не самый эффективный код, но, по крайней мере, он работает :) Моя ошибка устранена
Подробности:
1) Если вы поместите shouldComponentUpdate, чтобы избежать переходов курсора, то contenteditable никогда не будет перерисовываться (по крайней мере, при нажатии клавиш)
2) Если компонент никогда не перерисовывается при нажатии клавиши, то React сохраняет устаревшее виртуальное пространство для этого contenteditable.
3) Если React сохраняет устаревшую версию contenteditable в своем виртуальном dom-дереве, то если вы попытаетесь сбросить contenteditable до значения, устаревшего в виртуальном dom, то во время виртуального dom-diff React вычислит, что нет никаких изменений в обратиться в ДОМ!
В основном это происходит, когда:
- изначально у вас есть пустой контент (shouldComponentUpdate = true, prop = "", предыдущий vdom = N / A),
- пользователь вводит текст, и вы предотвращаете его отображение (shouldComponentUpdate = false, prop = text, previous vdom = "")
- после того, как пользователь нажимает кнопку проверки, вы хотите очистить это поле (shouldComponentUpdate = false, prop = "", previous vdom = "")
- поскольку и новый, и старый vdom "", React не затрагивает dom.
initialValue
вstate
и использовать его вrender
, но я не позволяю Реагировать обновления его дальше.