渲染后将焦点设置在输入上

Dav*_*ave 557 javascript reactjs

在渲染组件后,将焦点设置在特定文本字段上的反应方式是什么?

文档似乎建议使用refs,例如:

ref="nameInput"在渲染函数的输入字段中设置,然后调用:

this.refs.nameInput.getInputDOMNode().focus(); 
Run Code Online (Sandbox Code Playgroud)

但我应该在哪里打电话呢?我尝试了几个地方,但我无法让它工作.

Bri*_*and 765

@ Dhiraj的答案是正确的,为方便起见,您可以使用autoFocus prop在安装时自动对焦输入:

<input autoFocus name=...
Run Code Online (Sandbox Code Playgroud)

请注意,在jsx中它是autoFocus(大写字母F)不像普通的旧HTML,它不区分大小写.

  • 请注意,在jsx中,它的auto*F*ocus(大写字母F)与普通的旧html不同,后者不区分大小写. (87认同)
  • 此方法为+1.值得一提的是,这不仅仅使用HTML5不可靠的`autofocus`属性,它实际上[在`react-dom`中使用`focus()`在DOM挂载上](https://github.com/facebook/react/blob /master/src/renderers/dom/stack/client/ReactDOMComponent.js#L632)所以它非常可靠. (41认同)
  • 非常好,经过漫长的徒劳无益的搜索后来到这里:) FYI - 我最终使用了React.DOM.input({type:'text',defaultValue:content,autoFocus:true,onFocus:function(e){e.target.选择();} }) (6认同)
  • 这应该是公认的答案 - 除非您需要 ref 对输入执行其他操作,否则这是一个更自然的 Web 解决方案,不需要额外的反应代码:) (3认同)
  • 我发现autoFocus仅适用于首页渲染。请参阅https://codepen.io/ericandrewlewis/pen/PbgwqJ?editors=1111,输入应在3秒钟后聚焦。 (2认同)
  • 不仅“为了方便”,而且如果您的组件是功能组件,也是如此。 (2认同)

Dhi*_*raj 616

你应该这样做componentDidMountrefs callback不是.像这样的东西

componentDidMount(){
   this.nameInput.focus(); 
}
Run Code Online (Sandbox Code Playgroud)

class App extends React.Component{
  componentDidMount(){
    this.nameInput.focus();
  }
  render() {
    return(
      <div>
        <input 
          defaultValue="Won't focus" 
        />
        <input 
          ref={(input) => { this.nameInput = input; }} 
          defaultValue="will focus"
        />
      </div>
    );
  }
}
    
ReactDOM.render(<App />, document.getElementById('app'));
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.js"></script>
<div id="app"></div>
Run Code Online (Sandbox Code Playgroud)

  • 这是正确的答案,但它对我不起作用,因为我的组件首先不呈现任何内容,直到单击另一个按钮.这意味着它已经安装,所以我不得不添加this.refs.nameInput.getDOMNode().focus(); 在componentDidUpdate中而不是componentDidMount. (102认同)
  • 警告:不推荐使用React.findDOMNode.请改用require('react-dom')中的ReactDOM.findDOMNode. (14认同)
  • 为什么,当调用element.focus()时,它是否将光标放在输入的开头?我在我的应用程序中看到了这个(我认为是什么)错误,在chrome中,实际上在<textarea>中,现在在这里检查你的演示它是一样的. (7认同)
  • @HuwDavies我想你会使用[参考回调属性](https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute)来做到这一点. <input>`元素.类似于`<input ref = {(component)=> ReactDOM.findDOMNode(component).focus()} /> (4认同)
  • 出于某种原因,立即调用 `.focus()` 在我的应用程序中不起作用,但它的超时时间很短(无关紧要):`componentDidMount() { setTimeout(() =&gt; { this.textInput.focus(); }, 10); }` (2认同)
  • 我发现在 16 中,打开开发工具会将焦点放在伪 cli/终端上,这会阻止焦点在 Firefox 中工作。关闭它突然使它工作,但只有在我花了 3 个小时试图在它下面.... (2认同)
  • 为什么我们不只使用_ref = {(input)=&gt; {input.focus()}} _?这个解决方案对我来说很好。 (2认同)

Ily*_*nov 157

从React 0.15开始,最简洁的方法是:

<input ref={input => input && input.focus()}/>
Run Code Online (Sandbox Code Playgroud)

  • 唯一的问题是它将输入重点放在任何可能不需要的重新渲染上. (8认同)
  • 这也处理初始渲染之外的场景,而仅使用autoFocus则不会. (5认同)
  • @JaeGeeTee它在组件安装之前和/或卸载之后为空(我不记得确定是哪种情况). (2认同)

Ben*_*arp 72

你不需要使用参考

React作为框架提供的主要优点是代码可以描述性地编写,而不是强制性地编写.这很重要 - 它使代码更容易理解.当您使用Ref时,您的代码更加迫切.

安装时要聚焦元素

在大多数情况下,只需使用autoFocus属性即可.

<input type="text" autoFocus />
Run Code Online (Sandbox Code Playgroud)

有条件地管理和移动焦点

您可能希望根据某个逻辑将焦点从一个元素移动到另一个元素(例如,在输入预期数量的字符时移动到下一个字段).autoFocus属性的问题在于它只能在组件首次渲染(安装)时设置焦点.因此,仅将属性值从true更改为false将不会产生任何影响.

解决方案是每次焦点更改时使用key属性重新安装元素.如果我们这样做,我们可以将焦点质量视为受控制的.

const useFocus = () => {
    const htmlElRef = useRef(null)
    const setFocus = () => {htmlElRef.current &&  htmlElRef.current.focus()}

    return [ htmlElRef, setFocus ] 
}
Run Code Online (Sandbox Code Playgroud)

示例1 - 按钮单击使输入聚焦,并输入3个字符,使其散焦.示例2 - enter将焦点移动到下一个field元素.

  • 这个答案包含了 React Hooks 的正确方法。极好的!它不会按 TypeScript 中的原样进行类型检查,而是采用一种(丑陋的)方式使其工作:(1) `(htmlElRef.current as any).focus()` 和 (2) `return {htmlElRef, setFocus}`的数组。 (3认同)
  • 这是用Typescript编写的“ useFocus”。https://gist.github.com/carpben/de968e377cbac0ffbdefe1ab56237573 (2认同)

Jac*_*Lee 54

如果你只想在React中进行自动对焦,那很简单.

<input autoFocus type="text" />
Run Code Online (Sandbox Code Playgroud)

如果您只是想知道放置该代码的位置,那么答案就在componentDidMount()中.

v014.3

componentDidMount() {
    this.refs.linkInput.focus()
}
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,您可以将引用附加到DOM节点,并完全避免使用findDOMNode.

在这里阅读API文档:https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode

  • 并记住将那个"F"大写!(注意自己和他人,而不是回答者). (8认同)

jmb*_*cci 25

我刚刚遇到这个问题而且我正在使用react 15.0.1 15.0.2并且我使用的是ES6语法,并且自从v.15在几周之前删除以及其他一些this.refs属性后,我从其他答案中得不到我需要的东西被弃用删除.

一般来说,我需要的是:

  1. 在组件安装时,聚焦第一个输入(字段)元素
  2. 聚焦第一个输入(字段)元素并出现错误(提交后)

我正在使用:

  • 反应容器/演示组件
  • 终极版
  • 反应-路由器

聚焦第一个输入元素

我在页面autoFocus={true}上的第一个<input />使用,以便当组件安装时,它将获得焦点.

使用错误聚焦第一个输入元素

这花费的时间更长,更令人费解.为了简洁,我保留了与解决方案无关的代码.

Redux商店/州

我需要一个全局状态来知道我是否应该设置焦点并在设置时禁用它,所以当重新渲染组件时我不会重新设置焦点(我将componentDidUpdate()用于检查设置焦点. )

这可以根据您的应用设计.

{
    form: {
        resetFocus: false,
    }
}
Run Code Online (Sandbox Code Playgroud)

容器组件

如果组件resetfocus最终将焦点设置在自身上,则组件将需要具有属性集和callBack以清除属性.

还要注意,我将Action Creators组织成单独的文件,主要是因为我的项目相当大,我想将它们分解成更易于管理的块.

import { connect } from 'react-redux';
import MyField from '../presentation/MyField';
import ActionCreator from '../actions/action-creators';

function mapStateToProps(state) {
    return {
        resetFocus: state.form.resetFocus
    }
}

function mapDispatchToProps(dispatch) {
    return {
        clearResetFocus() {
            dispatch(ActionCreator.clearResetFocus());
        }
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(MyField);
Run Code Online (Sandbox Code Playgroud)

演示组件

import React, { PropTypes } form 'react';

export default class MyField extends React.Component {
    // don't forget to .bind(this)
    constructor(props) {
        super(props);
        this._handleRef = this._handleRef.bind(this);
    }

    // This is not called on the initial render so
    // this._input will be set before this get called
    componentDidUpdate() {
        if(!this.props.resetFocus) {
            return false;
        }

        if(this.shouldfocus()) {
            this._input.focus();
            this.props.clearResetFocus();
        }
    }

    // When the component mounts, it will save a 
    // reference to itself as _input, which we'll
    // be able to call in subsequent componentDidUpdate()
    // calls if we need to set focus.
    _handleRef(c) {
        this._input = c;
    }

    // Whatever logic you need to determine if this
    // component should get focus
    shouldFocus() {
        // ...
    }

    // pass the _handleRef callback so we can access 
    // a reference of this element in other component methods
    render() {
        return (
            <input ref={this._handleRef} type="text" />
        );
    }
}

Myfield.propTypes = {
    clearResetFocus: PropTypes.func,
    resetFocus: PropTypes.bool
}
Run Code Online (Sandbox Code Playgroud)

概观

一般的想法是,每个可能出错并被集中的表单字段需要检查自己以及是否需要将注意力集中在自身上.

需要发生业务逻辑以确定给定字段是否是设置焦点的正确字段.这没有显示,因为它将取决于个人应用.

提交表单时,该事件需要将全局焦点标志设置resetFocus为true.然后,当每个组件更新自身时,它将看到它应该检查它是否获得焦点,如果是,则调度事件以重置焦点,以便其他元素不必继续检查.

编辑 作为旁注,我将业务逻辑放在"实用程序"文件中,我只是导出了方法并在每个shouldfocus()方法中调用它.

干杯!


ett*_*any 24

React 16.3通过在组件的构造函数中创建ref并使用如下所示,添加了一种新的便捷方式来处理此问题:

class MyForm extends Component {
  constructor(props) {
      super(props);

      this.textInput = React.createRef();
  }

  componentDidMount() {
    this.textInput.current.focus(); // one important change here is that we need to access the element via current.
  }

  render() {
    // instead of using arrow function, the created ref can be used directly.
    return(
      <div>
        <input ref={this.textInput} />
      </div>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,您可以在React博客中查看此文章

更新:

从React 16.8开始,useRef可以在函数组件中使用hook来获得相同的结果:

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

const MyForm = () => {
  const textInput = useRef(null);

  useEffect(() => {
    textInput.current.focus();
  }, []);

  return (
    <div>
      <input ref={textInput} />
    </div>
  );
};
Run Code Online (Sandbox Code Playgroud)

  • 如果您使用打字稿,请确保输入引用:``useRef&lt;HTMLInputElement&gt;(null)``` (4认同)
  • 一个小变化:`textInput.current?.focus();` (2认同)

Kev*_*tle 23

React文档现在有一个部分.https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute

 render: function() {
  return (
    <TextInput
      ref={function(input) {
        if (input != null) {
          input.focus();
        }
      }} />
    );
  },
Run Code Online (Sandbox Code Playgroud)


GAE*_*fan 12

这不再是最佳答案.从v0.13开始,this.refs在AFTER componentDidMount()运行之前可能无法使用,在某些奇怪的情况下.

只需将autoFocus标记添加到输入字段,如上面的FakeRainBrigand所示.

  • 多个`<input autofocus>`字段表现不佳 (4认同)
  • 当然不是.每页只有一个焦点.如果您有多个自动对焦,则应检查代码和意图. (4认同)
  • @ Dave的问题是关于在渲染后将焦点设置在`<input>`上 (2认同)

o01*_*o01 11

参考.@Dave评论@ Dhiraj的回答; 另一种方法是在正在渲染的元素上使用ref属性的回调功能(在组件首次渲染之后):

<input ref={ function(component){ React.findDOMNode(component).focus();} } />
Run Code Online (Sandbox Code Playgroud)

更多信息


Pav*_*ala 11

这是正确的方法,如何自动对焦.当您使用回调而不是字符串作为ref值时,会自动调用它.您可以获得您的参考,而无需使用DOMgetDOMNode

render: function() {
  return <TextInput ref={(c) => this._input = c} />;
},
componentDidMount: function() {
  this._input.focus();
},
Run Code Online (Sandbox Code Playgroud)

  • 受控形式呢? (2认同)

Dan*_*iel 9

在 Typescript 中使用 React Hooks/Functional 组件,您可以使用useRef钩子withHTMLInputElement作为 的泛型参数useRef

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

export default function MyComponent(): JSX.Element {
    const inputReference = useRef<HTMLInputElement>(null);

    useEffect(() => {
        inputReference.current?.focus();
    }, []);

    return (
        <div>
            <input ref={inputReference} />
        </div>
    );
}
Run Code Online (Sandbox Code Playgroud)

或者,如果使用reactstrap,请提供inputReferenceinnerRef而不是ref

import React, { useEffect, useRef } from 'react';
import { Input } from 'reactstrap';

export default function MyComponent(): JSX.Element {
    const inputReference = useRef<HTMLInputElement>(null);

    useEffect(() => {
        inputReference.current?.focus();
    }, []);

    return (
        <div>
            <Input innerRef={inputReference} />
        </div>
    );
}
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢! (2认同)

Raz*_*ill 8

您可以将该方法调用放在render函数中.或者在生命周期方法中,componentDidUpdate


Lan*_*tig 8

请注意,使用material-ui TextField组件,这些答案都不适用于我.Per 如何将焦点设置为materialUI TextField?我不得不跳过一些箍来让它工作:

const focusUsernameInputField = input => {
  if (input) {
    setTimeout(() => {input.focus()}, 100);
  }
};

return (
  <TextField
    hintText="Username"
    floatingLabelText="Username"
    ref={focusUsernameInputField}
  />
);
Run Code Online (Sandbox Code Playgroud)

  • 好像您的组件正在动画中一样,对focus()的调用必须延迟到动画结束。 (2认同)

Ali*_*eza 7

你不需要getInputDOMNode?? 在这种情况下...

只需简单地得到reffocus()它时,组件被安装- componentDidMount ...

import React from 'react';
import { render } from 'react-dom';

class myApp extends React.Component {

  componentDidMount() {
    this.nameInput.focus();
  }

  render() {
    return(
      <div>
        <input ref={input => { this.nameInput = input; }} />
      </div>
    );
  }

}

ReactDOM.render(<myApp />, document.getElementById('root'));
Run Code Online (Sandbox Code Playgroud)


Pav*_*hev 7

那对我有用:

<input autoFocus={true} />
Run Code Online (Sandbox Code Playgroud)


SHI*_*485 6

我有同样的问题,但我也有一些动画,所以我的同事建议使用 window.requestAnimationFrame

这是我的元素的 ref 属性:

ref={(input) => {input && window.requestAnimationFrame(()=>{input.focus()})}}
Run Code Online (Sandbox Code Playgroud)


小智 5

AutoFocus最适合我。我需要双击将某些文本更改为带有该文本的输入,所以最终得到的结果是:

<input autoFocus onFocus={this.setCaretToEnd} value={this.state.editTodo.value} onDoubleClick={this.updateTodoItem} />
Run Code Online (Sandbox Code Playgroud)

注:要解决React将插入号放置在文本开头的问题,请使用以下方法:

setCaretToEnd(event) {
    var originalText = event.target.value;
    event.target.value = '';
    event.target.value = originalText;
}
Run Code Online (Sandbox Code Playgroud)

在这里找到:https : //coderwall.com/p/0iz_zq/how-to-put-focus-at-the-end-of-an-input-with-react-js