javascript - React.js:onChange event for contentEditable




dom reactjs (5)

كيف أستمع لتغيير الحدث من أجل التحكم في 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);

http://jsfiddle.net/NV/kb3gN/1621/


Answers

أقترح استخدام mutationObserver للقيام بذلك. تمنحك الكثير من السيطرة على ما يجري. كما يمنحك المزيد من التفاصيل حول كيف يفسر الاستعراض جميع ضربات المفاتيح

هنا في TypeScript

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;
    }
}

هنا هو مكون يضم الكثير من هذا من lovasoa: https://github.com/lovasoa/react-contenteditable/blob/master/index.js

يسبح الحدث في emitChange

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;
}

أستخدم طريقة مشابهة بنجاح


ربما هذا ليس بالضبط الإجابة التي تبحث عنها ، ولكن بعد أن جاهدت مع نفسي وأواجه مشاكل مع الإجابات المقترحة ، قررت أن تجعلها غير خاضعة للرقابة بدلاً من ذلك.

عندما يكون البرنامج editable false ، أستخدم text كما هو ، ولكن عندما يكون true ، أقوم بالتبديل إلى وضع التحرير الذي لا يكون text تأثير فيه (ولكن على الأقل لا يفاجئ المتصفح). خلال هذا الوقت يتم تشغيل onChange بواسطة عنصر التحكم. أخيرًا ، عندما أقوم بتغيير التغيير مرة أخرى إلى false ، فإنه يملأ HTML بكل ما تم تمريره في text :

/** @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;

تعديل: راجع إجابة سيباستيان لوربر التي تعمل على إصلاح خطأ في التنفيذ.

استخدم الحدث onInput ، واختياريا على سبيل المثال كخلفية احتياطية. قد ترغب في حفظ المحتويات السابقة لمنع إرسال أحداث إضافية.

كنت شخصيا لدي هذا بمثابة وظيفة التقديم.

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

return (<ContentEditable html={this.state.html} onChange={handleChange} />);

jsbin

الذي يستخدم هذا المجمع البسيط حول 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;
    }
});

يمكنك محاولة استخدام:

$('*').live('click', function() {
 console.log(this.id);
 return false;
});






javascript dom contenteditable reactjs