按下 Enter 键后调用 onChange 事件

373

我刚开始使用Bootstrap,现在遇到了一个问题。我有一个输入框,只要我输入一个数字,就会调用onChange函数,但是我希望在整个数字输入完后按下“Enter”键时再调用它。验证函数也有同样的问题——它调用得太早了。

var inputProcent = React.CreateElement(bootstrap.Input, {type: "text",
  //bsStyle: this.validationInputFactor(),
  placeholder: this.initialFactor,
  className: "input-block-level",
  onChange: this.handleInput,
  block: true,
  addonBefore: '%',
  ref:'input',
  hasFeedback: true
});
12个回答

678

根据React文档,你可以监听键盘事件,例如onKeyPressonKeyUp,而不是onChange

var Input = React.createClass({
  render: function () {
    return <input type="text" onKeyDown={this._handleKeyDown} />;
  },
  _handleKeyDown: function(e) {
    if (e.key === 'Enter') {
      console.log('do validate');
    }
  }
});

更新:使用 React.Component

这是使用 React.Component 来完成相同操作的代码。

class Input extends React.Component {
  _handleKeyDown = (e) => {
    if (e.key === 'Enter') {
      console.log('do validate');
    }
  }

  render() {
    return <input type="text" onKeyDown={this._handleKeyDown} />
  }
}

这里是jsfiddle

更新2:使用函数式组件

const Input = () => {
  const handleKeyDown = (event) => {
    if (event.key === 'Enter') {
      console.log('do validate')
    }
  }

  return <input type="text" onKeyDown={handleKeyDown} />
}

2
您还希望将验证过程绑定到 onBlur 事件。 - wuct
9
可以使用更简洁的方式实现相同的解决方案,与输入文本相关:<input ref='reference' onKeyUp={(e) => {(e.keyCode === 13 ? doSomething(this.refs.reference.value) : null)}} /> - musemind
5
实际上,你不需要使用 ref<input onKeyPress={e => doSomething(e.target.value)} 就足够了。 - wuct
9
使用类方法而不是内联函数的原因在于,避免每次触发onKeyPress事件时创建一个新函数。这是一种微小的性能优化。 - wuct
3
我更喜欢使用onKeyUp,因为它只会在松开按键时触发。另一方面,如果用户按住键不放,onKeyDown将会多次触发。 - kawerewagaba
显示剩余7条评论

100
你可以直接在输入框上使用 onKeyPress。每次输入框发生更改时,onChange 函数会更改状态值,并在按下 Enter 键后调用搜索函数 search()。
你可以直接在输入框上使用 onKeyPress。每次输入框发生更改时,onChange 函数会更改状态值,并在按下 Enter 键后调用搜索函数 search()。
<input
    type="text"
    placeholder="Search..."
    onChange={event => {this.setState({query: event.target.value})}}
    onKeyPress={event => {
                if (event.key === 'Enter') {
                  this.search()
                }
              }}
/>

这个答案对我有效,而不是上面被接受的答案。 - karthik shankar
1
如果你有一个很重的表单,我建议你在渲染方法之外创建一个函数,并将其作为引用传递,例如 onKeyPress={this.yourFunc},否则每次渲染都会重新创建一个箭头函数。 - Viktor
这适用于在输入和父级情况下编写onKeyPress事件的情况。谢谢。 - Naveen Setty
4
或者 onKeyPress={(event) => event.key === 'Enter' && this.search()} - camden_kid
onKeyPress已被弃用,请使用onKeyUp - Eduards

52

在表单控件(input)中按下Enter键通常会触发表单上的submit (onSubmit)事件。如果您只有一个输入项,可以通过这种方式处理它(如果只有一个输入项,则提交按钮是可选的):

const { useState } = React;

function App() {
  const [text, setText] = useState("");
  const [submitted, setSubmitted] = useState('');

  function handleChange(e) {
    setText(e.target.value);
  }

  function handleSubmit(e) {
    e.preventDefault();
    setSubmitted(text);
    setText("");
  }

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input type="text" value={text} onChange={handleChange} />
        <input type="submit" value="add" />
      </form>
      submitted: {submitted}
    </div>
  );
}

ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://unpkg.com/react@17.0.2/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.development.js"></script>
<div id="root"></div>

隐式表单提交(Enter 键触发 submit 事件)会在以下情况下进行:

  • 存在提交按钮
  • 不存在提交按钮,但只存在一个输入框

更多信息请参见此处

或者你可以将处理程序绑定到 input 上的 blur (onBlur) 事件上,在焦点被移除时触发(例如,通过按 Tab 键移动到下一个可获得焦点的元素)。


4
使用“onKeyPress”相比之下,这样更清晰。 - Blackus
2
由于目标不同,event.target.value 不可用。 - Izkata
4
在大多数 Web 应用程序中,没有表单,只有输入框,因此这个答案对大多数使用情况来说不相关,以我看来。 - vsync
2
@vsync 这可能不适用于大多数人,但对一部分人仍然有效 - 而且绝对不是错误的,我认为这不值得被踩? - Luca
2
@vsync 你应该为可访问性添加一个表单元素,就像你不应该把所有东西都变成 div 一样。 - Maxim Mazurok
显示剩余2条评论

13

您可以使用event.key

function Input({onKeyPress}) {
  return (
    <div>
      <h2>Input</h2>
      <input type="text" onKeyPress={onKeyPress}/>
    </div>
  )
}

class Form extends React.Component {
  state = {value:""}

  handleKeyPress = (e) => {
    if (e.key === 'Enter') {
      this.setState({value:e.target.value})
    }
  }

  render() {
    return (
      <section>
        <Input onKeyPress={this.handleKeyPress}/>
        <br/>
        <output>{this.state.value}</output>
      </section>
    );
  }
}

ReactDOM.render(
  <Form />,
  document.getElementById("react")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>


12

我更喜欢使用onKeyUp,因为它只在松开按键时触发。而onKeyDown则会在某些情况下多次触发,比如用户按住某个按键不放。例如,在监听用户是否按下"Enter"键来进行网络请求时,我们不希望它多次触发,因为这可能会很耗费资源。

// handler could be passed as a prop
<input type="text" onKeyUp={handleKeyPress} />

handleKeyPress(e) {
  if (e.key === 'Enter') {
    // do whatever
  }
}

此外,要避免使用keyCode,因为它将在不久的将来被弃用。


9

React用户,这里有一个完整的答案。

React版本为16.4.2

您可以选择在每次按键时更新,或仅在提交时获取值。将键事件添加到组件中可以工作,但官方文档中也推荐了其他方法。

受控组件 vs 非受控组件

受控组件

来自文档 - 表单和受控组件

在HTML中,诸如input、textarea和select之类的表单元素通常会维护其自己的状态,并根据用户输入进行更新。在React中,可变状态通常保存在组件的state属性中,并且只能使用setState()进行更新。

我们可以通过使React状态成为“单一数据源”来将两者结合起来。然后呈现表单的React组件还可以控制随后的用户输入中发生的事情。以这种方式由React控制值的输入表单元素称为“受控组件”。

如果使用受控组件,则必须在每次更改值时保持状态更新。为此,将事件处理程序绑定到组件上。在文档的示例中,通常使用onChange事件。

示例:

1)在构造函数中绑定事件处理程序(值保存在状态中)

constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
}

2)创建处理程序函数

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

3)创建表单提交函数(从状态中获取值)

handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
}

4) Render

<form onSubmit={this.handleSubmit}>
    <label>
      Name:
      <input type="text" value={this.state.value} onChange={this.handleChange} />
    </label>
    <input type="submit" value="Submit" />
</form>

如果您使用受控组件,则为了更新和保持正确的状态,始终会触发handleChange函数。状态将始终具有更新后的值,并且在提交表单时,值将从状态中获取。如果您的表单非常长,则可能会有缺点,因为您将不得不为每个组件创建一个函数,或者编写一个简单的函数来处理每个组件的值更改。 不受控制的组件 来自文档-不受控制的组件 大多数情况下,我们建议使用受控组件来实现表单。在受控组件中,表单数据由React组件处理。另一种选择是不受控制的组件,在这种情况下,表单数据由DOM本身处理。
要编写不受控制的组件,您可以使用ref从DOM中获取表单值,而不是为每个状态更新编写事件处理程序。
主要区别在于您不使用onChange函数,而是使用表单的onSubmit来获取值,并在必要时进行验证。
例如:
1)在构造函数中绑定事件处理程序并创建对输入的引用(不保留任何状态值)
constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.input = React.createRef();
}

2) 创建表单提交函数(从DOM组件中获取值)

handleSubmit(event) {
    alert('A name was submitted: ' + this.input.current.value);
    event.preventDefault();
}

3)渲染

<form onSubmit={this.handleSubmit}>
    <label>
      Name:
      <input type="text" ref={this.input} />
    </label>
    <input type="submit" value="Submit" />
</form>

如果您使用不受控制的组件,则无需绑定handleChange函数。当提交表单时,将从DOM中获取值,并在此时进行必要的验证。也不需要为任何输入组件创建任何处理程序函数。

您的问题

现在,针对您的问题:

...我希望在输入整数后按下“Enter”时调用它

如果您想实现这一点,请使用不受控制的组件。如果不必要,则不要创建onChange处理程序。 enter键将提交表单,并将触发handleSubmit函数。

您需要做出的更改:

从您的元素中删除onChange调用

var inputProcent = React.CreateElement(bootstrap.Input, {type: "text",
    //    bsStyle: this.validationInputFactor(),
    placeholder: this.initialFactor,
    className: "input-block-level",
    // onChange: this.handleInput,
    block: true,
    addonBefore: '%',
    ref:'input',
    hasFeedback: true
});

处理表单提交并验证您的输入。您需要在表单提交函数中获取元素的值,然后进行验证。确保在构造函数中创建对元素的引用。

  handleSubmit(event) {
      // Get value of input field
      let value = this.input.current.value;
      event.preventDefault();
      // Validate 'value' and submit using your own api or something
  }

未受控组件的示例用法:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    // bind submit function
    this.handleSubmit = this.handleSubmit.bind(this);
    // create reference to input field
    this.input = React.createRef();
  }

  handleSubmit(event) {
    // Get value of input field
    let value = this.input.current.value;
    console.log('value in input field: ' + value );
    event.preventDefault();
    // Validate 'value' and submit using your own api or something
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" ref={this.input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

ReactDOM.render(
  <NameForm />,
  document.getElementById('root')
);

完美答案! - Alaa Mohammad

7
防止按下 Enter 键提交表单的示例,在我的情况下是 Google 地图位置自动完成输入。
<input
  ref={addressInputRef}
  type="text"
  name="event[location]"
  className="w-full"
  defaultValue={location}
  onChange={(value) => setLocation(value)}
  onKeyDown={(e) => {
    if (e.code === "Enter") {
      e.preventDefault()
    }
  }}
/>

应该使用 e.key 而不是 e.code。 - Mitesh K
@MiteshK 都适用于“Enter” https://jsbin.com/tiyuhaqiko/edit?html,js,output - Dorian

7
您可以编写一个类似于这样的小包装函数
const onEnter = (event, callback) => event.key === 'Enter' && callback()

然后在您的输入上使用它。
<input 
    type="text" 
    placeholder="Title of todo" 
    onChange={e => setName(e.target.value)}
    onKeyPress={e => onEnter(e, addItem)}/>

2

这个比其他所有解决方案都要好:

<!-- html -->
<input type="text" onkeydown='handleKeyPress(this)'>

...

// js
function handleKeyPress(e)
{
    if (event.key === 'Enter') 
    {
        // call your method here
    }
}

0
const [value, setValue] = useState("");

const handleOnChange = (e) => {
    setValue(e.target.value);
};

const handleSubmit = (e) => {
    e.preventDefault();
    addTodoItem(value.trim());
    setValue("");
};

return (
    <form onSubmit={handleSubmit}>
        <input value={value} onChange={handleOnChange}></input>
    </form>
);

目前你的回答不够清晰。请编辑并添加更多细节,以帮助其他人理解它如何回答所提出的问题。你可以在帮助中心找到有关如何撰写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接