繁体   English   中英

反应内容可编辑和光标位置

[英]React contentEditable and cursor position

我有简单的组件

class ContentEditable extends React.Component {
  constructor(props) {
    super(props);
    this.handleInput = this.handleInput.bind(this);
  }

  handleInput(event) {
    let html = event.target.innerHTML;
    if (this.props.onChange && html !== this.lastHtml) {
      this.props.onChange({ target: { value: html, name: this.props.name } });
      this.lastHtml = html;
    }
  }

  render() {
    return (
      <span
        contentEditable="true"
        onInput={this.handleInput}
        className={"auto " + this.props.className}
        dangerouslySetInnerHTML={{ __html: this.props.value }}
      />
    );
  }
}
export default ContentEditable;

<ContentEditable
  value={this.state.name}
  onChange={e => {
    this.setState({ name: e.target.value });
  }}
/>;

useRef的解决方案如下所示。

使用 useRef 将数据保存在自定义输入中

这里useRef会在组件渲染周期之外保留默认值/初始值,因此它会保留原始值而不受我们在 react 组件中所做的其他类型的操作的影响。

这个组件做了两件事

  1. 这将使用onChange方法将用户输入发送到父组件
  2. 从父组件中获取一个默认值作为prop命名value并在自定义输入框中呈现值(使用contentEditable创建)

我添加了一个代码沙箱,链接在这里,用它来看看它是如何工作的!

代码沙箱示例包含两个组件

  • 一个是ContentEditableWithRef ,它解决了useRef的问题,它是一个不受控制的组件,并且
  • 另一个组件是ContentEditable ,它使用useState来解决同样的问题。

我也有同样的问题。 刚刚用ref修复它。 只需将 event.target 的textContent分配给ref

const textareaEl = useRef<HTMLDivElement>(null);

const handleChange = (e: React.ChangeEvent<HTMLDivElement>) => {
    textareaEl.current.textContent = e.target.textContent;
    onChange(e); // If you have change event for form/state
};

/** If you're passing value from state, 
    you can mutate it each change for not losing cursor position. 
 */
useEffect(() => {
  if (value) {
     textareaEl.current.textContent = value;
  }
}, [value]);


return (
    <div
      id="textarea-element"
      ref={textareaEl}
      contentEditable={true}
      suppressContentEditableWarning={true}
      onChange={handleChange}
     />
)

import React, { useRef } from 'react';

const ContentEditable = ({ value, onChange = () => {}, ...props }) => {
    const state = useRef({ value, prevValue: null, key: null });

    if (state.current.prevValue !== value) {
        state.current.value = value;
        state.current.key = Date.now();
    }

    const _handleInput = (event) => {
        const value = event.target.innerText;
        state.current.prevValue = value;
        onChange(value);
    };

    return (
        <div
            {...props}
            key={state.current.key}
            role="textbox"
            contentEditable={true}
            dangerouslySetInnerHTML={{ __html: state.current.value }}
            onInput={_handleInput}
        />
    );
};
export default ContentEditable;

用法:

const [value, setValue] = useState("initial test");

<ContentEditable
  value={value}
  onChange={setValue}
/>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM