【问题标题】:Positioning caret in contenteditable ReactJS components在 contenteditable ReactJS 组件中定位插入符号
【发布时间】:2014-09-24 05:53:03
【问题描述】:

我正在使用ReactJS 将文本值呈现到contenteditable DOM 节点中。例如:

var data = [{
  value: 'Hello '
},{
  value: 'World!'
}];

var component = React.createClass({
  render: function () {
    var pieces = this.props.data.map(function (piece) {
      return (
        <span contentEditable="false">
          <span contentEditable="true">{piece.value}</span>;
        </span>
      );
    });

    return <div contentEditable="true">{pieces}</div>;
  }
});

React.renderComponent(<component data={data} />, someContainer);

导致 DOM 看起来像这样(出于多种原因):

<div contenteditable="true">
  <span contentEditable="false">
    <span contentEditable="true">Hello </span>;
  </span>
  <span contentEditable="false">
    <span contentEditable="true">World!</span>;
  </span>
</div>

当用户与这些可编辑的 span 交互时,例如,从第二个到第一个的退格,我可以通过从第一个模型中删除最后一个字符来更新数据,但我需要以某种方式告诉 React 定位光标在第一个span[contenteditable="true"]的末尾

我的问题:

在我的.render() 函数中,我有一个this.state.caretPosition 属性告诉我光标应该在的位置(这只存在于一个组件上)。 render() 应该只返回一个(虚拟)DOM 节点。我如何告诉 ReactJS 将插入符号定位在返回的 DOM 节点中的那个位置?

示例:jsbin

【问题讨论】:

    标签: javascript contenteditable reactjs


    【解决方案1】:

    React 15.6.1 中,您可以像这样手动设置插入符号位置:

    class CursorForm extends Component {
    
      constructor(props) {
        super(props);
        this.state = {value: ''};
      }
    
      handleChange = event => {
        // Custom set cursor on zero text position in input text field
        event.target.selectionStart = 0 
        event.target.selectionEnd = 0
    
        this.setState({value: event.target.value})
      }
    
      render () {
        return (
          <form>
            <input type="text" value={this.state.value} onChange={this.handleChange} />
          </form>
        )  
      }
    
    }
    

    您可以通过 event.target.selectionStartevent.target.selectionEnd 值完全控制光标位置,而无需访问真实的 DOM 树。

    【讨论】:

    • 这限制了您将插入符号设置在&lt;input&gt; 内 - 如果您想将它定位在另一个节点中(由同一组件呈现)怎么办?另外,event.target 是 DOM 节点的句柄,因此“没有任何访问真实 DOM 树的权限”是不正确的。
    • @valex 问题是关于 contenteditable 所以你的回答没有任何价值。
    【解决方案2】:

    我能够让您的示例使用这些how-to-set-caretcursor-position-in-contenteditable-element-divselect-range-in-contenteditable-div 中描述的方法。那里使用的相同方法可能对您有用。您很可能需要在 componentDidMount() 方法中运行它。希望有帮助。以下是它的大致外观:

    componentDidMount: function () {
        var el = document.getElementById("a3");
        var range = document.createRange();
        var sel = window.getSelection();
    
        range.setStart(el.childNodes[0], 1);
        range.collapse(true);
        sel.removeAllRanges();
        sel.addRange(range);
        el.childNodes[0].focus();
      },
    

    编辑:鉴于您的结构非常嵌套,您将不得不尝试使用您实际选择的节点以获得所需的效果。如果光标不在可编辑元素中,则需要调用 focus() 来实际显示应用的光标位置。

    【讨论】:

    • 我今天早上刚刚提出了一个几乎相同的解决方案。我正在使用componentDidUpdate() 方法,因为这通常不会在最初插入组件时发生,但在之后,当用户使用按键更改内容时。您的回答证实了我的做法 - 非常感谢您
    猜你喜欢
    • 1970-01-01
    • 2014-07-29
    • 2015-05-31
    • 1970-01-01
    • 1970-01-01
    • 2016-07-12
    • 1970-01-01
    • 2011-10-05
    • 2021-08-28
    相关资源
    最近更新 更多