如何在反应组件(打字稿+ css)中使用向上和向下键切换div焦点

Posted

技术标签:

【中文标题】如何在反应组件(打字稿+ css)中使用向上和向下键切换div焦点【英文标题】:How to toggle div focus using up and down key in react component (typescript + css) 【发布时间】:2021-08-28 10:53:49 【问题描述】:

我在各种 div 中呈现数据,我想在用户按下向上/向下箭头时选择/聚焦 div。

对于使用向上/向下键选择 div,我看到使用 ref 和 ForewardRef 作为子组件,我们可以切换焦点,但仍在努力弄清楚如何在打字稿代码中实现这一点。

我对此反应不熟悉,因此欢迎对以下代码提出任何建议或改进。

下面是我的代码。

选项.ts

export interface option 
id:number;
label:string;
value:string;

App.tsx

 import React, useRef, useEffect from 'react';
 import  option  from './option';
 import Options from './options';

 export default function App() 
  const options : option[] = [
     id:0, label : "Option 1", value:"12000",
     id:1, label : "Option 2", value:"10000" ,
     id:2, label : "Option 3", value:"11000",
     id:3, label : "Option 4", value:"23000" 
   ];


   const [invTheme, setInvTheme] = React.useState("10000");
   const firstRef = React.createRef<htmlDivElement>();
   const checkedRef = React.createRef<HTMLDivElement>();

  useEffect(() => 
      if (checkedRef.current) 
          checkedRef.current.focus();
       else if (firstRef.current) 
      firstRef.current.focus();
   
  , []);

   return (
     <div className="App">
      
      options.map((option, i) => 
        const id, label, value = option;
        const checked = invTheme === value;

        return (
          <div key=i>
            <Options id=id label=label value=value checked=checked
             onChange=() =>
              setInvTheme(value);
            />
            <br></br>
          </div>
        )
      )
   
</div>
  );
 

Options.tsx

import React, useEffect from 'react'
import  makeStyles, createStyles, Theme  from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';

 const useStyles = makeStyles((theme: Theme) =>
  createStyles(
        root: 
         flexGrow: 1,
         ,
         div: 
  padding: theme.spacing(2),
  margin: 'auto',
  maxWidth: 700,
  border:`1px solid Gray`
,
selectedDiv: 
  padding: theme.spacing(2),
  margin: 'auto',
  maxWidth: 700,
  border: `2px solid Blue`

),);

 export default function Options(props:any) 
  const classes = useStyles();
  //const [selectedDiv, setSelectedDiv] = React.useState(false);

  //useEffect(()=>
       //if(checked) setSelectedDiv(true);
     //,[])

 const handleOnClick = (e:any) => 
    if (e.type === "click" && e.clientX !== 0 && e.clientY !== 0) 
      //setSelectedDiv(true);
     
      onChange(target:value);
    
  ;

const  id, label, value, onChange, checked  = props;
console.log("id: "+ id+" checked "+ checked);

return (
  <div>
    <div className=checked ? classes.selectedDiv : classes.div  onClick=handleOnClick>
    <Grid container spacing=2>
        <Grid item>
            <input id=id type="radio" name="type" aria-label=label checked=checked  value=value onChange=onChange/>
        </Grid>
        <Grid item >
            label
        </Grid>
    </Grid>
  </div>
  </div>
);

【问题讨论】:

【参考方案1】:

我就是这样解决的。

我利用checked props来控制div的style属性。

在代码下方找到:

options.tsx:

import React, useEffect from 'react'
import  makeStyles, createStyles, Theme  from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';

 const useStyles = makeStyles((theme: Theme) =>
  createStyles(
        root: 
         flexGrow: 1,
         ,
         div: 
  padding: theme.spacing(2),
  margin: 'auto',
  maxWidth: 700,
  border:`1px solid Gray`,
 
,
selectedDiv: 
  padding: theme.spacing(2),
  margin: 'auto',
  maxWidth: 700,
  border:`1px solid Gray`,
,
selected: 
  

),);

 export default function Options(props:any) 
  const classes = useStyles();
  const [selectedDiv, setSelectedDiv] = React.useState(false);
  const  id, label, selected, value, onChange, checked  = props;
  useEffect(()=>
       if(selected) setSelectedDiv(true);
     ,[])

 const handleOnClick = (e:any) => 
    if (e.type === "click" && e.clientX !== 0 && e.clientY !== 0) 
      setSelectedDiv(true);
     
      onChange(target:value);
    
  ;



return (
  <div>
    <div className=selectedDiv  ?  classes.selectedDiv :classes.div  onClick=handleOnClickstyle = checked && selectedDiv? border: `2px solid Blue`,maxWidth: 700,: >
    <Grid container spacing=2 >
        <Grid item>
            <input id=id type="radio" name="type" aria-label=label checked=checked  value=value onChange=onChange/>
        </Grid>
        <Grid item >
            label
        </Grid>
    </Grid>
  </div>
  </div>
);

App.tsx:

import React, useRef, useEffect from 'react';
 import  option  from './option';
 import Options from './options' 


 

 export default function App()  
  const options : option[] = [
     id:0, label : "Option 1", selected : false, value:"12000",
     id:1, label : "Option 2", selected : true,  value:"10,000" ,
     id:2, label : "Option 3", selected : false, value:"10000",
     id:3, label : "Option 4", selected : false, value:"23000" 
   ];


   const [invTheme, setInvTheme] = React.useState("12000");
   const firstRef = React.createRef<HTMLDivElement>();
   const checkedRef = React.createRef<HTMLDivElement>(); 
 

  useEffect(() => 
      if (checkedRef.current) 
          checkedRef.current.focus();
       else if (firstRef.current) 
      firstRef.current.focus();
   
  , []);


   return (
     <div className="App">
      
      options.map((option, i) => 
        const id, label, selected, value = option;
        const checked = invTheme === value;
 
        return (
          <div key=i  >
            <Options id=id label=label selected=selected value=value checked=checked
             onChange=() =>
              setInvTheme(value);
               />
            <br></br>
          </div>
        )
      )
   
</div>
  );
 

【讨论】:

感谢您的样式条件输入,我得到了修改类条件并获得突出显示的 div 的想法。我已经更新了我想要实现的第二个问题的问题。

以上是关于如何在反应组件(打字稿+ css)中使用向上和向下键切换div焦点的主要内容,如果未能解决你的问题,请参考以下文章

如何在带有打字稿的反应功能组件中定义自定义道具?

如何插入 data.json 以使组件与界面中的所有属性(打字稿)发生反应

为我的反应打字稿组件库生成/维护打字稿定义文件

如何将声音文件导入反应打字稿组件?

使用打字稿进行反应组件子类型检查

反应路由器/反应查询不会取消/发出导航请求 - 反应/打字稿