Изменить фокус ввода текста с помощью реакции

Моя цель здесь - создать форму, которая переводит вас к следующему элементу ввода, когда вы нажимаете клавишу возврата, и отправляет форму, когда вы находитесь на последнем вводе.

Это создается для мобильных устройств, и поскольку нет возможности использовать кнопку «Далее» вместо кнопки «Перейти к клавиатуре» в браузере (дополнительную информацию об этом см. этот ответ).

Чтобы лучше это представить, вот картинка:введите здесь описание изображения

Я также написал некоторый код, но дело в том, что я не могу поймать событие в нужном месте, поэтому форма сразу же отправляется после возврата или когда я предотвращаю событие, фокус меняется после того, как я нажимаю вернуться 2 раза.

См. пример здесь: https://codepen.io/ofhouse/pen/Rgwzxy (I также вставил код ниже)

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

  componentDidMount() {
    if (this.props.focus) {
      this.textInput.focus();
    }
  }

  componentDidUpdate(nextProps) {
    if (nextProps.focus) {
      this.textInput.focus();
    }
  }

  _onKeyPress(e) {
    if (e.key === 'Enter') {
      this.props.onSubmit(e);
    }
  }

  render() {
    return (
      <div>
        <input
          type="text"
          onKeyPress={this._onKeyPress}
          ref={input => {
            this.textInput = input;
          }}
        />
      </div>
    );
  }
}

class Application extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      currentElement: 0,
    };
  }

  _submitForm(e) {
    // If I remove this preventDefault it works, but also the form is submitted --> SiteReload
    e.preventDefault();
  }

  _changeFocus(nextElement) {
    return e => {
      this.setState({
        currentElement: nextElement,
      });
    };
  }

  render() {
    const { currentElement } = this.state;
    return (
      <form>

        <h1>React input focus</h1>

        <TextInput focus={currentElement === 0} onSubmit={this._changeFocus(1)} />
        <TextInput focus={currentElement === 1} onSubmit={this._changeFocus(0)} />

        <div>
          <button type="submit" onClick={this._submitForm}>Submit</button>
        </div>

      </form>
    );
  }
}

ReactDOM.render(<Application />, document.getElementById('app'));

person ofhouse    schedule 04.06.2017    source источник


Ответы (1)


Я не думаю, что вы используете лучший подход, позвольте мне объяснить. Фокусировка входных данных выполняется методом focus собственного элемента DOM. Чтобы узнать, на каком вводе сфокусироваться, в зависимости от того, какой ввод имеет текущий фокус, является логика, которая должна быть реализована в контейнере этих вводов, компоненте Application в вашем случае.

Я внес несколько существенных изменений в ваш код, и теперь он работает: CodePen

Позвольте мне объяснить это:

Прежде всего, мы предотвращаем отправку события keyPressed ввода, когда нажата клавиша 'Enter', чтобы предотвратить форму submit

_onKeyPress(e) {
  if (e.key === 'Enter') {
    this.props.onSubmit(e);
    e.preventDefault();
  }
}

Нам не нужны ни componenDidMount, ни componentDidUpdate в TextInput, нам нужен только метод focus:

focus() {
  this.textInput.focus();
}

Большинство изменений внесено в компонент Application. Прежде всего, нам не нужно состояние, нам действительно нужно иметь входные данные в массиве, чтобы мы могли вызывать для них focus.

constructor(props) {
  super(props);

  this.inputs = [];
}

Чтобы изменить фокус, нам просто нужен индекс ввода для вызова метода focus компонента TextInput:

_changeFocus(index) {
  return e => {
    this.inputs[index].focus();
  };
}

Затем нам нужен способ добавить входные данные в this.inputs, идеальным было бы свойство ref, я создал метод _addInput в качестве помощника для этого:

_addInput(index) {
  return input => {
    this.inputs[index] = input;
  };
}

Наконец, при рендеринге TextInput вам нужно передать их _addInput в ref и _changeFocus в onSubmit с соответствующими индексами:

<TextInput ref={this._addInput(0)} onSubmit={this._changeFocus(1)} />
<TextInput ref={this._addInput(1)} onSubmit={this._changeFocus(0)} />

Во втором TextInput я переключаю фокус на первый, но, возможно, отправка формы будет более полезной.

person Marco Scabbiolo    schedule 04.06.2017
comment
Вау, большое спасибо, что нашли время, чтобы указать все подробно! Ваш подход кажется намного чище, чем мой, здесь действительно чему-то научились. Я проверил его на своем коде, и он работает очень хорошо, определенно сэкономил мне несколько часов. Спасибо! - person ofhouse; 05.06.2017