36. (JavaScript) 종합 실습 : 한글 검색 앱 만들기

박은서's avatar
Jan 12, 2026
36. (JavaScript) 종합 실습 : 한글 검색 앱 만들기

1. 문제

💡
인풋태그에 아무것도 넣지 않고 검색하고 전체 검색
인풋태그에 갔을 넣고 검색하면 name, description으로 검색하기
초기화는 화면 전체 비우기
notion image
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>종합 실습</title> <style> body { font-family: Arial, sans-serif; max-width: 900px; margin: 50px auto; padding: 20px; background: #fafafa; } h1 { text-align: center; color: #333; } .search-box { text-align: center; padding: 30px; background: white; border-radius: 10px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); } input { padding: 12px; width: 300px; font-size: 16px; border: 2px solid #ddd; border-radius: 5px; } button { padding: 12px 25px; margin: 5px; cursor: pointer; background: #2196f3; color: white; border: none; border-radius: 5px; font-size: 16px; } button:hover { background: #0b7dda; } button:disabled { background: #ccc; cursor: not-allowed; } .photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 20px; margin-top: 20px; } .photo-card { background: white; border-radius: 10px; overflow: hidden; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); transition: transform 0.2s; } .photo-card:hover { transform: translateY(-5px); box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); } .photo-card img { width: 100%; height: 200px; object-fit: cover; } .photo-card .info { padding: 15px; } .photo-card .title { font-weight: bold; margin-bottom: 5px; color: #333; } .loading { text-align: center; padding: 40px; font-size: 18px; color: #666; } .error { padding: 20px; background: #ffebee; color: #c62828; border-radius: 5px; text-align: center; } .empty { text-align: center; padding: 40px; color: #999; } </style> </head> <body> <h1>🎨 종합 실습: 한글 검색 앱</h1> <div class="search-box"> <input type="text" id="searchInput" placeholder="검색어를 입력하세요 (예: 사과, 딸기, 과일)" /> <button onclick="searchItems()">검색</button> <button onclick="clearResults()">초기화</button> </div> <div id="resultContainer"></div> <script> // 1. DOM에서 요소 찾기 const searchInput = document.querySelector("#searchInput"); const resultContainer = document.querySelector("#resultContainer"); // 한글 데이터 const items = [ { id: 1, name: "사과", category: "과일", description: "빨간색 과일입니다", }, { id: 2, name: "딸기", category: "과일", description: "달콤한 빨간 과일입니다", }, { id: 3, name: "바나나", category: "과일", description: "노란색 과일입니다", }, { id: 4, name: "오렌지", category: "과일", description: "주황색 과일입니다", }, { id: 5, name: "포도", category: "과일", description: "보라색 과일입니다", }, { id: 6, name: "수박", category: "과일", description: "여름 과일입니다", }, { id: 7, name: "당근", category: "채소", description: "주황색 채소입니다", }, { id: 8, name: "토마토", category: "채소", description: "빨간색 채소입니다", }, { id: 9, name: "오이", category: "채소", description: "초록색 채소입니다", }, { id: 10, name: "양파", category: "채소", description: "노란색 채소입니다", }, { id: 11, name: "고구마", category: "채소", description: "주황색 채소입니다", }, { id: 12, name: "배추", category: "채소", description: "초록색 채소입니다", }, ]; // 검색 function searchItems() {} // 초기화 function clearResults() {} // 페이지 로드 시 전체 데이터 표시 window.onload = () => {}; </script> </body> </html>

2. 풀이

1️⃣ 코드

1)

<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>종합 실습</title> <style> body { font-family: Arial, sans-serif; max-width: 900px; margin: 50px auto; padding: 20px; background: #fafafa; } h1 { text-align: center; color: #333; } .search-box { text-align: center; padding: 30px; background: white; border-radius: 10px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); } input { padding: 12px; width: 300px; font-size: 16px; border: 2px solid #ddd; border-radius: 5px; } button { padding: 12px 25px; margin: 5px; cursor: pointer; background: #2196f3; color: white; border: none; border-radius: 5px; font-size: 16px; } button:hover { background: #0b7dda; } button:disabled { background: #ccc; cursor: not-allowed; } .photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 20px; margin-top: 20px; } .photo-card { background: white; border-radius: 10px; overflow: hidden; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); transition: transform 0.2s; } .photo-card:hover { transform: translateY(-5px); box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); } .photo-card img { width: 100%; height: 200px; object-fit: cover; } .photo-card .back { display: grid; justify-content: center; align-items: center; width: 100%; height: 200px; background: linear-gradient(135deg, rgb(167, 89, 255), rgb(60, 0, 128)); } .photo-card .name { color: white; font-size: 50px; font-weight: 700; } .photo-card .info { padding: 15px; } .photo-card .title { font-weight: bold; margin-bottom: 5px; color: #333; } .loading { text-align: center; padding: 40px; font-size: 18px; color: #666; } .error { padding: 20px; background: #ffebee; color: #c62828; border-radius: 5px; text-align: center; } .empty { text-align: center; padding: 40px; color: #999; } </style> </head> <body> <h1>🎨 종합 실습: 한글 검색 앱</h1> <div class="search-box"> <input type="text" id="searchInput" placeholder="검색어를 입력하세요 (예: 사과, 딸기, 과일)" /> <button onclick="searchItems()">검색</button> <button onclick="clearResults()">초기화</button> </div> <div class="photo-grid" id="resultContainer"></div> <script> // 1. DOM에서 요소 찾기 const searchInput = document.querySelector("#searchInput"); const resultContainer = document.querySelector("#resultContainer"); // 한글 데이터 const items = [ { id: 1, name: "사과", category: "과일", description: "빨간색 과일입니다", }, { id: 2, name: "딸기", category: "과일", description: "달콤한 빨간 과일입니다", }, { id: 3, name: "바나나", category: "과일", description: "노란색 과일입니다", }, { id: 4, name: "오렌지", category: "과일", description: "주황색 과일입니다", }, { id: 5, name: "포도", category: "과일", description: "보라색 과일입니다", }, { id: 6, name: "수박", category: "과일", description: "여름 과일입니다", }, { id: 7, name: "당근", category: "채소", description: "주황색 채소입니다", }, { id: 8, name: "토마토", category: "채소", description: "빨간색 채소입니다", }, { id: 9, name: "오이", category: "채소", description: "초록색 채소입니다", }, { id: 10, name: "양파", category: "채소", description: "노란색 채소입니다", }, { id: 11, name: "고구마", category: "채소", description: "주황색 채소입니다", }, { id: 12, name: "배추", category: "채소", description: "초록색 채소입니다", }, ]; // 검색 function searchItems() { let searchItem = items.filter( (i) => i.name.includes(searchInput.value) || i.category.includes(searchInput.value) || i.description.includes(searchInput.value) ); resultContainer.innerHTML = ""; searchItem.forEach((i) => { let photoCard = document.createElement("div"); photoCard.setAttribute("class", "photo-card"); let photoBack = document.createElement("div"); photoBack.setAttribute("class", "back"); photoCard.appendChild(photoBack); let photoName = document.createElement("div"); photoName.innerHTML = i.name; photoName.setAttribute("class", "name"); photoBack.appendChild(photoName); let photoInfo = document.createElement("div"); photoInfo.setAttribute("class", "info"); photoCard.appendChild(photoInfo); let photoTitle = document.createElement("div"); photoTitle.innerHTML = i.name; photoTitle.setAttribute("class", "title"); photoInfo.appendChild(photoTitle); let photoCate = document.createElement("div"); photoCate.innerHTML = "카테고리: " + i.category; photoInfo.appendChild(photoCate); let photoDesc = document.createElement("div"); photoDesc.innerHTML = i.description; photoInfo.appendChild(photoDesc); resultContainer.append(photoCard); }); } // 초기화 function clearResults() { resultContainer.innerHTML = ""; } // 페이지 로드 시 전체 데이터 표시 window.onload = () => { items.forEach((i) => { let photoCard = document.createElement("div"); photoCard.setAttribute("class", "photo-card"); let photoBack = document.createElement("div"); photoBack.setAttribute("class", "back"); photoCard.appendChild(photoBack); let photoName = document.createElement("div"); photoName.innerHTML = i.name; photoName.setAttribute("class", "name"); photoBack.appendChild(photoName); let photoInfo = document.createElement("div"); photoInfo.setAttribute("class", "info"); photoCard.appendChild(photoInfo); let photoTitle = document.createElement("div"); photoTitle.innerHTML = i.name; photoTitle.setAttribute("class", "title"); photoInfo.appendChild(photoTitle); let photoCate = document.createElement("div"); photoCate.innerHTML = "카테고리: " + i.category; photoInfo.appendChild(photoCate); let photoDesc = document.createElement("div"); photoDesc.innerHTML = i.description; photoInfo.appendChild(photoDesc); resultContainer.append(photoCard); }); }; </script> </body> </html>

2)

<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>종합 실습</title> <style> body { font-family: Arial, sans-serif; max-width: 900px; margin: 50px auto; padding: 20px; background: #fafafa; } h1 { text-align: center; color: #333; } .search-box { text-align: center; padding: 30px; background: white; border-radius: 10px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); } input { padding: 12px; width: 300px; font-size: 16px; border: 2px solid #ddd; border-radius: 5px; } button { padding: 12px 25px; margin: 5px; cursor: pointer; background: #2196f3; color: white; border: none; border-radius: 5px; font-size: 16px; } button:hover { background: #0b7dda; } button:disabled { background: #ccc; cursor: not-allowed; } .photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 20px; margin-top: 20px; } .photo-card { background: white; border-radius: 10px; overflow: hidden; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); transition: transform 0.2s; } .photo-card:hover { transform: translateY(-5px); box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); } .photo-card img { width: 100%; height: 200px; object-fit: cover; } .photo-card .back { display: grid; justify-content: center; align-items: center; width: 100%; height: 200px; background: linear-gradient(135deg, rgb(167, 89, 255), rgb(60, 0, 128)); } .photo-card .name { color: white; font-size: 50px; font-weight: 700; } .photo-card .info { padding: 15px; } .photo-card .title { font-weight: bold; margin-bottom: 5px; color: #333; } .loading { text-align: center; padding: 40px; font-size: 18px; color: #666; } .error { padding: 20px; background: #ffebee; color: #c62828; border-radius: 5px; text-align: center; } .empty { text-align: center; padding: 40px; color: #999; } </style> </head> <body> <h1>🎨 종합 실습: 한글 검색 앱</h1> <div class="search-box"> <input type="text" id="searchInput" placeholder="검색어를 입력하세요 (예: 사과, 딸기, 과일)" /> <button onclick="searchItems()">검색</button> <button onclick="clearResults()">초기화</button> </div> <div class="photo-grid" id="resultContainer"></div> <script> // 1. DOM에서 요소 찾기 const searchInput = document.querySelector("#searchInput"); const resultContainer = document.querySelector("#resultContainer"); // 한글 데이터 const items = [ { id: 1, name: "사과", category: "과일", description: "빨간색 과일입니다", }, { id: 2, name: "딸기", category: "과일", description: "달콤한 빨간 과일입니다", }, { id: 3, name: "바나나", category: "과일", description: "노란색 과일입니다", }, { id: 4, name: "오렌지", category: "과일", description: "주황색 과일입니다", }, { id: 5, name: "포도", category: "과일", description: "보라색 과일입니다", }, { id: 6, name: "수박", category: "과일", description: "여름 과일입니다", }, { id: 7, name: "당근", category: "채소", description: "주황색 채소입니다", }, { id: 8, name: "토마토", category: "채소", description: "빨간색 채소입니다", }, { id: 9, name: "오이", category: "채소", description: "초록색 채소입니다", }, { id: 10, name: "양파", category: "채소", description: "노란색 채소입니다", }, { id: 11, name: "고구마", category: "채소", description: "주황색 채소입니다", }, { id: 12, name: "배추", category: "채소", description: "초록색 채소입니다", }, ]; // DOM function renderItem(i) { let item = document.createElement("div"); item.setAttribute("class", "photo-card"); item.innerHTML = ` <div class="back"> <div class="name">${i.name}</div> </div> <div class="info"> <div class="title">${i.name}</div> <div>카테고리: ${i.category}</div> <div>${i.description}</div> </div> `; return item; } // 검색 function searchItems() { let searchItem = items.filter( (i) => i.name.includes(searchInput.value) || i.category.includes(searchInput.value) || i.description.includes(searchInput.value) ); resultContainer.innerHTML = ""; searchItem.forEach((i) => { resultContainer.append(renderItem(i)); }); } // 초기화 function clearResults() { resultContainer.innerHTML = ""; } // 페이지 로드 시 전체 데이터 표시 window.onload = () => { items.forEach((i) => { resultContainer.append(renderItem(i)); }); }; </script> </body> </html>

2️⃣ 결과

1) 페이지 로드

notion image
notion image

2) 특정 단어 검색

notion image
notion image
notion image

3) 초기화

notion image
Share article