Javascript 反应:如何通过箭头键在列表中导航
我用一个文本输入构建了一个简单的组件,下面是一个列表(使用语义ui) 现在我想使用箭头键在列表中导航Javascript 反应:如何通过箭头键在列表中导航,javascript,reactjs,Javascript,Reactjs,我用一个文本输入构建了一个简单的组件,下面是一个列表(使用语义ui) 现在我想使用箭头键在列表中导航 首先,我必须选择第一个元素。但是如何访问特定的列表元素呢 其次,我将获得当前选定元素的信息并选择下一个元素。如何获取所选元素的信息 选择意味着将类活动添加到项目中,或者有更好的方法吗 export default class Example extends Component { constructor(props) { super(props) th
- 首先,我必须选择第一个元素。但是如何访问特定的列表元素呢
- 其次,我将获得当前选定元素的信息并选择下一个元素。如何获取所选元素的信息
活动添加到项目中,或者有更好的方法吗
export default class Example extends Component {
constructor(props) {
super(props)
this.handleChange = this.handleChange.bind(this)
this.state = { result: [] }
}
handleChange(event) {
// arrow up/down button should select next/previous list element
}
render() {
return (
<Container>
<Input onChange={ this.handleChange }/>
<List>
{
result.map(i => {
return (
<List.Item key={ i._id } >
<span>{ i.title }</span>
</List.Item>
)
})
}
</List>
</Container>
)
}
}
导出默认类示例扩展组件{
建造师(道具){
超级(道具)
this.handleChange=this.handleChange.bind(this)
this.state={result:[]}
}
手变(活动){
//向上/向下箭头按钮应选择下一个/上一个列表元素
}
render(){
返回(
{
result.map(i=>{
返回(
{i.title}
)
})
}
)
}
}
尝试以下方法:
export default class Example extends Component {
constructor(props) {
super(props)
this.handleKeyDown = this.handleKeyDown.bind(this)
this.state = {
cursor: 0,
result: []
}
}
handleKeyDown(e) {
const { cursor, result } = this.state
// arrow up/down button should select next/previous list element
if (e.keyCode === 38 && cursor > 0) {
this.setState( prevState => ({
cursor: prevState.cursor - 1
}))
} else if (e.keyCode === 40 && cursor < result.length - 1) {
this.setState( prevState => ({
cursor: prevState.cursor + 1
}))
}
}
render() {
const { cursor } = this.state
return (
<Container>
<Input onKeyDown={ this.handleKeyDown }/>
<List>
{
result.map((item, i) => (
<List.Item
key={ item._id }
className={cursor === i ? 'active' : null}
>
<span>{ item.title }</span>
</List.Item>
))
}
</List>
</Container>
)
}
}
导出默认类示例扩展组件{
建造师(道具){
超级(道具)
this.handleKeyDown=this.handleKeyDown.bind(this)
此.state={
光标:0,
结果:[]
}
}
handleKeyDown(e){
const{cursor,result}=this.state
//向上/向下箭头按钮应选择下一个/上一个列表元素
如果(e.keyCode===38&&cursor>0){
this.setState(prevState=>({
游标:prevState.cursor-1
}))
}else if(e.keyCode===40&&cursor({
游标:prevState.cursor+1
}))
}
}
render(){
const{cursor}=this.state
返回(
{
结果.map((项目,i)=>(
{item.title}
))
}
)
}
}
光标会跟踪您在列表中的位置,因此当用户按下向上或向下箭头键时,您会相应地减少/增加光标。光标应与数组索引一致
您可能希望使用onKeyDown
来查看箭头键,而不是onChange
,这样您就不会延迟或干扰标准的输入编辑行为
在渲染循环中,只需对照光标检查索引,以查看哪个索引处于活动状态
如果您正在根据字段的输入筛选结果集,您可以随时将光标重置为零,以便始终保持行为一致。接受的答案对我非常有用,谢谢!我对该解决方案进行了调整,并提出了一个建议,也许它会对某些人有用:
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
const useKeyPress = function(targetKey) {
const [keyPressed, setKeyPressed] = useState(false);
function downHandler({ key }) {
if (key === targetKey) {
setKeyPressed(true);
}
}
const upHandler = ({ key }) => {
if (key === targetKey) {
setKeyPressed(false);
}
};
React.useEffect(() => {
window.addEventListener("keydown", downHandler);
window.addEventListener("keyup", upHandler);
return () => {
window.removeEventListener("keydown", downHandler);
window.removeEventListener("keyup", upHandler);
};
});
return keyPressed;
};
const items = [
{ id: 1, name: "Josh Weir" },
{ id: 2, name: "Sarah Weir" },
{ id: 3, name: "Alicia Weir" },
{ id: 4, name: "Doo Weir" },
{ id: 5, name: "Grooft Weir" }
];
const ListItem = ({ item, active, setSelected, setHovered }) => (
<div
className={`item ${active ? "active" : ""}`}
onClick={() => setSelected(item)}
onMouseEnter={() => setHovered(item)}
onMouseLeave={() => setHovered(undefined)}
>
{item.name}
</div>
);
const ListExample = () => {
const [selected, setSelected] = useState(undefined);
const downPress = useKeyPress("ArrowDown");
const upPress = useKeyPress("ArrowUp");
const enterPress = useKeyPress("Enter");
const [cursor, setCursor] = useState(0);
const [hovered, setHovered] = useState(undefined);
useEffect(() => {
if (items.length && downPress) {
setCursor(prevState =>
prevState < items.length - 1 ? prevState + 1 : prevState
);
}
}, [downPress]);
useEffect(() => {
if (items.length && upPress) {
setCursor(prevState => (prevState > 0 ? prevState - 1 : prevState));
}
}, [upPress]);
useEffect(() => {
if (items.length && enterPress) {
setSelected(items[cursor]);
}
}, [cursor, enterPress]);
useEffect(() => {
if (items.length && hovered) {
setCursor(items.indexOf(hovered));
}
}, [hovered]);
return (
<div>
<p>
<small>
Use up down keys and hit enter to select, or use the mouse
</small>
</p>
<span>Selected: {selected ? selected.name : "none"}</span>
{items.map((item, i) => (
<ListItem
key={item.id}
active={i === cursor}
item={item}
setSelected={setSelected}
setHovered={setHovered}
/>
))}
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<ListExample />, rootElement);
import React,{useState,useffect}来自“React”;
从“react dom”导入react dom;
const useKeyPress=功能(targetKey){
const[keyPressed,setKeyPressed]=使用状态(false);
函数下处理程序({key}){
如果(键===目标键){
setKeyPressed(真);
}
}
常量upHandler=({key})=>{
如果(键===目标键){
setKeyPressed(假);
}
};
React.useffect(()=>{
addEventListener(“keydown”,downHandler);
addEventListener(“keyup”,upHandler);
return()=>{
removeEventListener(“keydown”,downHandler);
removeEventListener(“keyup”,upHandler);
};
});
按下返回键;
};
常数项=[
{id:1,名字:“Josh Weir”},
{id:2,姓名:“莎拉·威尔”},
{id:3,姓名:“Alicia Weir”},
{id:4,名字:“杜威尔”},
{id:5,姓名:“格罗奥特威尔”}
];
常量列表项=({item,active,setSelected,setHovered})=>(
(项目)}
onMouseCenter={()=>setHovered(项)}
onMouseLeave={()=>setHovered(未定义)}
>
{item.name}
);
常量ListExample=()=>{
const[selected,setSelected]=使用状态(未定义);
const downPress=useKeyPress(“箭头向下”);
const upPress=使用按键(“箭头向上”);
const enterPress=useKeyPress(“回车”);
const[cursor,setCursor]=useState(0);
常量[悬停,设置悬停]=使用状态(未定义);
useffect(()=>{
如果(items.length&向下按){
setCursor(prevState=>
prevState{
如果(项目.长度和加高){
setCursor(prevState=>(prevState>0?prevState-1:prevState));
}
},[upPress]);
useffect(()=>{
如果(items.length&&enterPress){
设置选定项(项目[光标]);
}
},[cursor,enterPress]);
useffect(()=>{
如果(items.length&悬停){
setCursor(items.indexOf(悬停));
}
},[悬停];
返回(
使用上下键并按enter键进行选择,或使用鼠标
选定:{选定?选定。名称:“无”}
{items.map((item,i)=>(
))}
);
};
const rootElement=document.getElementById(“根”);
render(,rootElement);
与@joshweir提供的解决方案几乎相同,但使用的是Typescript。我还使用了“ref”来代替“window”对象,并仅将事件侦听器添加到输入文本框中
import React, { useState, useEffect, Dispatch, SetStateAction, createRef, RefObject } from "react";
const useKeyPress = function (targetKey: string, ref: RefObject<HTMLInputElement>) {
const [keyPressed, setKeyPressed] = useState(false);
function downHandler({ key }: { key: string }) {
if (key === targetKey) {
setKeyPressed(true);
}
}
const upHandler = ({ key }: { key: string }) => {
if (key === targetKey) {
setKeyPressed(false);
}
};
React.useEffect(() => {
ref.current?.addEventListener("keydown", downHandler);
ref.current?.addEventListener("keyup", upHandler);
return () => {
ref.current?.removeEventListener("keydown", downHandler);
ref.current?.removeEventListener("keyup", upHandler);
};
});
return keyPressed;
};
const items = [
{ id: 1, name: "Josh Weir" },
{ id: 2, name: "Sarah Weir" },
{ id: 3, name: "Alicia Weir" },
{ id: 4, name: "Doo Weir" },
{ id: 5, name: "Grooft Weir" }
];
const i = items[0]
type itemType = { id: number, name: string }
type ListItemType = {
item: itemType
, active: boolean
, setSelected: Dispatch<SetStateAction<SetStateAction<itemType | undefined>>>
, setHovered: Dispatch<SetStateAction<itemType | undefined>>
}
const ListItem = ({ item, active, setSelected, setHovered }: ListItemType) => (
<div
className={`item ${active ? "active" : ""}`}
onClick={() => setSelected(item)}
onMouseEnter={() => setHovered(item)}
onMouseLeave={() => setHovered(undefined)}
>
{item.name}
</div>
);
const ListExample = () => {
const searchBox = createRef<HTMLInputElement>()
const [selected, setSelected] = useState<React.SetStateAction<itemType | undefined>>(undefined);
const downPress = useKeyPress("ArrowDown", searchBox);
const upPress = useKeyPress("ArrowUp", searchBox);
const enterPress = useKeyPress("Enter", searchBox);
const [cursor, setCursor] = useState<number>(0);
const [hovered, setHovered] = useState<itemType | undefined>(undefined);
const [searchItem, setSearchItem] = useState<string>("")
const handelChange = (e: React.SyntheticEvent<HTMLInputElement>) => {
setSelected(undefined)
setSearchItem(e.currentTarget.value)
}
useEffect(() => {
if (items.length && downPress) {
setCursor(prevState =>
prevState < items.length - 1 ? prevState + 1 : prevState
);
}
}, [downPress]);
useEffect(() => {
if (items.length && upPress) {
setCursor(prevState => (prevState > 0 ? prevState - 1 : prevState));
}
}, [upPress]);
useEffect(() => {
if (items.length && enterPress || items.length && hovered) {
setSelected(items[cursor]);
}
}, [cursor, enterPress]);
useEffect(() => {
if (items.length && hovered) {
setCursor(items.indexOf(hovered));
}
}, [hovered]);
return (
<div>
<p>
<small>
Use up down keys and hit enter to select, or use the mouse
</small>
</p>
<div>
<input ref={searchBox} type="text" onChange={handelChange} value={selected ? selected.name : searchItem} />
{items.map((item, i) => (
<ListItem
key={item.id}
active={i === cursor}
item={item}
setSelected={setSelected}
setHovered={setHovered}
/>
))}
</div>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<ListExample />, rootElement);
import React,{useState,useffect,Dispatch,SetStateAction,createRef,reobject}来自“React”;
const useKeyPress=函数(targetKey:string,ref:ReObject){
const[keyPressed,setKeyPressed]=使用状态(false);
函数下处理程序({key}:{key:string}){
如果(键===目标键){
setKeyPressed(真);
}
}
常量upHandler=({key}:{key:string})=>{
如果(