编辑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
防止插入符位置跳动
- 如果使用
shouldComponentUpdate
这种方式,则不能依赖React的VDOM差异算法。
因此,您需要额外的一行,以便每当shouldComponentUpdate
返回yes时,就可以确保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;
}
});
虚拟dom仍然过时,并且它可能不是最有效的代码,但至少它确实有效:) 我的错误已解决
细节:
1)如果放置了shouldComponentUpdate以避免插入符号跳动,则contenteditable永不放弃(至少在击键时)
2)如果组件从不在按键时重新渲染,那么React会为此内容保留一个过时的虚拟dom。
3)如果React在其虚拟dom树中保留了contenteditable的过时版本,那么如果您尝试将contenteditable重置为虚拟dom中过时的值,那么在虚拟dom diff期间,React将计算出对申请DOM!
这种情况通常发生在以下情况:
- 您最初具有一个可编辑的空内容(shouldComponentUpdate = true,prop =“”,先前的vdom = N / A),
- 用户键入一些文本,然后阻止渲染(shouldComponentUpdate = false,prop = text,先前的vdom =“”)
- 用户单击验证按钮后,您想清空该字段(shouldComponentUpdate = false,prop =“”,上一个vdom =“”)
- 由于新产生的vdom和旧的vdom均为“”,因此React不会触及dom。
initialValue
进入state
和使用它render
,但我不让进一步反应更新它。