Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/445.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React.js:contentEditable的onChange事件_Javascript_Dom_Contenteditable_Reactjs - Fatal编程技术网

Javascript React.js:contentEditable的onChange事件

Javascript React.js:contentEditable的onChange事件,javascript,dom,contenteditable,reactjs,Javascript,Dom,Contenteditable,Reactjs,如何侦听基于contentEditable的控件的更改事件 var Number = React.createClass({ render: function() { return <div> <span contentEditable={true} onChange={this.onChange}> {this.state.value} </span>

如何侦听基于
contentEditable
的控件的更改事件

var Number = React.createClass({
    render: function() {
        return <div>
            <span contentEditable={true} onChange={this.onChange}>
                {this.state.value}
            </span>
            =
            {this.state.value}
        </div>;
    },
    onChange: function(v) {
        // Doesn't fire :(
        console.log('changed', v);
    },
    getInitialState: function() {
        return {value: '123'}
    }    
});

React.renderComponent(<Number />, document.body);
var Number=React.createClass({
render:function(){
返回
{this.state.value}
=
{this.state.value}
;
},
onChange:函数(v){
//不开火:(
console.log('changed',v);
},
getInitialState:函数(){
返回{value:'123'}
}    
});
React.renderComponent(,document.body);

编辑:查看哪个修复了我的实现中的错误


使用onInput事件和onBlur(可选)作为回退。您可能希望保存以前的内容以防止发送额外事件

我个人会把它作为我的渲染函数

var handleChange = function(event){
    this.setState({html: event.target.value});
}.bind(this);

return (<ContentEditable html={this.state.html} onChange={handleChange} />);
var handleChange=函数(事件){
this.setState({html:event.target.value});
}.约束(本);
返回();
它使用这个简单的包装器来包装contentEditable

var ContentEditable = React.createClass({
    render: function(){
        return <div 
            onInput={this.emitChange} 
            onBlur={this.emitChange}
            contentEditable
            dangerouslySetInnerHTML={{__html: this.props.html}}></div>;
    },
    shouldComponentUpdate: function(nextProps){
        return nextProps.html !== this.getDOMNode().innerHTML;
    },
    emitChange: function(){
        var html = this.getDOMNode().innerHTML;
        if (this.props.onChange && html !== this.lastHtml) {

            this.props.onChange({
                target: {
                    value: html
                }
            });
        }
        this.lastHtml = html;
    }
});
var ContentEditable=React.createClass({
render:function(){
返回;
},
shouldComponentUpdate:函数(下一步){
返回nextrops.html!==this.getDOMNode().innerHTML;
},
emitChange:function(){
var html=this.getDOMNode().innerHTML;
if(this.props.onChange&&html!==this.lastHtml){
这个。道具。改变({
目标:{
值:html
}
});
}
this.lastHtml=html;
}
});

这可能不是您想要的答案,但我自己也在努力解决这个问题,并且对建议的答案有疑问,因此我决定将其改为不受控制

可编辑
道具为
时,我按原样使用
文本
道具,但当它为
时,我切换到编辑模式,其中
文本
无效(但至少浏览器不会崩溃)。在此期间,控件将触发
onChange
。最后,当我将
editable
更改回
false
时,它将用
文本中传递的内容填充HTML:

/** @jsx React.DOM */
'use strict';

var React = require('react'),
    escapeTextForBrowser = require('react/lib/escapeTextForBrowser'),
    { PropTypes } = React;

var UncontrolledContentEditable = React.createClass({
  propTypes: {
    component: PropTypes.func,
    onChange: PropTypes.func.isRequired,
    text: PropTypes.string,
    placeholder: PropTypes.string,
    editable: PropTypes.bool
  },

  getDefaultProps() {
    return {
      component: React.DOM.div,
      editable: false
    };
  },

  getInitialState() {
    return {
      initialText: this.props.text
    };
  },

  componentWillReceiveProps(nextProps) {
    if (nextProps.editable && !this.props.editable) {
      this.setState({
        initialText: nextProps.text
      });
    }
  },

  componentWillUpdate(nextProps) {
    if (!nextProps.editable && this.props.editable) {
      this.getDOMNode().innerHTML = escapeTextForBrowser(this.state.initialText);
    }
  },

  render() {
    var html = escapeTextForBrowser(this.props.editable ?
      this.state.initialText :
      this.props.text
    );

    return (
      <this.props.component onInput={this.handleChange}
                            onBlur={this.handleChange}
                            contentEditable={this.props.editable}
                            dangerouslySetInnerHTML={{__html: html}} />
    );
  },

  handleChange(e) {
    if (!e.target.textContent.trim().length) {
      e.target.innerHTML = '';
    }

    this.props.onChange(e);
  }
});

module.exports = UncontrolledContentEditable;
/**@jsx React.DOM*/
"严格使用",;
var React=require('React'),
escapeTextForBrowser=require('react/lib/escapeTextForBrowser'),
{PropTypes}=反应;
var UncontrolledContentEditable=React.createClass({
道具类型:{
组件:PropTypes.func,
onChange:PropTypes.func.isRequired,
text:PropTypes.string,
占位符:PropTypes.string,
可编辑:PropTypes.bool
},
getDefaultProps(){
返回{
组件:React.DOM.div,
可编辑:false
};
},
getInitialState(){
返回{
initialText:this.props.text
};
},
组件将接收道具(下一步){
if(nextrops.editable&&!this.props.editable){
这是我的国家({
initialText:nextrops.text
});
}
},
组件将更新(下一步){
如果(!nextrops.editable&&this.props.editable){
this.getDOMNode().innerHTML=escapeTextForBrowser(this.state.initialText);
}
},
render(){
var html=escapeTextForBrowser(this.props.editable?
this.state.initialText:
这个.props.text
);
返回(
);
},
手变(e){
如果(!e.target.textContent.trim().length){
e、 target.innerHTML='';
}
此.props.onChange(e);
}
});
module.exports=不可控内容可编辑;

编辑2015

有人用我的解决方案在NPM上做了一个项目:

编辑2016年6月6日:我刚刚遇到一个新问题,当浏览器试图“重新格式化”您刚才给他的html时,会出现这个问题,导致组件总是重新呈现

Edit 07/2016:这是我的产品内容可编辑实现。它在
react contentEditable
上有一些您可能需要的附加选项,包括:

  • 锁定
  • 允许嵌入html片段的命令式API
  • 能够重新格式化内容
总结: 在我遇到新问题之前,FakeRainBrigand的解决方案对我来说已经很好用了一段时间。有争议的内容是一件痛苦的事情,而且不容易处理

这说明了问题所在

如您所见,当您键入一些字符并单击清除时,内容不会被清除。这是因为我们试图将contenteditable重置为最后一个已知的虚拟dom值

看来:

  • 您需要
    shouldComponentUpdate
    来防止插入符号位置跳转
  • 如果以这种方式使用
    shouldComponentUpdate
    ,则不能依赖React的VDOM差分算法
因此,您需要一个额外的行,以便无论何时
shouldComponentUpdate
返回yes,您都可以确定DOM内容实际上已经更新

因此,此处的版本添加了一个
组件diddupdate
,并成为:

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;
    }
});
var ContentEditable=React.createClass({
render:function(){
返回;
},
shouldComponentUpdate:函数(下一步){
返回nextrops.html!==this.getDOMNode().innerHTML;
},
componentDidUpdate:函数(){
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){
这个。道具。改变({
目标:{
值:html
}
});
}
this.lastHtml=html;
}
});
虚拟dom仍然过时,它可能不是最有效的代码,但至少它可以工作:)


详细信息:

1) 如果您放置shouldComponentUpdate以避免插入符号跳转,则contenteditable永远不会重新加载(至少在击键时)

2) 如果c
emitChange: function(evt){
    var html = this.getDOMNode().innerHTML;
    if (this.props.onChange && html !== this.lastHtml) {
        evt.target = { value: html };
        this.props.onChange(evt);
    }
    this.lastHtml = html;
}
import * as React from 'react';

export default class Editor extends React.Component {
    private _root: HTMLDivElement; // Ref to the editable div
    private _mutationObserver: MutationObserver; // Modifications observer
    private _innerTextBuffer: string; // Stores the last printed value

    public componentDidMount() {
        this._root.contentEditable = "true";
        this._mutationObserver = new MutationObserver(this.onContentChange);
        this._mutationObserver.observe(this._root, {
            childList: true, // To check for new lines
            subtree: true, // To check for nested elements
            characterData: true // To check for text modifications
        });
    }

    public render() {
        return (
            <div ref={this.onRootRef}>
                Modify the text here ...
            </div>
        );
    }

    private onContentChange: MutationCallback = (mutations: MutationRecord[]) => {
        mutations.forEach(() => {
            // Get the text from the editable div
            // (Use innerHTML to get the HTML)
            const {innerText} = this._root; 

            // Content changed will be triggered several times for one key stroke
            if (!this._innerTextBuffer || this._innerTextBuffer !== innerText) {
                console.log(innerText); // Call this.setState or this.props.onChange here
                this._innerTextBuffer = innerText;
            }
        });
    }

    private onRootRef = (elt: HTMLDivElement) => {
        this._root = elt;
    }
}
<div
  contentEditable='true'
  onInput={e => console.log('Text inside div', e.currentTarget.textContent)}
>
Text inside div
</div>
<div onBlur={(e)=>{console.log(e.currentTarget.textContent)}} contentEditable suppressContentEditableWarning={true}>
     <p>Lorem ipsum dolor.</p>
</div>
<div 
    contentEditable={true}
    onSelect={() => callMeOnSelect()}
    onChange={() => callMeOnChange()}
    onMouseUp={() => callMeOnMouseUp()}
    className="myClassNameHere"/>
let selection = window.getSelection().toString();