요구사항
키보드와 마우스를 이용해서 추천 검색어를 선택할 수 있도록 합니다.
- esc를 누르면 추천 검색어 창이 닫여야 합니다.
- 키보드의 위, 아래 키를 누르면 추천 검색어 하이라이트가 옮겨지고 엔터를 누르면 하이라이트가 위치한 검색어가 입력창에 반영되어야 합니다.
- 마우스로 다른 곳을 클릭하여 input이 focus를 잃어버리는 경우 추천 검색어 창이 닫여야 합니다.
- 마우스로 추천 검색어를 누르면 커서가 위치한 검색어가 입력창에 반영되어야 합니다.
기본 HTML은 다음과 같습니다.
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <title>검색하기</title> <style> header { display: flex; width: 600px; flex-direction: column; justify-content: center; } .keywords { z-index: 1; background-color: white; display: none; position: absolute; top: 110px; width: 600px; border: 1px solid #ccc; border-radius: 5px; } .keywords li:hover, .keywords .selected { cursor: pointer; background-color: lightskyblue; color: white; } .keywords .active { background-color: lightskyblue; color: white; } .keywords ul { padding: 0; margin: 0; } .keywords li { list-style: none; padding-left: 10px; } table { margin-top: 10px; } </style> </head> <body> <header> <h1>검색하기</h1> <input class="keyword" autocomplete="off" /> </header> <div class="keywords"> </div> <div class="search-results"> <table border=1> <tr> <th width="120px" height="50px">가</th> <th width="120px" height="50px">나</th> <th width="120px" height="50px">다</th> <th width="120px" height="50px">라</th> <th width="120px" height="50px">마</th> </tr> </table> </div> <script> // .......... // </script> </body></html>
script의 전체 내용은 다음과 같습니다.
const getData = async () => { const response = await fetch("https://reqres.in/api/users?page=1") return response.json() } const keyword = document.querySelector(".keyword") const keywords = document.querySelector(".keywords") function closeKeywords() { keywords.style.display = "none" keywords.innerHTML = "" } keyword.addEventListener("keyup", async (e) => { const selectedKeyword = keywords.querySelector("li.selected") // li.selected 가 없는 경우에만 api에서 데이터를 가져옴 if(keyword.value.length > 2 && !selectedKeyword) { console.log("=== API 호출 ===") const list = (await getData()).data keywords.innerHTML = "" const $ul = document.createElement("ul") for(let person of list) { const $li = document.createElement("li") $li.textContent = `${person.first_name} ${person.last_name}` $ul.append($li) } keywords.append($ul) keywords.style.display = "block" } if(keyword.value.length === 0) { keywords.innerHTML = "" } // 요구사항 1 - esc를 누르면 추천 검색어 창이 닫여야 합니다. if(e.key === "Escape") { closeKeywords() } // console.log(e.key) // 요구사항 2 - 키보드의 위, 아래 키를 누르면 추천 검색어 하이라이트가 옮겨지고 엔터를 누르면 하이라이트가 위치한 검색어가 입력창에 반영되어야 합니다. const keywordsList = keywords.querySelectorAll("li") if((e.key === "ArrowUp" || e.key === "ArrowDown") && keywords.style.display === "block") { let target const initIndex = e.key === "ArrowUp" ? keywordsList.length - 1 : 0 const adjacentSibling = selectedKeyword && (e.key === "ArrowUp" ? selectedKeyword.previousElementSibling : selectedKeyword.nextElementSibling) if(adjacentSibling) { target = adjacentSibling } else { target = keywordsList.item(initIndex) } selectedKeyword && selectedKeyword.classList.remove("selected") target.classList.add("selected") keyword.value = target.textContent } }) document.addEventListener("click", e => { // 요구사항 3 - 마우스로 다른 곳을 클릭하여 input이 focus를 잃어버리는 경우 추천 검색어 창이 닫여야 합니다. const closestKeywords = e.target.closest(".keywords") // 부모 요소 중에 keywords 클래스를 가진 부모가 있는지 확인 if(!closestKeywords && keywords.style.display === "block") { closeKeywords() } }) keywords.addEventListener("click", e => { // 요구사항 4 - 마우스로 추천 검색어를 누르면 커서가 위치한 검색어가 입력창에 반영되어야 합니다. keyword.value = e.target.textContent })
요구사항 1 – esc를 누르면 추천 검색어 창이 닫여야 합니다.
추천어 검색창이 닫힌다는 것은
- 검색창이 보여지지 않음
- 검색창의 내용이 초기화됨
을 의미합니다. 닫힘 기능이 있는 함수를 먼저 만듭니다.
function closeKeywords() { keywords.style.display = "none" keywords.innerHTML = "" }
그 다음 검색어 입력창에 keyup
이벤트를 부여하고, 해당 키가 ESC
인 경우 추천어 검색창을 닫도록 합니다.
// 요구사항 1 - esc를 누르면 추천 검색어 창이 닫여야 합니다. if(e.key === "Escape") { closeKeywords() }
요구사항 2 – 키보드의 위, 아래 키를 누르면 추천 검색어 하이라이트가 옮겨지고 엔터를 누르면 하이라이트가 위치한 검색어가 입력창에 반영되어야 합니다.
키보드 위 키가 눌린 경우
- 현재 선택된 추천 검색어가 없는 경우 또는 선택된 추천 검색어가 첫번째(맨 위)에 위치한 경우 목록의 맨 마지막이 선택되도록 합니다.
- 그 외의 경우 현재 선택된 검색어의 바로 위(자매 요소)가 선택되도록 합니다.
키보드 아래 키가 눌린 경우
- 현재 선택된 추천 검색어가 없는 경우 또는 선택된 추천 검색어가 마지막에 위치한 경우 목록의 첫번째가 선택되도록 합니다.
- 그 외의 경우 현재 선택된 검색어의 바로 아래(자매 요소)가 선택되도록 합니다.
검색어 목록(<li>
)에 selected
클래스 유무 여부에 따라 선택 여부가 결정됩니다.
// 요구사항 2 - 키보드의 위, 아래 키를 누르면 추천 검색어 하이라이트가 옮겨지고 엔터를 누르면 하이라이트가 위치한 검색어가 입력창에 반영되어야 합니다. const keywordsList = keywords.querySelectorAll("li") if((e.key === "ArrowUp" || e.key === "ArrowDown") && keywords.style.display === "block") { let target const initIndex = e.key === "ArrowUp" ? keywordsList.length - 1 : 0 const adjacentSibling = selectedKeyword && (e.key === "ArrowUp" ? selectedKeyword.previousElementSibling : selectedKeyword.nextElementSibling) if(adjacentSibling) { target = adjacentSibling } else { target = keywordsList.item(initIndex) } selectedKeyword && selectedKeyword.classList.remove("selected") target.classList.add("selected") keyword.value = target.textContent }
요구사항 3 – 마우스로 다른 곳을 클릭하여 input이 focus를 잃어버리는 경우 추천 검색어 창이 닫여야 합니다.
document
에 마우스 이벤트를 부여해서 추천 검색어 창이 켜진 상태이고, 클릭된 부분이 추천 검색어 창이 아닌 경우 추천 검색어 창을 닫히게 합니다.
document.addEventListener("click", e => { // 요구사항 3 - 마우스로 다른 곳을 클릭하여 input이 focus를 잃어버리는 경우 추천 검색어 창이 닫여야 합니다. const closestKeywords = e.target.closest(".keywords") // 부모 요소 중에 keywords 클래스를 가진 부모가 있는지 확인 if(!closestKeywords && keywords.style.display === "block") { closeKeywords() } })
요구사항 4 – 마우스로 추천 검색어를 누르면 커서가 위치한 검색어가 입력창에 반영되어야 합니다.
키워드 목록 창에 마우스 클릭 이벤트를 부여하고, 목록을 클릭하면 클릭된 목록의 textContent
를 입력창에 반영하도록 합니다.
keywords.addEventListener("click", e => { // 요구사항 4 - 마우스로 추천 검색어를 누르면 커서가 위치한 검색어가 입력창에 반영되어야 합니다. keyword.value = e.target.textContent })
0개의 댓글