react控制输入光标跳转

IT技术 reactjs input text-cursor
2021-03-27 04:50:51

我正在使用 React 并格式化了一个受控输入字段,当我写一些数字并在输入字段外单击时,它可以正常工作。但是,当我想编辑输入时,光标会跳到输入字段中的值的前面。这只发生在 IE 中,而不是在 Chrome 中。我已经看到对于一些程序员来说,光标会跳到值的后面。所以我认为我的光标跳到前面的原因是因为值在输入字段中向右对齐而不是向左对齐。这是一个场景:

我的第一个输入是1000 然后我想编辑成10003,结果是31000

有没有办法控制光标不应该跳转?

6个回答

根据您的问题进行猜测,您的代码很可能与此类似:

    <输入
        自动对焦=“自动对焦”
        类型=“文本”
        值={this.state.value}
        onChange={(e) => this.setState({value: e.target.value})}
    />

如果您的事件被处理onBlur但本质上是相同的问题,这可能会在行为上有所不同这里的行为,许多人称其为 React “错误”,实际上是预期的行为。

输入控件的值不是控件加载时的初始值,而是对 的底层value绑定this.state当状态改变时,React 会重新渲染控件。

本质上,这意味着控件由 React 重新创建并由状态值填充。问题是它无法知道光标在重新创建之前的位置。

我发现解决这个问题的一种方法是在重新渲染之前记住光标位置,如下所示:

    <输入
        自动对焦=“自动对焦”
        类型=“文本”
        值={this.state.value}
        onChange={(e) => {
            this.cursor = e.target.selectionStart;
            this.setState({value: e.target.value});
        }}
        onFocus={(e) => {
            e.target.selectionStart = this.cursor;
        }}
    />
特别是对于钩子,您可以执行以下操作(基于@abhinav-prabhakar 建议): const inputRef = useRef(null); useEffect(() => { inputRef.current.focus(); }, [inputRef]);然后<input ref={inputRef} />我只是将其添加到此处,以免使答案变得复杂,并使其脱离问题的上下文更加混乱。
2021-06-02 04:50:51
如何用钩子做到这一点?
2021-06-19 04:50:51
@JuliodeLeon -useState用于cursorPos. 但这很糟糕,因为有一些边缘情况需要处理已删除和粘贴的输入。
2021-06-22 04:50:51

这是我的解决方案:

import React, { Component } from "react";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: ""
    };

    //get reference for input
    this.nameRef = React.createRef();

    //Setup cursor position for input
    this.cursor;
  }

  componentDidUpdate() {
    this._setCursorPositions();
  }

  _setCursorPositions = () => {
    //reset the cursor position for input
    this.nameRef.current.selectionStart = this.cursor;
    this.nameRef.current.selectionEnd = this.cursor;
  };

  handleInputChange = (key, val) => {
    this.setState({
      [key]: val
    });
  };

  render() {
    return (
      <div className="content">
        <div className="form-group col-md-3">
          <label htmlFor="name">Name</label>
          <input
            ref={this.nameRef}
            type="text"
            autoComplete="off"
            className="form-control"
            id="name"
            value={this.state.name}
            onChange={event => {
              this.cursor = event.target.selectionStart;
              this.handleInputChange("name", event.currentTarget.value);
            }}
          />
        </div>
      </div>
    );
  }
}

export default App;

这是<input/>标签的替代品这是一个简单的功能组件,它使用钩子来保存和恢复光标位置:

import React, { useEffect, useRef, useState } from 'react';

const ControlledInput = (props) => {
   const { value, onChange, ...rest } = props;
   const [cursor, setCursor] = useState(null);
   const ref = useRef(null);

   useEffect(() => {
      const input = ref.current;
      if (input) input.setSelectionRange(cursor, cursor);
   }, [ref, cursor, value]);

   const handleChange = (e) => {
      setCursor(e.target.selectionStart);
      onChange && onChange(e);
   };

   return <input ref={ref} value={value} onChange={handleChange} {...rest} />;
};

export default ControlledInput;
这很美,你是一个传奇。我在这里尝试了其他答案,但这不仅确实有效,而且效果很好(没有光标跳动然后向后移动,非常流畅的用户体验)而且它很容易使用!🙏
2021-05-25 04:50:51
请注意,这input.setSelecetionRange()不适用于type="number"- 如果这就是您想要的,我发现我必须这样做type="text" inputMode="numeric"
2021-06-08 04:50:51

这是一个简单的解决方案。为我工作。

<Input
ref={input=>input && (input.input.selectionStart=input.input.selectionEnd=this.cursor)}
value={this.state.inputtext} 
onChange={(e)=>{
this.cursor = e.target.selectionStart;
this.setState({inputtext: e.target.value})
/>

解释:

我们在这里所做的是我们将光标位置保存在 onChange() 中,现在当标签由于状态值的变化而重新渲染时,引用代码被执行,并且在引用代码中我们恢复了光标位置。

我的光标总是跳到行尾。这个解决方案似乎解决了这个问题(来自 github):

import * as React from "react";
import * as ReactDOM from "react-dom";

class App extends React.Component<{}, { text: string }> {
  private textarea: React.RefObject<HTMLTextAreaElement>;
  constructor(props) {
    super(props);
    this.state = { text: "" };
    this.textarea = React.createRef();
  }

  handleChange(e: React.ChangeEvent<HTMLTextAreaElement>) {
    const cursor = e.target.selectionStart;
    this.setState({ text: e.target.value }, () => {
      if (this.textarea.current != null)
        this.textarea.current.selectionEnd = cursor;
    });
  }

  render() {
    return (
      <textarea
        ref={this.textarea}
        value={this.state.text}
        onChange={this.handleChange.bind(this)}
      />
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));