首页 > 解决方案 > 使用 ref 专注于 Input 元素不起作用

问题描述

大家好,我正在做一个项目,我需要使用箭头键处理焦点元素。现在一切正常,功能通过点击工作。不幸的是,当我使用箭头键时,该过程适用于 tr 元素,但不适用于输入元素。

这是应用程序组件:

    import React from "react";
import "./App.css";
import RenderRowItem from "./RenderRow";
const keysMapNum={
    LEFT:37,
    UP:38,
    RIGHT:39,
    DOWN:40,
    ENTER:13,
    TAB:9,
    CTRL:17
};
class App extends React.Component {
  state = {
    data: [],
    formData: [],
    selectedInput:[0,0]
  };
  componentDidMount() {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then(response => response.json())
      .then(json => {
        const data = json.map(({ id, name, username, email }) => {
          return {
            id,
            name,
            username,
            email
          };
        });
          const mappedData=[];
        data.forEach(item=>{
            const rowRef=React.createRef();
            const rowData=[];
           Object.keys(item).forEach(innerItem=>{
               let optimizedData = {
                   filedName:innerItem,
                   value:item[innerItem],
                   hint:false,
                   ref:React.createRef(),
                   editable:true,
                   visible:true,
                   focused:false
               };
               rowData.push(optimizedData);

           });
           const mappedDataItem = {
               rowRef,
               rowData,
               focused:false
           };
           mappedData.push(mappedDataItem);

        });
        console.log(mappedData);
        this.setState({
          data:mappedData
        },()=>{
            console.log(this.state.data)
        });

      });
      document.addEventListener("keydown",(e)=>{
          // e.preventDefault();
            const newState={...this.state};
            console.log("doc",newState);
            let [rowNum,columnNum]=[...newState.selectedInput];
            const rowLength=newState.data.length;

            const columnLength=newState.data[rowNum]["rowData"].length;
            if(e.keyCode===keysMapNum.DOWN){
                rowNum++;
                if(rowNum>=rowLength){
                    rowNum=0;

                }
                newState.selectedInput[0]=rowNum;
                this.selectedColumn(rowNum,columnNum);
                this.setState({
                    ...newState
                },()=>{
                    this.selectedRow(rowNum,newState.data[rowNum].rowRef);


                });
            }else if(e.keyCode===keysMapNum.UP){
                rowNum--;

                if(rowNum<0){
                    rowNum=rowLength - 1;

                }
                newState.selectedInput[0]=rowNum;
                this.selectedColumn(rowNum,columnNum)
                this.setState({
                    ...newState
                },()=>{
                    this.selectedRow(rowNum,newState.data[rowNum].rowRef);

                })
            }else if(e.keyCode===keysMapNum.LEFT){

            }else if(e.keyCode===keysMapNum.RIGHT){

            }
            this.setState({
                ...newState
            })
      });
  }
  selectedRow=(rowNum,ref)=>{
      const newState={...this.state};
    newState.data.forEach(item=>{
   if(item.rowRef.current!==null){
       item.rowRef.current.style.backgroundColor="";
       item.rowRef.current.style.color="#333";
   }
    });
      if(ref.current!==null){
          ref.current.style.backgroundColor="gray";
          ref.current.style.color="white";
      }
      // if(newState.data[rowNum]["rowData"][0].ref.current!==null){newState.data[rowNum]["rowData"][0].ref.current.focus();
      // newState.data[rowNum]["rowData"][0].ref.current.select();}
  };
  selectedColumn=(rowNum,columnNum)=>{
 const newState={...this.state};
 let ref=newState.data[rowNum]["rowData"][columnNum].ref;
      newState.data[rowNum]["rowData"][columnNum].ref.current.style.backgroundColor="tomato";
if(ref.current!==null){
    ref.current.focus();
    ref.current.select();
}
  };
    handleInputClick=(rowNum,columnNum)=>{
    const newState={...this.state};
    newState.selectedInput=[rowNum,columnNum];
    newState.data[rowNum]["focused"]=true;
    newState.data[rowNum]["rowData"][columnNum]["focused"]=true;
    this.setState({
        ...newState
    },()=>{
        this.selectedColumn(rowNum,columnNum);
    })
    };
 setRef=(ref)=> {
        this.name = ref;
    };
  render() {
    const { data } = this.state;

    // { id, name, username, email }
    return (
      <div className="App">
        <table>
            <tbody>
          {data.map((datum, rowNum) => {
            return (
              <tr key={rowNum} ref={datum.rowRef} onClick={()=>this.selectedRow(rowNum,datum.rowRef)}>

                  {datum.rowData.map((item,columnNum) => (

                    <RenderRowItem  key={Math.random()} ref={item.ref} handleInputClick={this.handleInputClick} rowNum={rowNum} columnNum={columnNum} value={item.value} fieldName={item.filedName}/>
                  ))}
              </tr>
            );
          })}
            </tbody>
        </table>
      </div>
    );
  }
}

export default App;

这是 RowItem 组件:

   import React from "react";
const RenderRow=React.forwardRef((props,ref)=>(
    <>

        <td  onClick={()=>props.handleInputClick(props.rowNum,props.columnNum)} >{props.filedName!=="id"?<input  type="text" value={props.value} ref={ref} />:props.value}</td>

    </>
));
export default RenderRow;

这个结构只是测试,我知道需要优化。请仅使用向上和向下箭头键。 这是沙盒链接

标签: javascriptreactjsrefs

解决方案


推荐阅读