在 Safari 和 Firefox 中的 React 中重新渲染时,插入符号位置恢复为内容可编辑范围的开头

问题描述 投票:0回答:2

在 Safari 或 Firefox 中的内容可编辑区域中输入文本时,每次按键时插入符号都会移至开头。这似乎只在 React 重新/渲染组件时才会发生。

Chrome 运行得很好。没有测试过IE。


一个示例,其中

|
是插入符号并输入
Hello
:

|
|H
|eH
|leH
|lleH
|olleH

这是我的组件的简化版本:

import React, { Component } from 'react';

class ContentEditable extends Component {
    constructor(props) {
        super(props);

        this.state = {
            value: props.value
        };
    }

    createMarkup() {
        return { __html: this.state.value };
    }

    handleInput(event) {
        this.setState({
            value: event.target.innerText
        });
    }

    isValid() {
        let bestLength = 3;

        return this.state.value.length > bestLength;
    }

    render() {
        let className = '';
        if (this.isValid()) {
            className = 'is-valid';
        }

        return (
            <span
                contentEditable="true"
                onInput={ this.handleInput.bind(this) }
                className={ className }
                dangerouslySetInnerHTML={ this.createMarkup() }
            >
            </span>
        );
    }
}

ContentEditable.propTypes = {
    value: React.PropTypes.string.isRequired
};

export default ContentEditable;

有人遇到过这个吗?

firefox reactjs safari contenteditable caret
2个回答
4
投票

您可以通过向 HTML 标记添加处理程序来实现

contenteditable
。 问题是每次重新渲染内容时,光标的位置都会重置。当
setState
的内容被编辑时,您会触发
span
,从而重置光标位置。

您可以存储对

span
标签的引用并更新其值,而不是触发状态更改。

A

ref
可以被存储,这将在范围中注入值。

class ContentEditable extends Component {
  constructor(props) {
    super(props);
    this.spanRef = React.createRef();
    this.val = props.value;
  }

  handleInput(event) {
    const { innerText } = event.target;
    if (this.val !== innerText) {
      this.spanRef.innerText = innerText;
      this.val = innerText;
    }
  }

  render() {
    return (
      <span
        contentEditable="true"
        className={"is-valid"}
        onInput={this.handleInput.bind(this)}
        ref={this.spanRef}
        suppressContentEditableWarning={true}
      >
        {this.val}
      </span>
    );
  }
}

运行代码


0
投票

我知道我参加聚会迟到了,但这可能对其他人有帮助,或者您也可以在其他问题上找到类似类型的解决方案。

当您直接更新或打印节点中的值时,Html 适用于节点概念,因为反应重新渲染它会重置光标位置以开始。您必须使用 HTML Web API 以编程方式将值传递给元素,这里是修改后的代码。

class ContentEditable extends Component {
  constructor(props) {
    super(props);
    this.spanRef = React.createRef();
    this.val = props.value;
  }

  componentDidUpdate(prevState, prevPorps){
    if(prevPorps?.value !== this.props.value) {
       this.spanRef.innerText = this.props.value;
    }
  }

  handleInput(event) {
    const { innerText } = event.target;
    if (this.val !== innerText) {
      this.spanRef.innerText = innerText;
      this.val = innerText;
    }
  }

  render() {
    return (
      <span
        contentEditable="true"
        className={"is-valid"}
        onInput={this.handleInput.bind(this)}
        ref={this.spanRef}
        suppressContentEditableWarning={true}
      >
      </span>
    );
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.