그리드 항목에 대한 사용자 정의 키보드 탐색 생성
9365 단어 a11yreacttypescript
전제 조건: React에 대한 기본 지식.
Check out the working project demo site 우리가 만들고 있는 것을 볼 수 있습니다.
시작 코드 설정
Get starter GitHub repository을 참조하여 코드를 자세히 살펴보십시오. 저장소를 복제하거나 전체 파일을 다운로드할 수 있습니다.
선호하는 편집기에서 코드를 열고 명령을 실행하십시오
yarn install && yarn start
. 그러면 로컬 환경에서 코드가 실행됩니다.프로젝트 시작
이제 코딩을 시작할 준비가 되었습니다. 먼저 제목을 추가하고 항목을 표시해 보겠습니다. 항목에 필요한 모든 데이터는 파일
items.json
에 있습니다. 그것들을 App
로 가져와 각각을 반복할 수 있습니다.import "./App.css";
import items from "./items.json";
function App() {
return (
<main className="main">
<h1 className="title">Custom keyboard navigation</h1>
<section className="items">
{items.map((item) => {
return <article>single item</article>;
})}
</section>
</main>
);
}
export default App;
현재 우리는 각 항목에 대해 동일한 텍스트만 표시합니다. 이미지와 확인란을 표시하기 위해 변경할 수 있습니다.
Item
내부의 구성 요소src/components/Item.tsx
를 열고 구성 요소를 업데이트합니다.import "./Item.css";
type ItemProps = {
description: string;
id: number;
name: string;
url: string;
};
function Item(props: ItemProps) {
const { description, name, url } = props;
return (
<div className="item">
<input className="input" type="checkbox" name={name} id={name} />
<img className="image" src={url} alt={description} />
</article>
);
}
export default Item;
또한
Item
를 App
로 가져와 모든 소품을 전달해야 합니다. 여기서는 수동으로 각 소품을 추가하는 대신 모든 소품을 펼칩니다.import "./App.css";
import Item from "./components/Item";
import items from "./items.json";
function App() {
return (
<main className="main">
<h1 className="title">Custom keyboard navigation</h1>
<section className="items">
{items.map((item) => {
return <Item {...item} />;
})}
</section>
</main>
);
}
export default App;
이제 두 구성 요소에 몇 가지 스타일을 추가하여 앱을 더 보기 좋게 만들 수 있습니다.
App.css
에서 우리는 스타일을 기본으로 만들고 그리드 안에 항목을 표시합니다..main {
margin: auto;
max-width: 1000px;
text-align: center;
}
.items {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
}
Item.css
에서 이미지 스타일을 지정하고 절대적으로 위치 확인란을 지정합니다..item {
position: relative;
height: 150px;
border-radius: 10px;
overflow: hidden;
cursor: pointer;
border: 2px solid lightgray;
}
.image {
width: 100%;
height: 100%;
object-fit: cover;
}
.input {
position: absolute;
width: 18px;
height: 18px;
cursor: pointer;
}
다음에 할 일은 이미지를 클릭할 때 확인란을 선택하는 것입니다. 이렇게 하면 작은 확인란을 클릭하는 것보다 전체 사용자 경험이 훨씬 좋아집니다.
그렇게 하려면 확인란이 선택되었는지 추적하기 위해 내부에 상태
Item
를 추가해야 합니다. onClick
핸들러를 전체 항목에 추가하고 checked
속성을 통해 체크박스 상태를 수동으로 설정합니다.import { useState } from "react";
import "./Item.css";
type ItemProps = {
description: string;
id: number;
name: string;
url: string;
};
function Item(props: ItemProps) {
const { description, name, url } = props;
const [isChecked, setIsChecked] = useState(false);
return (
<div
className={isChecked ? "item checked" : "item"}
onClick={() => setIsChecked(!isChecked)}
>
<input
className="input"
type="checkbox"
name={name}
id={name}
checked={isChecked}
/>
<img className="image" src={url} alt={description} />
</article>
);
}
export default Item;
위의 코드에서 새 클래스 이름
checked
을 추가했으므로 Item.css
에도 추가해야 합니다..checked {
border: 2px solid rgb(36, 36, 174);
}
사용자 정의 키보드 탐색 추가
현재 앱을 탭하면 포커스가 한 확인란에서 다른 확인란으로 변경됩니다. 항목 수가 적은 경우에도 괜찮습니다. 500개의 항목을 표시하고 키보드를 통해 앱의 다음 섹션으로 이동하려고 한다고 상상해 보십시오. 다음 섹션으로 이동하기 위해 500개 항목을 탭으로 이동하시겠습니까? 아마 아닐 겁니다. 다행히 긴 항목 목록을 탐색하는 더 좋은 방법이 있습니다.
아이디어는 간단합니다.
tabIndex=0
(포커스 가능)가 있는 확인란이 하나만 있고 다른 모든 확인란은 tabIndex=-1
(키보드 탐색으로 무시됨)가 있습니다. 그런 다음 사용자가 클릭하는 화살표에 따라 각 항목을 프로그래밍 방식으로 변경합니다tabIndex
.우리 코드로 돌아가자.
App
안에 ref
에 main
를 추가하여 내부에서 키보드 클릭만 듣도록 합니다. 또한 현재 초점이 맞춰진 항목을 알기 위해 추적 커서에 대한 상태를 추가합니다.첫 번째
useEffect
안에 이벤트 리스너를 추가합니다. 각 키보드 버튼에서 기능handleKey
을 누르면 실행됩니다. 내부에서 화살표 키 누름을 찾고 이를 기반으로 커서 상태를 수정합니다. 단순화하기 위해 numberOfColumns
는 하드 코딩되어 있습니다.두 번째
useEffect
에서는 이름을 기반으로 내부에서 올바른 확인란main
을 찾은 다음 초점을 맞춥니다.import { keyboardKey } from "@testing-library/user-event";
import { useEffect, useRef, useState } from "react";
import "./App.css";
import Item from "./components/Item";
import items from "./items.json";
function App() {
const itemsRef = useRef<HTMLElement>(null);
const [cursor, setCursor] = useState(1);
const numberOfColumns = 4;
const totalNumberOfFiles = items.length;
useEffect(() => {
const handleKey = (event: keyboardKey) => {
if (event.key === "ArrowRight") {
setCursor((prevCursor) => {
if (prevCursor === totalNumberOfFiles) {
return totalNumberOfFiles;
}
return prevCursor + 1;
});
}
if (event.key === "ArrowLeft") {
setCursor((prevCursor) => {
if (prevCursor === 0) {
return 0;
}
return prevCursor - 1;
});
}
if (event.key === "ArrowDown") {
setCursor((prevCursor) => {
if (prevCursor + numberOfColumns > totalNumberOfFiles) {
return prevCursor;
}
return prevCursor + numberOfColumns;
});
}
if (event.key === "ArrowUp") {
setCursor((prevCursor) => {
if (prevCursor - numberOfColumns < 0) {
return prevCursor;
}
return prevCursor - numberOfColumns;
});
}
};
if (itemsRef.current) {
const currentCursor = itemsRef.current;
currentCursor.addEventListener("keyup", handleKey);
return () => currentCursor.removeEventListener("keyup", handleKey);
}
}, [totalNumberOfFiles, numberOfColumns]);
useEffect(() => {
if (itemsRef.current) {
const selectCursor = itemsRef.current.querySelector(
`input[name='item ${cursor}']`
);
(selectCursor as HTMLInputElement)?.focus();
}
}, [cursor]);
return (
<main ref={itemsRef} className="main">
<h1 className="title">Custom keyboard navigation</h1>
<section className="items">
{items.map((item) => {
const tabIndex = cursor === item.id ? 0 : -1;
return <Item {...item} tabIndex={tabIndex} />;
})}
</section>
</main>
);
}
export default App;
마지막으로 추가해야 할 것은
tabIndex
에 Item
입니다.import { useState } from "react";
import "./Item.css";
type ItemProps = {
description: string;
id: number;
name: string;
url: string;
tabIndex: number;
};
function Item(props: ItemProps) {
const { description, name, url, tabIndex } = props;
const [isChecked, setIsChecked] = useState(false);
return (
<div
className={isChecked ? "item checked" : "item"}
onClick={() => setIsChecked(!isChecked)}
>
<input
className="input"
type="checkbox"
name={name}
id={name}
checked={isChecked}
tabIndex={tabIndex}
/>
<img className="image" src={url} alt={description} />
</article>
);
}
export default Item;
이 기사를 읽어 주셔서 감사합니다. 새로운 것을 배웠기를 바랍니다.
Link to the finished project GitHub repository
Reference
이 문제에 관하여(그리드 항목에 대한 사용자 정의 키보드 탐색 생성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/eruj22/create-custom-keyboard-navigation-for-grid-items-4ibn텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)