Javascript 使用 React 更改文本区域中的光标位置

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38385936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 21:24:44  来源:igfitidea点击:

Change the cursor position in a textarea with React

javascriptjqueryreactjs

提问by Discombobulous

I have a textarea in React that I want to turn into a "notepad". Which means I want the "tab" key to indent instead of unfocus. I looked at this answer, but I can't get it to work with React. Here is my code:

我在 React 中有一个文本区域,我想把它变成一个“记事本”。这意味着我希望“tab”键缩进而不是取消焦点。我看了这个答案,但我无法让它与 React 一起工作。这是我的代码:

handleKeyDown(event) {
    if (event.keyCode === 9) { // tab was pressed
        event.preventDefault();
        var val = this.state.scriptString,
            start = event.target.selectionStart,
            end = event.target.selectionEnd;

        this.setState({"scriptString": val.substring(0, start) + '\t' + val.substring(end)});
        // This line doesn't work. The caret position is always at the end of the line
        this.refs.input.selectionStart = this.refs.input.selectionEnd = start + 1;
    }
}
onScriptChange(event) {
   this.setState({scriptString: event.target.value});
}
render() {
    return (
        <textarea rows="30" cols="100" 
                  ref="input"
                  onKeyDown={this.handleKeyDown.bind(this)}
                  onChange={this.onScriptChange.bind(this)} 
                  value={this.state.scriptString}/>
    )
}

When I run this code, even if I press the "tab" key in the middle of the string, my cursor always appears at the end of the string instead. Anyone knows how to correctly set the cursor position?

当我运行这段代码时,即使我按下字符串中间的“tab”键,我的光标也总是出现在字符串的末尾。有人知道如何正确设置光标位置吗?

回答by QoP

You have to change the cursor position afterthe state has been updated(setState()does not immediately mutate this.state)

您必须在状态更新更改光标位置(setState()不会立即发生变化this.state

In order to do that, you have to wrap this.refs.input.selectionStart = this.refs.input.selectionEnd = start + 1;in a function and pass it as the second argument to setState(callback).

为此,您必须包装this.refs.input.selectionStart = this.refs.input.selectionEnd = start + 1;一个函数并将其作为第二个参数传递给setState(callback)。

handleKeyDown(event) {
      if (event.keyCode === 9) { // tab was pressed
          event.preventDefault();
          var val = this.state.scriptString,
          start = event.target.selectionStart,
          end = event.target.selectionEnd;
          this.setState(
              {
                  "scriptString": val.substring(0, start) + '\t' + val.substring(end)
              },
              () => {
                  this.refs.input.selectionStart = this.refs.input.selectionEnd = start + 1
              });
      }
 }

jsfiddle

提琴手

回答by seveibar

Here's a solution in a hooks-style architecture. My recommendation is to change the textarea valueand selectionStartimmediately on tab insertion.

这是一个钩子式架构的解决方案。我的建议是更改 textareavalueselectionStart立即在标签插入时更改。

import React, { useRef } from "react"

const CodeTextArea = ({ onChange, value, error }) => {
  const textArea = useRef()
  return (
      <textarea
        ref={textArea}
        onKeyDown={e => {
          if (e.key === "Tab") {
            e.preventDefault()

            const { selectionStart, selectionEnd } = e.target

            const newValue =
              value.substring(0, selectionStart) +
              "  " +
              value.substring(selectionEnd)

            onChange(newValue)
            if (textArea.current) {
              textArea.current.value = newValue
              textArea.current.selectionStart = textArea.current.selectionEnd =
                selectionStart + 2
            }
          }
        }}
        onChange={e => onChange(e.target.value)}
        value={value}
      />
  )
}

回答by Vivek Kumar

In React 15best option is something like that:

React 15最好的办法是类似的东西:

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

}

You can get full control of cursor position by event.target.selectionStartand event.target.selectionEndvalues without any access to real DOM tree.

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