有人在NPM上使用我的解决方案做了一个项目:react-contenteditable
我遇到了另一个问题,当浏览器尝试“重新格式化”刚刚给出的HTML时,会导致组件始终重新渲染。请查看这个.
这里是我的内容可编辑实现。 它比react-contenteditable
具有一些额外选项,包括:
- 锁定
- 命令式API允许嵌入HTML片段
- 重新格式化内容的能力
总结:
FakeRainBrigand的解决方案一直对我很有效,直到我遇到了新问题。内容可编辑真的很棘手,而且不是在React中处理得很容易...
这个JSFiddle演示了这个问题。
如您所见,当您键入某些字符并单击清除时,内容不会被清除。 这是因为我们尝试将contenteditable重置为最后已知的虚拟DOM值。
因此,似乎:
- 您需要使用
shouldComponentUpdate
来防止插入符跳跃
- 如果您以这种方式使用
shouldComponentUpdate
,则不能依赖于React的VDOM差异算法。
所以您需要多加一行代码,这样每当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;
}
});
虚拟 DOM 是过时的,可能不是最高效的代码,但至少它能工作 :) 我的 bug 被解决了
详情:
如果您在 shouldComponentUpdate 中添加逻辑以避免光标跳动,则 contenteditable 永远不会重新渲染(至少在按键时不会)。
如果组件在按键时从未重新渲染,则 React 会为该 contenteditable 保留一个过时的虚拟 DOM。
如果 React 在其虚拟 DOM 树中保留了 contenteditable 的过时版本,则如果您尝试将 contenteditable 重置为虚拟 DOM 中过时的值,则在虚拟 DOM 差异期间,React 将计算出没有要应用于 DOM 的更改!
这通常发生在以下情况下:
- 您最初有一个空的 contenteditable(shouldComponentUpdate=true,prop="",之前的 vdom=N/A),
- 用户输入一些文本并且您阻止渲染(shouldComponentUpdate=false,prop=text,之前的 vdom="")
- 在用户单击验证按钮后,您想清空该字段(shouldComponentUpdate=false,prop="",之前的 vdom="")
- 由于新生成的虚拟 DOM 和旧的虚拟 DOM 都是 "",因此 React 不会触及 DOM。
contentEditable
的斗争 - 我使用了一个带有readonly
属性的input
,而不是一个span
或paragraph
。 - ovidiu-miu