如何使用React聚焦到下一个输入框

10

我正在创建一个类似 Wordle 的游戏,为了实现这个目标,当用户输入字母时,应用程序应该聚焦到下一个输入框。但是我无法做到这一点,也不知道原因。

    
const GameLine = (props) => {

    const lineIndex = props.index;
  
    const checkTry = () => {
        const userGuess = firstLetter + ' ' + secondLetter + ' ' + thirdLetter + ' ' + fourthLetter + ' ' + fifthLetter;
        console.log(userGuess);
    }

    const [firstLetter, setFirstLetter] = useState(null);
    const [secondLetter, setSecondLetter] = useState(null);
    const [thirdLetter, setThirdLetter] = useState(null);
    const [fourthLetter, setFourthLetter] = useState(null);
    const [fifthLetter, setFifthLetter] = useState(null);
  
    const handleNextInput = (e) => {
        console.log("ID atual: " + e.target.id);
        const fieldName = e.target.id.split('-')[1];
        const nextSibiling = document.getElementById(`box${lineIndex}-${parseInt(fieldName) + 1}`);
        console.log(nextSibiling);
        if(nextSibiling !== null){
            nextSibiling.focus();
        }
    }


    return ( 
        <BoxesDiv>
            <Box1 type="text" id={ `box${lineIndex}-1`} onChange={(e) => { handleNextInput(e); setFirstLetter(e.target.value)}} value={firstLetter} /> 
            <Box2 type="text" id={ `box${lineIndex}-2`} onChange={(e) => setSecondLetter(e.target.value)} value={secondLetter} onKeyPress={(e)=>handleNextInput(e)}/>
            <Box3 type="text" id={ `box${lineIndex}-3`} onChange={(e) => { handleNextInput(e); setThirdLetter(e.target.value)}} value={thirdLetter} /> 
            <Box4 type="text" id={ `box${lineIndex}-4`} onChange={(e) => { handleNextInput(e); setFourthLetter(e.target.value)}} value={fourthLetter} />
            <Box5 type="text" id={ `box${lineIndex}-5`} onChange={(e) => setFifthLetter(e.target.value)} value={fifthLetter} onKeyPress={ (e)=>{ if(e.key === "Enter"){checkTry()} } }/>
        </BoxesDiv>  
    );
}

我试图通过id获取下一个输入框,并使用Element.focus(),但没有任何反应。能否有人帮我找到错误所在?
谢谢。
5个回答

4

React访问元素的方式是使用refs。您可以最初创建一个ref数组并将它们映射到输入框。添加keyup事件监听器以更新输入焦点到下一个输入框。

尝试以下操作。

import { useState, createRef, useEffect } from "react";

const GameLine = (props) => {
  const lineIndex = props.index;
  // number of inputs
  const numerOfInputs = props?.numerOfInputs || 5;

  // create a array of refs
  const [inputRefsArray] = useState(() =>
    Array.from({ length: numerOfInputs }, () => createRef())
  );

  // state for current input index
  const [currentIndex, setCurrentIndex] = useState(0);

  // save letters in a array where each entry in the array refers to an input
  const [letters, setLetters] = useState(() =>
    Array.from({ length: numerOfInputs }, () => "")
  );

  const handleKeyPress = () => {
    setCurrentIndex((prevIndex) => {
      // calculate the next input index, next input after the final input will be again the first input. you can change the logic here as per your needs
      const nextIndex = prevIndex < numerOfInputs - 1 ? prevIndex + 1 : 0;
      const nextInput = inputRefsArray?.[nextIndex]?.current;
      nextInput.focus();
      nextInput.select();
      return nextIndex;
    });
  };

  useEffect(() => {
    // focus the firs iput initially
    if (inputRefsArray?.[0]?.current) {
      inputRefsArray?.[0]?.current?.focus();
    }
    
    // add the event listener for keyup keyboard event
    window.addEventListener("keyup", handleKeyPress, false);
    
    // remove the event listener when the component unmounts
    return () => {
      window.removeEventListener("keyup", handleKeyPress);
    };
  }, []);

  return (
    <div>
      {inputRefsArray.map((ref, index) => {
        return (
          <input
            ref={ref}
            type="text"
            id={`box${index}-1`}
            onChange={(e) => {
              const { value } = e.target;
              setLetters((letters) =>
                letters.map((letter, letterIndex) =>
                  letterIndex === index ? value : letter
                )
              );
            }}
            onClick={(e) => {
              setCurrentIndex(index);
              e.target.select();
            }}
            value={letters[index]}
            max={"1"}
          />
        );
      })}
    </div>
  );
};

export default GameLine;

Edit ecstatic-franklin-m94ci0


1
你应该在第二个框中调用 handleNextInput 函数。我认为你可以使用 onKeyUp 函数来处理 handleNextInput
<Box2 onKeyUp={(e)=>handleNextInput(e)} ... />

0

我使用输入ID和文档来设置焦点

document.getElementById('txt0').focus();

如果您有动态字段,可以添加一个动态 id。例如:
                {arrayItems.map((item, index) => {
                        <TextField
                          id={'txt' + index}
                          onKeyUp={(event) => {
                            if (event.key == 'ArrowDown') {
                              document.getElementById(`txt`+(index+1)).focus();
                            }
                            if (event.key == 'ArrowUp' && index > 0) {
                              document.getElementById(`txt`+(index-1)).focus();
                            }
                          }}
                        />
                }
                        

0

你可以声明一个函数来检查用户是否按下了回车键。 如果是,你将得到表单中第一个元素的索引。然后将焦点放在具有(索引+2)的元素上。 因为第一个文本字段的索引为0,第二个文本字段的索引为2。

    function handleEnter(event){
                        console.log(event.key)
                        if (event.key === "Enter") {
                            const form = event.target.form;
                            const index = [...form].indexOf(event.target);
                            console.log(index)
                            form[index + 2].focus();
                            event.preventDefault();
                          }
                    }
            
            
    <form>
            
 <TextField onKeyDown={(e)=>handleEnter(e)} variant="outlined" label='name' />
 <TextField onKeyDown={(e)=>handleEnter(e)} variant="outlined" label='age' />
                    
 <Buttontype='submit' variant="contained" >Ajouter le client</Button>
                       
    </form>
              
       

0

如果由于某种原因您无法访问event,您可以这样做:

const someMethodWithoutAccessToEvent = () => {
  const active = document.activeElement;
  if (active?.nextElementSibling) {
    (active.nextElementSibling as HTMLElement).focus();
  }
}

运行得非常好


不适用于元素位于不同的父级 - apc

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