-
使用contentEditable的坑
HTML元素中有个特殊的属性contentEditable,此属性可以将HTML节点变为可编辑的元素,以实现某些需要特殊输入需求(比如想要自己鲁一个富文本等)。但是,如果你是第一次在react中使用,那么多半会遇到我标题所述的坑。具体就是想把一个组件做成可输入的(别问为啥不用input之类的,问就是特殊需求,不想解释)的控件,输入的值会更新到组件上,此时你要搞定两个问题,第一,类似input输入的框的监听输入的onChange事件,第二,从onChange中获取值之后调用setState()更新。第一个问题很好解决,具体看以下代码,然而第二个问题,更新的时候,就让我掉坑了。多说无用,上代码:
//将一个span标签变成可输入的标签
import React, { Component } from 'react';
class EditNode extends Component {
constructor(props) {
super(props);
this.ref = React.createRef();
this.onChange = this.onChange.bind(this);
}
// 解决输入监听的问题
onChange() {
const html = this.ref.current.innerHTML;
this.props.onChange(html);
}
render() {
const {value} = this.props;
return (
<span contentEditable="true"
ref={this.ref}
dangerouslySetInnerHTML={{ __html: value }}
onInput={this.onChange}
onBlur={this.onChange}
/>
);
}
}
export default EditNode;
//使用以上组件
import React, { Component } from 'react';
import EditNode from './EditNode';
class SomeCompoent extends Component {
constructor(props) {
super(props);
this.state = {
html:''
}
}
render() {
return (
<EditNode value={this.state.html}
onChange={(value) => {
//当输入值改变,调用setState()更新的时候,不管你在哪个位置输入,光标妥妥的会跳到第一个位置
this.setState({html:value});
}}
/>
);
}
}
export default SomeCompoent;
-
解决坑
先说说解决历程,尝试了各种检查确认代码没有问题,做防抖更新,保存光标位置等,然并卵。直到启用了面向Google编程高级技能:

import React, { Component } from 'react';
class EditNode extends Component {
constructor(props) {
super(props);
this.ref = React.createRef();
this.onChange = this.onChange.bind(this);
}
onChange() {
const html = this.ref.current.innerHTML;
if (this.props.onChange && html !== this.lastHtml) {
this.props.onChange(html);
}
this.lastHtml = html;
}
shouldComponentUpdate(nextProps) {
return nextProps.value !== this.ref.current.innerHTML;
}
componentDidUpdate() {
if (this.props.value !== this.ref.current.innerHTML) {
this.ref.current.innerHTML = this.props.value;
}
}
render() {
const {value } = this.props;
return (
<span contentEditable="true"
ref={this.ref}
dangerouslySetInnerHTML={{ __html: value }}
onInput={this.onChange}
onBlur={this.onChange}
/>
);
}
}
export default EditNode;
具体原理今天不想写了,被这个问题摩擦了一阵,没心情了。 链接:stackoverflow.com/questions/5…