React.js: contentEditable의 onChange 이벤트
의 변경 이벤트를 재생하려면 어떻게 해야 합니까?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);
이것은 나에게 효과가 있었던 가장 간단한 해결책이다.
<div
contentEditable='true'
onInput={e => console.log('Text inside div', e.currentTarget.textContent)}
>
Text inside div
</div>
구현의 오류를 수정하는 Sebastien Lorber의 답변을 참조하십시오.
onInput 이벤트 및 옵션으로 onBlur을 폴백으로 사용합니다.추가 이벤트 전송을 방지하기 위해 이전 내용을 저장할 수 있습니다.
저는 개인적으로 이것을 렌더링 함수로 사용하고 싶습니다.
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;
}
});
누군가가 내 솔루션으로 NPM에 대한 프로젝트를 만들었다: 반응 콘텐츠
방금 제공한 HTML을 브라우저가 "재포맷"하려고 하면 컴포넌트가 항상 재렌더링되는 또 다른 문제가 발생했습니다.이것 좀 봐.
다음은 프로덕션 콘텐츠 편집 가능 구현입니다.다음 옵션 중 몇 가지 추가 옵션이 있습니다.react-contenteditable
다음과 같은 기능을 제공합니다.
- 록
- HTML fragment를 삽입할 수 있는 명령형 API
- 콘텐츠 재포맷 기능
요약:.
FakeRainBrigand의 솔루션은 새로운 문제가 생기기 전까지는 꽤 잘 작동했습니다.Content Editables는 귀찮고 React에 대처하기가 쉽지 않습니다.
이 JSFiddle은 문제를 나타냅니다.
보시는 바와 같이 몇 개의 문자를 입력하고 을 클릭하면 내용이 지워지지 않습니다.이는 콘텐츠 가능을 마지막으로 알려진 가상 DOM 값으로 리셋하려고 하기 때문입니다.
그래서 다음과 같이 보입니다.
- 당신은 필요하다
shouldComponentUpdate
캐럿 위치 점프를 방지하려면 - React의 VDOM 확산 알고리즘에 의존할 수 없습니다.
shouldComponentUpdate
이쪽입니다.
그래서 당신은 여분의 대사가 필요합니다. 그래서 언제든지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은 오래된 상태로 남아 있어 가장 효율적인 코드는 아닐 수 있지만 적어도 동작합니다:) 버그는 해결되었습니다.
세부사항:
캐럿 점프를 피하기 위해 show Component Update를 넣으면 (적어도 키 입력에서는) 컨텐츠가 재렌더되지 않습니다.
이 컴포넌트가 키 스트로크로 재렌더되지 않는 경우 React는 이 콘텐츠에 대해 오래된 가상 DOM을 유지합니다.
React가 콘텐츠의 오래된 버전을 가상 DOM 트리에 보관하고 있는 경우 콘텐츠의 값을 가상 DOM 내의 오래된 값으로 리셋하려고 하면 가상 DOM diff 동안 React는 DOM에 적용할 변경 사항이 없음을 계산합니다.
이 문제는 주로 다음과 같은 경우에 발생합니다.
- 처음에는 컨텐츠에 저장 가능한 빈 공간이 있습니다(shouldComponentUpdate=true,prop=previous 이전 vdom=N/A).
- 사용자가 일부 텍스트를 입력하면 렌더링이 금지됩니다(shouldComponentUpdate=false,prop=text, 이전 vdom=").
- 사용자가 유효성 검사 버튼을 클릭한 후 해당 필드(shouldComponentUpdate=false,prop=previous previous vdom=")를 비우선 vdom="
- 새로 생성된 가상 DOM과 오래된 가상 DOM이 모두 " "이기 때문에 리액트는 DOM에 접촉하지 않습니다.
되면 항상 때문에 '포커스'를 .onBlur
이벤트 핸들러
<div
onBlur={e => {
console.log(e.currentTarget.textContent);
}}
contentEditable
suppressContentEditableWarning={true}
>
<p>Lorem ipsum dolor.</p>
</div>
이것은 아마 당신이 찾고 있는 답은 아닐 것입니다만, 스스로 이 문제와 씨름하고 있고, 제안된 답변에 문제가 있어, 저는 그 대신 그것을 통제하지 않기로 결정했습니다.
editable
은 「」입니다.false
, , , 을합니다.text
true
text
이 동안.onChange
제어에 의해 발사됩니다.으로 내가 때editable
으로 false
된 내용을 로 채웁니다.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;
이를 위해서는 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
emiss Change에서 이벤트를 시뮬레이트합니다.
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;
}
비슷한 방법을 성공적으로 사용하고 있습니다.
<div
spellCheck="false"
onInput={e => console.log("e: ", e.currentTarget.textContent}
contentEditable="true"
suppressContentEditableWarning={true}
placeholder="Title"
className="new-post-title"
/>
다음은 Sebastien Lorber의 답변을 바탕으로 한 후크 기반 버전입니다.
const noop = () => {};
const ContentEditable = ({
html,
onChange = noop,
}: {
html: string;
onChange?: (s: string) => any;
}) => {
const ref = useRef<HTMLDivElement>(null);
const lastHtml = useRef<string>('');
const emitChange = () => {
const curHtml = ref.current?.innerHTML || '';
if (curHtml !== lastHtml.current) {
onChange(curHtml);
}
lastHtml.current = html;
};
useEffect(() => {
if (!ref.current) return;
if (ref.current.innerHTML === html) return;
ref.current.innerHTML = html;
}, [html]);
return (
<div
onInput={emitChange}
contentEditable
dangerouslySetInnerHTML={{ __html: html }}
ref={ref}
></div>
);
};
<div
onBlur={e => {
console.log(e.currentTarget.textContent);
}}
contentEditable
suppressContentEditableWarning={true}
>
<p>Lorem ipsum dolor.</p>
</div>
이 값을 설정하기 전까지는 완벽하게 동작합니다.를 호출하는 setState(e.currentTarget.textContent)
, , , , , 을 .currentTarget
무효로 합니다. setState
으로 동작합니다.currentTarget
를 사용할 수 없습니다.
17가 있었던 은 액 1717.0을 사용하는 이었습니다.2개e.target.innerText
:
<div
onBlur={e => setState(e.target.innerText)}
contentEditable
suppressContentEditableWarning={true}
>
<p>Lorem ipsum dolor.</p>
</div>
언급URL : https://stackoverflow.com/questions/22677931/react-js-onchange-event-for-contenteditable
'programing' 카테고리의 다른 글
Angular-ui 라우터는 2개의 상태를 동시에 활성화 합니다. (0) | 2023.04.03 |
---|---|
TypeScript 프로젝트에서 기존 C# 클래스 정의를 재사용하는 방법 (0) | 2023.04.03 |
배열에 다음이 포함된 경우 각도 표현식 (0) | 2023.04.03 |
저장된 텍스트 영역에서 반응 표시 줄 바꿈 (0) | 2023.04.03 |
Visual Studio 코드 자동 가져오기 (0) | 2023.04.03 |