JS' 공부흔적

[JavaScript] 마우스로 버튼을 클릭할 때와 키보드로 버튼을 클릭할 때를 구분하는 방법 본문

JavaScript

[JavaScript] 마우스로 버튼을 클릭할 때와 키보드로 버튼을 클릭할 때를 구분하는 방법

이준수 2023. 5. 24. 15:41

같은 버튼을 클릭해도 마우스로 클릭할 때와 키보드로 클릭할 때 다르게 동작하도록 구현할 필요가 생겼다. 원래는 키보드를 눌렀을 때 useState()를 통해 boolean state로 관리하려고 했지만, 의도한 대로 동작하지 않았다.

이를 event 객체의 detail을 사용하여 해결했다.

event.detail이란?

event.detail은 특정 이벤트 내에서 마우스로 버튼을 누른 횟수를 나타낸다. 버튼이 한 번 눌렸다면 1, 더블 클릭을 했다면 2, 그 이상 다중 클릭을 했다면 해당 숫자만큼 표시된다. 아래 각 경우에 해당하는 예시를 보자.

 

한 번 클릭
더블 클릭
다중 클릭

 

위에서 언급했듯이 특정 이벤트 내에서 마우스로 버튼을 누른 횟수를 나타내기 때문에, 만약 키보드 동작으로 버튼을 클릭한다면 event.detail 값은 0이 나온다.

 

키보드를 통한 버튼 클릭

 

event.detail을 사용하여 아래와 같이 구현했다.

  • 마우스로 버튼을 클릭할 때는 처음 버튼부터 누른 버튼까지 모두 색칠되도록 구현
  • 키보드에 의해(나의 경우 엔터키) 버튼을 클릭할 때는 버튼이 차례대로 색칠되도록 구현

 

최종 결과

 

 

코드는 아래와 같다.

// App.tsx

import { useRef, useState } from "react";
import { Button, Wrap } from "./App.style";

const App = () => {
  const buttons = [1, 2, 3];

  const divRef = useRef<HTMLDivElement>(null);
  const buttonRef = useRef<HTMLButtonElement>(null);
  const [count, setCount] = useState(0);

  const onKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
    if (event.key === "Enter" && buttonRef.current) {
      buttonRef.current.click();
    }
  };

  const onClick = (event: React.MouseEvent<HTMLButtonElement>, btn: number) => {
    if (event.detail) {
      setCount(btn);
    } else {
      setCount((prev) => (prev + 1) % 4);
    }
    if (divRef.current) divRef.current.focus();
  };

  return (
    <Wrap ref={divRef} tabIndex={0} onKeyDown={onKeyDown}>
      {buttons.map((btn) => (
        <Button
          ref={buttonRef}
          key={btn}
          isFilled={btn <= count}
          onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
            onClick(event, btn)
          }
        />
      ))}
    </Wrap>
  );
};

export default App;
// App.style.ts

import styled from "styled-components";

export const Wrap = styled.div`
  background-color: wheat;
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  gap: 16px;
`;

export const Button = styled.button<{ isFilled: boolean }>`
  width: 100px;
  height: 100px;
  border-radius: 50%;
  border: 1px solid black;
  background-color: ${({ isFilled }) => (isFilled ? "black" : "white")};
`;

 

 

 

 

728x90
반응형