Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

JavaScript로 자동 완성(Autocomplete) 기능 구현하는 방법

검색창이나 입력 폼에서 사용자가 글자를 입력하면 관련된 추천 단어가 실시간으로 나타나는 자동 완성(Autocomplete) 기능은 웹사이트 사용성을 크게 높여주는 요소입니다. 이 글에서는 순수 JavaScript만을 사용하여 자동 완성 기능을 직접 구현하는 방법을 단계별로 살펴보겠습니다.

전체 예제 코드

아래는 HTML, CSS, JavaScript를 모두 포함한 완전한 자동 완성 구현 예제입니다.

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
    * {
        box-sizing: border-box;
    }
    body {
        margin: 10px;
        padding: 0px;
        font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
    }
    .autocomplete {
        position: relative;
        display: inline-block;
    }
    input {
        border: none;
        background-color: #f1f1f1;
        padding: 10px;
        font-size: 16px;
        border-radius: 4px;
    }
    input[type="text"] {
        background-color: #e1f6fc;
        width: 100%;
    }
    input[type="submit"] {
        background-color: DodgerBlue;
        color: #fff;
        cursor: pointer;
    }
    .autocomplete-items {
        position: absolute;
        border-bottom: none;
        border-top: none;
        z-index: 99;
        top: 100%;
        left: 0;
        right: 0;
    }
    .autocomplete-items div {
        padding: 10px;
        cursor: pointer;
        border: 1px solid #8e26d4;
        border-bottom: 1px solid #d4d4d4;
    }
    .autocomplete-items div:hover {
        background-color: #e9e9e9;
    }
    .autocomplete-active {
        background-color: rgb(30, 255, 169) !important;
        color: #ffffff;
    }
</style>
</head>
<body>
<h1>Autocomplete Example</h1>
<form autocomplete="off">
<div class="autocomplete" style="width:300px;">
<input id="searchField" type="text" name="animal" placeholder="Animals" />
</div>
<input type="submit" />
</form>
<script>
    function autocomplete(searchEle, arr) {
        var currentFocus;
        searchEle.addEventListener("input", function(e) {
            var divCreate,
            b,
            i,
            fieldVal = this.value;
            closeAllLists();
            if (!fieldVal) {
                return false;
            }
            currentFocus = -1;
            divCreate = document.createElement("DIV");
            divCreate.setAttribute("id", this.id + "autocomplete-list");
            divCreate.setAttribute("class", "autocomplete-items");
            this.parentNode.appendChild(divCreate);
            for (i = 0; i <arr.length; i++) {
                if ( arr[i].substr(0, fieldVal.length).toUpperCase() == fieldVal.toUpperCase() ) {
                    b = document.createElement("DIV");
                    b.innerHTML = "<strong>" + arr[i].substr(0, fieldVal.length) + "</strong>";
                    b.innerHTML += arr[i].substr(fieldVal.length);
                    b.innerHTML += "<input type='hidden' value='" + arr[i] + "'>";
                    b.addEventListener("click", function(e) {
                        searchEle.value = this.getElementsByTagName("input")[0].value;
                        closeAllLists();
                    });
                    divCreate.appendChild(b);
                }
            }
        });
        searchEle.addEventListener("keydown", function(e) {
            var autocompleteList = document.getElementById(
                this.id + "autocomplete-list"
            );
            if (autocompleteList)
                autocompleteList = autocompleteList.getElementsByTagName("div");
            if (e.keyCode == 40) {
                currentFocus++;
                addActive(autocompleteList);
            }
            else if (e.keyCode == 38) {
                //up
                currentFocus--;
                addActive(autocompleteList);
            }
            else if (e.keyCode == 13) {
                e.preventDefault();
                if (currentFocus > -1) {
                    if (autocompleteList) autocompleteList[currentFocus].click();
                }
            }
        });
        function addActive(autocompleteList) {
            if (!autocompleteList) return false;
                removeActive(autocompleteList);
            if (currentFocus >= autocompleteList.length) currentFocus = 0;
            if (currentFocus < 0) currentFocus = autocompleteList.length - 1;
            autocompleteList[currentFocus].classList.add("autocomplete-active");
        }
        function removeActive(autocompleteList) {
            for (var i = 0; i < autocompleteList.length; i++) {
                autocompleteList[i].classList.remove("autocomplete-active");
            }
        }
        function closeAllLists(elmnt) {
            var autocompleteList = document.getElementsByClassName(
                "autocomplete-items"
            );
            for (var i = 0; i < autocompleteList.length; i++) {
                if (elmnt != autocompleteList[i] && elmnt != searchEle) {
                    autocompleteList[i].parentNode.removeChild(autocompleteList[i]);
                }
            }
        }
        document.addEventListener("click", function(e) {
            closeAllLists(e.target);
        });
    }
    var animals = ["giraffe","tiger", "lion", "dog","cow","bull","cat","cheetah"];
    autocomplete(document.getElementById("searchField"), animals);
</script>
</body>
</html>

코드 작동 원리

1. 입력 이벤트 처리

검색 입력창에 input 이벤트 리스너를 등록하여 사용자가 글자를 입력할 때마다 동작합니다. 입력값이 비어 있으면 아무 작업도 하지 않고, 값이 있으면 기존의 추천 목록을 모두 닫은 후 새 목록을 생성합니다.

2. 일치하는 항목 필터링

배열에 담긴 각 단어의 앞부분이 현재 입력값과 일치하는지 대소문자를 구분하지 않고 비교합니다. 일치하는 항목은 DIV 요소로 생성되며, 입력된 부분은 굵게(<strong>) 표시되어 어떤 부분이 매칭되었는지 한눈에 알 수 있습니다.

3. 키보드 네비게이션 지원

keydown 이벤트를 통해 다음과 같은 키보드 조작을 지원합니다.

  • 아래 방향키(40): 추천 목록에서 다음 항목으로 이동
  • 위 방향키(38): 이전 항목으로 이동
  • Enter 키(13): 현재 선택된 항목을 확정하고 목록을 닫음

목록의 끝에 도달하면 처음으로 순환(loop)되도록 처리되어 있어 편리합니다.

4. 목록 열기 및 닫기

closeAllLists() 함수는 문서 전체에 클릭 이벤트를 등록해, 검색창 외부를 클릭하면 추천 목록이 자동으로 사라지도록 합니다. 덕분에 별도의 닫기 버튼 없이도 자연스러운 UX를 제공할 수 있습니다.

5. 데이터 배열 연결

마지막으로 동물 이름 배열(giraffe, tiger, lion, dog, cow, bull, cat, cheetah)을 정의하고, autocomplete() 함수에 검색 입력창과 함께 전달하여 기능을 활성화합니다.

실행 결과

위 코드를 실행하면 다음과 같은 화면이 출력됩니다.

JavaScript로 자동 완성(Autocomplete) 기능 구현하는 방법

동물 필드에 글자를 입력하면 아래와 같이 일치하는 추천 목록이 나타납니다.

JavaScript로 자동 완성(Autocomplete) 기능 구현하는 방법

마무리

이처럼 외부 라이브러리 없이 순수 JavaScript만으로도 자동 완성 기능을 충분히 구현할 수 있습니다. 실제 프로젝트에서는 서버 API에서 데이터를 가져오거나, 디바운싱(debouncing)을 적용해 불필요한 연산을 줄이는 방식으로 확장하면 더욱 완성도 높은 검색 경험을 제공할 수 있습니다.