그럼에도 불구하고

👨‍💻

지역 검색 구현하기 본문

JavaScript/Function implementation

지역 검색 구현하기

zenghyun 2022. 12. 24. 01:49

오늘은 지역 검색을 할 수 있는 code를 만들어보자

 

 

 

 

조건 

  • 지역명의 첫 번째 글자만 받아서 검색한다. (한글, 영어)
  • 검색된 지역명과 data에 있는 지역명이 일치하는 지역만 보여준다.
  • 일치하지 않는 지역은 보여주지 않는다. ( display: none; 속성 이용 ) 

 

 

[ searchName.html ]

 

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>지역 검색</title>
  <link rel="stylesheet" href="style.css"/>
  <script src="main.js" defer></script>
</head>
<body>
<header>
  <label>지역명의 첫번째 글자를 입력해주세요.<input id="search-word-input" maxlength="1" type="text" oninput="numberMaxLength(this);"></label>
</header>
<div id="prefecture-list">
  <button data-name="속초" data-phonetic="sokcho">속초</button>
  <button data-name="부산" data-phonetic="busan">부산</button>
  <button data-name="포항" data-phonetic="pohang">포항</button>
  <button data-name="상주" data-phonetic="sangju">상주</button>
  <button data-name="서울" data-phonetic="seoul">서울</button>
  <button data-name="제주" data-phonetic="jeju">제주</button>
  <button data-name="김해" data-phonetic="kimhae">김해</button>
  <button data-name="대구" data-phonetic="daegu">대구</button>
  <button data-name="울산" data-phonetic="ulsan">울산</button>
  <button data-name="창원" data-phonetic="changwon">창원</button>
  <button data-name="마산" data-phonetic="masan">마산</button>
  <button data-name="인천" data-phonetic="incheon">인천</button>
  <button data-name="평택" data-phonetic="pyeongtaek">평택</button>
  <button data-name="의정부" data-phonetic="uijeongbu">의정부</button>
  <button data-name="고양" data-phonetic="goyang">고양</button>
  <button data-name="성남" data-phonetic="seongnam">성남</button>
  <button data-name="용인" data-phonetic="yongin">용인</button>
  <button data-name="부천" data-phonetic="bucheon">부천</button>
  <button data-name="안산" data-phonetic="ansan">안산</button>
  <button data-name="남양주" data-phonetic="namyangju">남양주</button>
  <button data-name="시흥" data-phonetic="siheong">시흥</button>
  <button data-name="파주" data-phonetic="paju">파주</button>
  <button data-name="김포" data-phonetic="kimpo">김포</button>
  <button data-name="광명" data-phonetic="kwangmyeong">광명</button>
  <button data-name="군포" data-phonetic="gunpo">군포</button>
  <button data-name="이천" data-phonetic="icheon">이천</button>
  <button data-name="하남" data-phonetic="hanam">하남</button>
  <button data-name="과천" data-phonetic="gwacheon">과천</button>
  <button data-name="전주" data-phonetic="jeonju">전주</button>
  <button data-name="군산" data-phonetic="gunsan">군산</button>
  <button data-name="목포" data-phonetic="mokpo">목포</button>
  <button data-name="나주" data-phonetic="naju">나주</button>
  <button data-name="광양" data-phonetic="gwangyang">광양</button>
  <button data-name="춘천" data-phonetic="chuncheon">춘천</button>
  <button data-name="원주" data-phonetic="wonju">원주</button>
  <button data-name="사천" data-phonetic="sacheon">사천</button>
  <button data-name="광주" data-phonetic="gwangju">광주</button>
  <button data-name="구리" data-phonetic="guri">구리</button>
  <button data-name="삼척" data-phonetic="samcheok">삼척</button>
  <button data-name="당진" data-phonetic="dangjin">당진</button>
  <button data-name="공주" data-phonetic="gonju">공주</button>
  <button data-name="천안" data-phonetic="cheonan">천안</button>
  <button data-name="부천" data-phonetic="bucheon">부천</button>
  <button data-name="수원" data-phonetic="suwon">수원</button>
  <button data-name="세종" data-phonetic="sejong">세종</button>
  <button data-name="대전" data-phonetic="daejeon">대전</button>
  <button data-name="충주" data-phonetic="chungju">충주</button>
</div>
</body>
</html>

 

 

[ search.js ]

 

const numberMaxLength = function (e) {
  const MAX_LENGTH = 1;
  if(e.value.length > MAX_LENGTH){
    e.value = e.value.slice(0, MAX_LENGTH);
  }
};

const searchWordText = document.querySelector('#search-word-input');

const prefectureList = document.querySelectorAll('#prefecture-list button');

searchWordText.addEventListener('keyup', () =>{

  const searchWord = searchWordText.value;

    prefectureList.forEach( (element) => {
      
      if( !searchWord || searchWord == ''){
        element.classList.remove('hide');
        return;
      }

      const prefectureName = element.dataset.name;

      const phonetic = element.dataset.phonetic;

      if( prefectureName.charAt(0) === searchWord.charAt(0) ||
          phonetic.charAt(0) === searchWord.charAt(0)){
            element.classList.remove('hide');
          } else {
            element.classList.add('hide');
          }

    });
  });

 

 

[ style.css ] 

 

* {
  margin: 0;
  padding: 0;
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
  tap-highlight-color: rgba(0, 0, 0, 0);
}


button {
  display: block;
}

label {
  display: block;
}

body {
  background-color: #f7f7f7;
}

button {
  text-decoration: none;
  color: black;
  background-color: #f5f4e8;
  text-align: center;
  border: none;
  border-radius: 4px;
  display: inline-block;
  height: 72px;
  line-height: 72px;
  padding: 0 32px;
  font-size: 2rem;
  cursor: pointer;
  transition: background-color 0.2s;
}

button:hover {
  background-color: #27bfb3;
}

button:active {
  background-color: #1d8e82;
}

header {
  padding: 20px;
  position: sticky;
  top: 0;
  background-color: #cd1511;
  text-align: center;
  color: white;
  font-size: 22px;
  margin-bottom: 10px;
  box-shadow: black 0 0 5px;
}

header #search-word-input {
  width: 60px;
  height: 30px;
  font-size: 30px;
}

#prefecture-list {
  display: grid;
  height: 100%;
  gap: 5px;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  grid-auto-rows: 72px;
  align-content: center;
  padding: 20px;
  overflow-y: scroll;
}

#prefecture-list button.hide {
  display: none;
}

 

 

결과

 

See the Pen Untitled by zenghyun (@zenghyun) on CodePen.

 

 

 

Review

 

<header>
  <label>지역명의 첫번째 글자를 입력해주세요.<input id="search-word-input" maxlength="1" type="text" oninput="numberMaxLength(this);"></label>
</header>

 

처음에 이 부분에서 애를 많이 먹었다. oninput을 사용하지 않고 maxlength = "1"로 지정하면 text box에 한 글자까지만 써질 줄 알았다. 

 

영어의 경우 이상 없이 잘 구현이 됐지만, 한글의 경우 두 글자가 써졌다. 

정확하게 말하자면 두 글자가 써지고 spacebar나 다른 곳을 클릭하면 한 글자로 바뀌기는 했다. 

 

검색 결과는 잘 나왔지만 영 찜찜했다.

그리고 가장 큰 문제점을 찾았는데 예를 들어 리스트에 있는 대전대구의 경우 

'대'를 검색하면 '대전''대구'가 잘 나왔는데 여기서 '대전'을 쓰면 '대구'까지 같이 나왔다.

 


※ 원인

 

 js에서 한 글자를 비교해서 일치하는 지역을 출력하는데, '대'까지 치면 '대전''대구'가 나오지만

maxlength의 한글 인식 문제때문에 '대전' 까지 입력이 가능하여  UI상으로는 '대전'까지 입력되어 보임

 

이때, 일치하는 지역을 출력하는 기능은 '대'만 입력했다고 인식하여 '대전'과 '대구'를 모두 보여줌  

 

 


 

 

javascript 상으로는 검색 결과를 잘 가져오지만 UI로 봤을 때는 굉장히 미흡해 보였다. 

그래서 왜 maxlength를 1로 지정해도 한글의 경우 2글자가 써지는지 궁금해서 찾아봤다. 

 

알고 보니 '자바스크립트의 유니코드'상에서 한글은 2Byte, 영어는 1Byte로 표현하기 때문이었다. 

그렇기에 한글의 경우 maxlength 설정과 함께 다른 처리도 해야 했다. 

 


[ 시행착오 ]

 

처음에는 javascript의 

searchWordText.addEventListener('keyup', () =>{ 
 // 생략
});

searchWordText'keyup' 이벤트가 발생할 때마다 내가 입력한 값의 length를 받아와서 최대 글자수와 비교하는 조건문을 만들었다.  

 

 

그 후에 이런 식으로 기존 searchWordText의 값을 바꾸려고 했으나 이벤트 함수 바깥에 선언된 전역 변수의 값을 가져올 수 없었다. ( 내부 함수에서 전역 변수의 값을 가져올 수 없기 때문 )

 

const searchWordText = document.querySelector('#search-word-input'); 

searchWordText.addEventListener('keyup', () =>{ 
 // 생략

if ( ) {
// 조건문에 해당하면 input 태그의 text 박스의 값을 바꿈
 searchWordText.innerHTML = 한 글자로 바꾼 값
}

});

 

 

자세한 내용은 scope에 대해 정리한 게시글을 참고하자.

 

https://despiteallthat.tistory.com/64

 

[Javascript] 스코프(scope)란?

오늘은 스코프(scope)에 대해 알아보자 [ 스코프(scope) ] 스코프(유효범위)는 자바스크립트를 포함한 모든 프로그래밍 언어의 기본적이며 중요한 개념이다. 하지만, 자바스크립트의 스코프는 다른

despiteallthat.tistory.com

 

 

 

그래서 <input> 태그의 여러 가지 속성을 검색해보다 oninput 이벤트를 알게 되었다. 

 

 


[ oninput ]

 

oninput 이벤트는 input 태그 안의 값들이 변경될 때마다 이벤트가 발생한다. 

 

즉, 내가 키보드를 누르는 순간마다 이벤트를 발생시키는 것이다. 

 

이 이벤트를 이용해서 현재 input 태그의 입력 값의 길이와 내가 지정한 최대 글자수를 비교하여 

최대 글자수를 넘어가는 순간 slice() 메서드를 사용하여 한 글자만 출력하게 만들었다. 

 

const numberMaxLength = function (e) {
  const MAX_LENGTH = 1;
  if(e.value.length > MAX_LENGTH){
    e.value = e.value.slice(0, MAX_LENGTH);
  }
};

 

 

결과적으로 아쉬운 부분을 해결해서 기분이 좋았다. 

 

다음에는 더 다양한 기능을 갖춘 검색 code를 구현해야겠다. 

 

 

ref: https://mygumi.tistory.com/398

      https://velog.io/@brgndy/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-input%ED%83%9C%EA%B7%B8%EC%9D%98-oninput-%EC%9D%B4%EB%B2%A4%ED%8A%B8-onChange-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%B0%A8%EC%9D%B4%EC%A0%90

'JavaScript > Function implementation' 카테고리의 다른 글

숫자 반환하기  (0) 2022.12.29
정규 표현식으로 특정 문자 검색하기  (1) 2022.12.28
제곱 함수 구하기  (0) 2022.12.19
day / night mode ver_2  (0) 2022.12.16
day / night mode 구현하기  (1) 2022.12.15
Comments