📚 필수 과제
1. 점심 메뉴 추천 페이지 레이아웃 만들기
1️⃣ 목적
- 웹 페이지의 기본 레이아웃을 구성하는 구조를 이해한다.
- 시맨틱 태그와 <form> 태그의 구조를 익힌다.
2️⃣ 구현 내용
- 점심 메뉴 추천을 위한 입력 form과 결과 영역이 있는 페이지를 구성해보세요.
- 맵기 정도, 예산, 음식 종류, 오늘의 기분
<main class="container">
<h1>🍱 점심 메뉴 추천기</h1>
<form id="lunch-form">
<div class="field">
<h3>🌶️ 맵기 정도</h3>
<select id="spicy" name="spicy" class="full">
<option value="" disabled selected>===맵기를 선택하세요===</option>
<option value="매운거 싫어요">매운거 싫어요</option>
<option value="살짝 매운 맛">살짝 매운 맛</option>
<option value="기본 매운 맛">기본 매운 맛</option>
<option value="조금 매운 맛">조금 매운 맛</option>
<option value="화끈한 매운 맛">화끈한 매운 맛</option>
<option value="아주 매운 맛">아주 매운 맛</option>
</select>
</div>
<div class="field">
<h3>💰 예산</h3>
<input type="range" id="budget" name="budget"
min="5000" max="20000" step="1000" value="5000" class="full">
<output id="budget-out">5,000원</output>
</div>
<div class="field">
<h3>🍗 음식 종류</h3>
<div class="radio-group" >
<label class="radio-item">
<input type="radio" id="korea" name="food-category" value="한식" required>
🍚 한식</label>
<label class="radio-item">
<input type="radio" id="japan" name="food-category" value="일식">
🍙 일식</label>
<label class="radio-item">
<input type="radio" id="china" name="food-category" value="중식">
🥟 중식</label>
<label class="radio-item">
<input type="radio" id="western" name="food-category" value="양식">
🍕 양식</label>
</div>
</div>
<div class="field">
<h3>🙂 오늘의 기분은?</h3>
<input type="text" id="mood" placeholder="오늘의 기분을 입력하세요" class="full" >
</div>
<button type="submit" id="submit-btn">추천받기</button>
</form>
</main>
점심 메뉴 추천을 하는 Form을 'lunch-form'으로 명명
이전 과제에서 사용했던 화면 레이아웃은 container 문구를 활용함으로서 화면을 깔끔하게 구성하고자 함
총 4개의 input type을 활용하여 구성하였으며, 입력된 결과값은 후술할 console.log 기능으로 개발자 도구에서 활용할 수 있도록 함
2. 맵기 정도 선택 기능
1️⃣ 목적
- <select> 태그 사용법을 익힌다.
- 사용자의 선택값을 JS에서 읽는 방법을 이해한다.
2️⃣ 구현 내용
- 맵기 정도를 <select> 태그로 선택할 수 있도록 구성해보세요.
<div class="field">
<h3>🌶️ 맵기 정도</h3>
<select id="spicy" name="spicy" class="full">
<option value="" disabled selected>===맵기를 선택하세요===</option>
<option value="매운거 싫어요">매운거 싫어요</option>
<option value="살짝 매운 맛">살짝 매운 맛</option>
<option value="기본 매운 맛">기본 매운 맛</option>
<option value="조금 매운 맛">조금 매운 맛</option>
<option value="화끈한 매운 맛">화끈한 매운 맛</option>
<option value="아주 매운 맛">아주 매운 맛</option>
</select>
</div>
화면 결과 예시에서 구성한 것처럼 option(드롭다운 형태)의 select 태그를 사용하도록 코드 진행
선택한 값에 따라 입력된 결과값을 그대로 받아들일 수 있게 하였음
기본적으로 구성된 select 태그 자체의 크기가 작은 상태로 CSS 구문을 활용하여 구성한 container 안에서 꽉 차게 화면을 구성함
3. 예산 입력 기능
1️⃣ 목적
- <input type="range">의 사용법과 시각적 피드백 구현을 익힌다.
2️⃣ 구현 내용
- 예산을 range로 조절할 수 있도록 input 필드를 구성하고, 현재 값도 표시해보세요.
/* HTML 코드 */
<div class="field">
<h3>💰 예산</h3>
<input type="range" id="budget" name="budget"
min="5000" max="20000" step="1000" value="5000" class="full">
<output id="budget-out">5,000원</output>
</div>
/* Javascript 코드 */
const budget = document.getElementById('budget');
const budgetOut = document.getElementById('budget-out');
const toKRW = v => Number(v).toLocaleString('ko-KR') + ' 원';
budget.addEventListener('input', () => budgetOut.value = toKRW(budget.value));
const form = document.getElementById('lunch-form');
기본 초기값은 5000원부터 시작하도록 예산을 설정, 최댓값은 2만원 range 범위를 조절함에 따라 1000원 단위로 조절될 수 있도록 input type을 설정하였음
output id를 통해 range 아래에 기본적으로 노출될 값을 입력하였고,
입력도니 금액을 한국 돈 형식으로 변환하는 함수를 인용하였고 그 상수를 toKRW로 선언하여 값을 저장하였음
budget.addEventListener('input', () => budgetOut.value = toKRW(budget.value));
위의 선언을 통해 슬라이더가 움직이는 상황이 생겼을 때 output 즉, 실시간으로 변경되는 현재 값을 노출시키도록 구성함
4. 음식 종류 선택 기능
1️⃣ 목적
- <input type="radio">의 활용법을 익힌다.
- 동일 그룹 내 라디오 버튼 처리 방식과 validation을 이해한다.
2️⃣ 구현 내용
- 원하는 음식 종류를 라디오 버튼으로 선택할 수 있도록 구성해보세요.
<div class="field">
<h3>🍗 음식 종류</h3>
<div class="radio-group" >
<label class="radio-item">
<input type="radio" id="korea" name="food-category" value="한식" required>
🍚 한식</label>
<label class="radio-item">
<input type="radio" id="japan" name="food-category" value="일식">
🍙 일식</label>
<label class="radio-item">
<input type="radio" id="china" name="food-category" value="중식">
🥟 중식</label>
<label class="radio-item">
<input type="radio" id="western" name="food-category" value="양식">
🍕 양식</label>
</div>
</div>
결과 예시에 맞춰 radio 타입을 선언, 체크박스와 유사한 형태로의 화면 구성을 만들게 되었음
진행과정 간 트러블슈팅③ 이슈 발생으로 인하여 label class 선언으로 한줄로 깔끔하게 구성하고 클릭 호환성을 증가시킨 형태로 수정 및 보완 하였음
5. 오늘의 기분 입력 기능
1️⃣ 목적
- <input type="text">의 활용법을 익힌다.
2️⃣ 구현 내용
- 오늘의 기분을 텍스트로 입력할 수 있도록 구성해보세요.
- 힌트 텍스트, 자리채움 문구인 placeholder를 이용해보세요.
<div class="field">
<h3>🙂 오늘의 기분은?</h3>
<input type="text" id="mood" placeholder="오늘의 기분을 입력하세요" class="full" >
</div>
할일 목록 과제를 수행하면서 사용했던 input type = text, textarea 기능을 재활용 하여 구성하였고,
입력 전 상태에 노출할 문구를 placeholder로 구성하여 화면을 나타냄
6. 추천받기 결과 확인
1️⃣ 목적
- 사용자의 입력을 바탕으로 메뉴 추천 API를 호출하고 결과를 콘솔에 출력해보며, 디버깅 방법을 경험합니다.
2️⃣ 구현 내용
- 추천받기 버튼 클릭시 alert창을 띄웁니다. (문구는 자유롭게 기입하세요.)
- 그 후 맵기 정도, 예산, 음식 종류, 오늘의 기분의 내용을 console 창에 로깅하여 입력한 결과를 확인 해봅니다.
/* HTML 코드 */
<button type="submit" id="submit-btn">추천받기</button>
// Javascript 코드
const form = document.getElementById('lunch-form');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const spicy = document.getElementById('spicy').value;
const budget = document.getElementById('budget').value;
//궁금한 점, formdata는 음식 종류의 입력값만을 받기위해서 사용한 개념인가?
//아니면 실질적으로 js에서 값을 두번씩 불러오고 있지는 않은가?
const data = new FormData(form);
const category = data.get('food-category');
const mood = document.getElementById('mood').value.trim();
// 입력된 값을 콘솔창으로 기록시키고, 입력된 상수값인 맵기,예산 등의 형태를 구현
console.log('맵기: ', spicy);
console.log('예산: ', budget);
console.log('음식 종류: ', category);
console.log('기분: ', mood);
alert('입력이 접수되었습니다! (개발자도구 콘솔에서 값을 확인하세요)');
버튼 타입 선언을 통해 입력되었을 때 작동하는 기능을 수행하고자 설정하였고
form에 입력했던 각 항목들에 따른 값을 const(상수) 값으로 저장함으로서 입력값을 받아들이고 저장할 수 있도록 구성하였음.
맵기 (spicy) , 예산(budget), 음식 종류(category), 기분(mood) 값을 console.log 기능을 통해 개발자 도구 콘솔에 제출된 값을 아카이빙 하는 형태로 구성하였음
❤️🔥 도전 과제
1. mock API 호출
1️⃣ 목적
- fetch를 이용해 외부 API 호출을 구현한다.
- 받은 데이터를 가공하여 원하는 값만 추출해본다.
2️⃣ 구현 내용
- mock api 인 https://6863bafe88359a373e960f61.mockapi.io**/sparta/web**/**:endpoint 에**서 받은 응답 중 가장 최근 생성된 name 값을 alert로 띄워보세요.
async function fetchLatestName() {
const res = await fetch("https://6863bafe88359a373e960f61.mockapi.io/sparta/web/lunch");
const list = await res.json();
// 배열의 마지막 요소를 '가장 최근'이라고 가정
for (let i = list.length - 1; i >= 0; i--) {
if (list[i].name) {
return list[i].name;
}
}
// 끝까지 없으면
return "(name 없음)";
}
try {
const latestName = await fetchLatestName();
alert(`가장 최근 생성된 name: ${latestName}`);
} catch (err) {
console.error(err);
alert("API 호출 실패");
예제에서 공유한 콘솔 값을 기반으로 가장 최근에 입력된 값부터 name 값을 찾기 위해 반복문을 설정
배열의 끝부분부터 name 값을 찾은 이후 알럿 창을 통해 과정이 진행되게끔 구성하였고, try-catch 문을 통하여 값을 읽는 예외처리에 대해서도 실행될 수 있는 코드를 구성함
2. 입력값 유효성 검증
1️⃣ 목적
- 사용자의 입력 상태를 조건문으로 검증하는 로직을 익힌다.
2️⃣ 구현 내용
- 음식 종류가 선택되지 않았을 때 alert를 띄우고, API를 호출하지 않도록 막아보세요.
- 오늘의 기분이 입력되지 않았을 때도 같은 방식으로 alert를 띄워보세요.
입력값 유효성 검증을 하는 과정은 크게 두가지로 확인하였음
if (!category) { alert('음식 종류를 선택하세요.'); return;}
if (!mood) { alert('오늘의 기분을 입력하세요.'); return;}
1. 입력된 select , input 태그 내에 required 선언을 통하여 submit 제출 버튼 클릭 처리가 되기 전 알럿 형태의 문구를 나타나게 할 수 있었음
2. Js 구간에서의 조건문을 설정하여 특정 값이 선택되거나 입력되지 않은 경우 프로세스가 처리되지 않도록 구성할 수 있었음
3. mock API 직접 생성 및 활용
1️⃣ 목적
- mockapi.io를 활용한 API 생성 실습
- RESTful API 구조와 응답 처리 로직 이해
2️⃣ 구현 내용
- 직접 mock API를 만들어서 데이터를 구성하고, 해당 API를 호출해보세요.
async function fetchRandomLunch() {
const res = await fetch("https://68b7baee73b3ec66cec55e50.mockapi.io/lunch");
const list = await res.json();
if (!Array.isArray(list) || list.length === 0) return "(데이터 없음)";
const randomIndex = Math.floor(Math.random() * list.length);
return list[randomIndex].name ?? "(name 없음)";
}
try {
const randomName = await fetchRandomLunch();
alert(`오늘의 랜덤 추천 메뉴: ${randomName}`);
} catch (err) {
console.error(err);
alert("API 호출 실패");
}
도전과제 1에서 주어졌던 mock api 주소값에 따른 임의의 값을 찾는 것처럼
개별로 생성한 api 호출 양식을 만들고 임의의 값을 부여하였음
개별로 생성한 api 링크는
json 형태의 값으로 배열값을 random한 참조값으로 받아들이게 하였고, 그 값을 try-catch 문을 통하여 예외처리 검증하는 과정을 진행 하였음
☠️ 트러블 슈팅
- 발생한 Issue ①
- 입력값의 유효성 검사를 하는 과정에서 기존 HTML 요소에 required 를 통해 유효성 검사를 진행하였음
- 이 과정에서 맵기 선택에서의 경고가 제대로 노출되지 않는 상황이 발생
- 입력값의 유효성 검사를 하는 과정에서 기존 HTML 요소에 required 를 통해 유효성 검사를 진행하였음
- 해결한 방법 / 찾아본 내용
- required로 검증을 하기 위해서는 입력된 값이 "유효하지 않은 경우" 에 한해 에러 메세지를 노출하는 것
- 이에 따라 option, select, input 등의 required의 value 값을 공백으로 부여하여 정상적인 검증과정으로 수정
- 또는, 도전 과제에서의 유효성 검사 방식과 동일하게 Javascript 의 조건문을 통한 검사로 알럿형태의 경고문을 노출 시킬 수 있음
- 도전과제의 조건을 충족시키기 위해 required 개념은 인지하고 있고, Js의 조건문 검증으로 대체하고자 함
- required로 검증을 하기 위해서는 입력된 값이 "유효하지 않은 경우" 에 한해 에러 메세지를 노출하는 것
- 발생한 Issue ②
- 도전 기능 API 호출과정에 대한 전반적인 이해도가 부족하고 절차가 이해되지 않음
- 해결한 방법 / 찾아본 내용
- GET / POST 형태를 통해 입력된 값 중 원하는 값을 추출하거나 끌어오는 과정들을 거칠 수 있도록 함
- 발생한 Issue ③
- 항목을 세로로 정렬하는 과정 및 여백을 설정하는 과정 중 input type = "radio" 로 구성된 음식 종류 구간의 레이아웃이 흐트러지는 현상이 발생
- 해결한 방법 / 찾아본 내용
- label class 선언을 통해 각 항목별 radio 내용을 묶는 과정을 진행하여 이슈를 해소함
'HTML&CSS > HTML&CSS 실습' 카테고리의 다른 글
| 점메추 API Ajax 호출 (0) | 2025.09.04 |
|---|---|
| 점심메뉴 추천기 API (0) | 2025.09.03 |
| 할 일 목록 만들기 (0) | 2025.09.02 |
| 프로필 페이지 제작 (0) | 2025.09.02 |