[英]How to iterate through list of items in React list using arrow keys
我在這個問題上看到過類似的帖子,但是當我嘗試實施他們的建議時,它永遠不會奏效。 我有活動狀態和我的搜索結果,它們在調度時返回。 當我輸入輸入搜索或單擊它時,菜單會在其下方打開並顯示結果,但是當我按下箭頭鍵時,它會停留在輸入欄中並且不會遍歷/聚焦每個列表項。 我想這樣做,以便當我點擊向下或向上箭頭鍵時,它會遍歷搜索結果,我可以在其中任何一個上按 Enter 以觸發搜索。
const [active, setActive] = useState(0)
const searchResults = useSelector((state) => Object.values(state.searchReducer.Search))
const keyDown = (e) => {
if(e.key === 38 && searchResults.length > 0){
setActive(active - 1)
}else if(e.key === 40 && active < searchResults.length - 1){
setActive(active + 1)
}
}
<BsSearch className="search-icon" />
<form onSubmit={handleSubmit}>
<input
onClick={() => setMenu(true)}
className="search-input"
autoFocus
onKeyDown={keyDown}
type="search"
placeholder="Search"
onChange={(e) => setSearchVal(e.target.value)}
value={searchVal}
/>
</form>
{menu && (
<div className="search-cont">
{searchResults.length > 0 ? (
searchResults?.map((ele, i) => {
return (
<NavLink onClick={(() => {setSearchVal('')})} key={i} className="spot-
links" to={`/users/${ele.id}`}>
<div
className="search-results-list"
id={active === i ? 'active' : null}
>
{ele.username}
</div>
</NavLink>
);
})
```
使用您當前的方法,有幾個因素對您不利:
id
設置為“活動”,除了更改元素的 id 之外不會做任何事情資源:
演示: https ://rlzdrf.csb.app/
帶注釋的代碼(為簡單起見,我使用帶有簡單按鈕交互的硬編碼搜索數據):
import { useCallback, useState, useEffect } from "react";
import Instructions from "./Instructions";
import SEARCH_DATA from "./searchData";
export default function App() {
const [activeIndex, setActiveIndex] = useState(0);
const [showResults, setShowResults] = useState(false);
const handleClick = (name: string) => {
alert(`You've selected ${name}!`);
};
// captures up/down/enter/escape keys
const handleSelection = useCallback(
(event: KeyboardEvent) => {
// prevent key presses from being captured if the results are hidden
if (!showResults) return;
const { key } = event;
const arrowUpPressed = key === "ArrowUp";
const arrowDownPressed = key === "ArrowDown";
const escapePressed = key === "Escape" || key === "Esc";
const enterPressed = key === "Enter";
const searchDataLength = SEARCH_DATA.length - 1;
// increments active index (wraps around when at top)
if (arrowUpPressed) {
event.preventDefault();
setActiveIndex((currentIndex) =>
currentIndex - 1 >= 0 ? currentIndex - 1 : searchDataLength
);
// decrements active index (wraps around when at bottom)
} else if (arrowDownPressed) {
event.preventDefault();
setActiveIndex((currentIndex) =>
currentIndex + 1 <= searchDataLength ? currentIndex + 1 : 0
);
// alerts active selection
} else if (enterPressed) {
event.preventDefault();
const target = event.target as HTMLElement;
alert(`You've selected ${target.dataset.name}!`);
// closes results
} else if (escapePressed) {
event.preventDefault();
setActiveIndex(0);
setShowResults(false);
}
},
[showResults]
);
// globally listens for key presses
useEffect(() => {
document.addEventListener("keydown", handleSelection);
return () => {
document.removeEventListener("keydown", handleSelection);
};
}, [handleSelection]);
// when the active selection changes, it focuses on the active element
useEffect(() => {
if (showResults) {
const activeElement = document.querySelector(
`[data-index='${activeIndex}']`
) as HTMLElement;
if (activeElement) activeElement.focus();
}
}, [showResults, activeIndex]);
return (
<div className="app">
<h1>Hello CodeSandbox</h1>
<h2>Press the "Show Results" button!</h2>
<Instructions />
<button
className="results"
type="button"
onClick={() => {
// toggle results
setShowResults((r) => !r);
// reset active index to 0 when results are closed
if (!showResults) setActiveIndex(0);
}}
>
Show Results
</button>
{showResults && SEARCH_DATA.length > 0
? SEARCH_DATA.map(({ id, name }, index) => (
<button
type="button"
role="presentation"
data-index={index}
data-name={name}
className={`name ${activeIndex === index ? "active" : ""}`}
key={id}
onClick={() => {
setActiveIndex(index);
handleClick(name);
}}
>
{name}
</button>
))
: null}
</div>
);
}
這只是完成上述任務的眾多方法之一,因此請隨意探索其他方法。 例如,您可能希望將焦點吸引到搜索結果中並聚焦鍵。 此外,如果您正在為可訪問性進行設計,最好對WCAG 2.1標准進行一些研究——它們還為各種不同的用例提供了一些很好的示例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.