지금까지 모달창을 만들기 위해 Mui나 부트스트랩의 도움을 많이 받았었습니다.
제가 직접 만들어 쓰려고 시도를 했었지만, 딱 하나의 문제가 걸려 계속해서 사용했었습니다.
바로 영역 밖을 클릭하였을 때, 꺼지게 하는 기능입니다.
이번 작업에서 셀렉트 박스를 직접 만드는 기회가 생겨 그 기능을 구현해 보았고, 모달창에도 적용시킬 수 있습니다.
셀렉트 박스 전체를 ref 를 이용해 영역을 지정해준 뒤 , 클릭을 하는 곳이 그 영역 안에 있는지 확인을 해주는 방법입니다.
const [showSelect,setShowSelect] = useState(false)
{showSelect && <SelectBox/>}
const selectEl = useRef<HTMLDivElement>(null);
<SelcetBox ref={selectEl} />
useRef() 로 바로 사용하게 되면 타입지정이 되지않아 undefined로 인식하여 에러가 나기 때문에 타입을 반드시 지정해줍니다.
const handleClickOutside = (e:MouseEvent)=>{
if(selectEl.current)
if(!selectEl.current.contains(e.target as Node))
{
setShowSelect(false)
}
}
useEffect(()=>{
if(showSelect){
window.addEventListener('click',handleClickOutside)
}
return()=>{
window.removeEventListener('click',handleClickOutside)
}
},[showSelect])
useEffect를 이용해 클릭이벤트를 만들어줍니다.
showSelect가 변할 때마다, 셀렉트창이 열려 있다면 => 클릭할 때마다 함수를 실행시킵니다.
마우스 이벤트를 확인하고, 그 이벤트의 요소가 셀렉트 ref 요소라면 넘어가고, 요소가 아니라면 끄는 함수입니다.
실제로 어떻게 동작하는지 보겠습니다.
우선 selectEl의 current를 확인합니다.
console.log(selectEl.current)
<div class='select_box'>
<div class='title'>스펙을 추가해주세요</div>
<div>
<span class='cotent'>1</span>
<span class='cotent'>2</span>
<span class='cotent'>3</span>
<span class='cotent'>4</span>
</div>
</div>
이번에는 셀렉트 박스 안의 아무거나 누르고 클릭 이벤트를 확인합니다.
console.log(e.target)
<span class='cotent'>3</span>
이제 이게 위의 ref에 포함되어있는지 확인을 하면 원하는 기능이 구현됩니다.
selectEl.current.contains(e.target as Node) => true
(as Node는 e.target의 타입 오류를 막기 위해 추가해줬습니다.)