자바스크립트 음식 탐색기 만들어보기

버건디·2022년 11월 8일
0
post-thumbnail

🔍 구현 할 내용들

🔍 HTML 코드


<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://kit.fontawesome.com/412379eca8.js" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="style.css">
    <script src="main.js"></script>
    <title>음식 검색기</title>
</head>

<body>
    <div class="container">

        <h1>음식 검색기</h1>

        <div class="flex">

            <form class="flex" id="form">
                <input type="text" id="search" placeholder="음식명이나 키워드를 입력하세요">
                <button class="search-button" type="submit"><i class="fa-solid fa-magnifying-glass"></i></button>
            </form>

            <button class="random-button" id="randomBtn"><i class="fa-solid fa-shuffle"></i></button>
        </div>

        <div id="result-heading">

        </div>
        <div id="meals" class="meals">
        </div>

        <div id="single-meal" class="sigleMealContainer">

        </div>



    </div>
</body>

</html>

🔍 CSS 코드

*{
    box-sizing: border-box;
}
body{
    background-color: rgb(89, 57, 57);
    margin: 0;
    color: white;
}

.container{
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;

}


.flex{
    display: flex;
    margin: 0;
}

.flex input{
    padding: 8px 10px;
    border-top-left-radius: 5px;
    border-bottom-left-radius: 5px;
    border: none;
    font-size: 14px;
}

.search-button{
    border-top-right-radius: 5px;
    border-bottom-right-radius: 5px;
}

.flex button{
    cursor: pointer;
    border: none;
    padding: 8px 10px;
    font-size: 14px;
}

.random-button{
    border-radius: 5px;
    margin-left: 5px;

}

.meals{
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 20px;
}

.meal{
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    position: relative;
}
.meal-info{
    position: absolute;
    width: 100%;
    height: 100%;
    cursor: pointer;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgba(0, 0, 0, 0.5);
    opacity: 0;
}

.meal-info:hover{
    animation-name: showMealInfo;
    animation-duration: 0.5s;
}

.sigleMealContainer{
    display: flex;
    justify-content: center;
    align-items: center;
}

.single-meal{
    display: flex;
    justify-content: center;
    flex-direction: column;
    align-items: center;
    width: 70%;
}

.single-meal h1{
    text-align: center;
}

.single-meal-info{
    border: 2px dashed #e09;
    width: 500px;
    margin: 20px;
}

.single-meal-info p{
    text-align: center;
   
}

.main h2{
    text-align: center;
}

.main ul{
    list-style: none;
    
}

.main ul li{
    display: inline-block;
    background-color: #fff;
    color: rgb(59, 50, 35);
    margin: 5px;
    border-radius: 5px;
    padding: 8px 10px;
    font-weight: bold;

}


img{
    width: 200px;
    height: 200px;
    cursor: pointer;
}




@keyframes showMealInfo{
    from{
        opacity: 0;
    }
    to{
        opacity: 1;
    }
}

🔍 주의 해야 할 점들

1. fetch 요청을 날릴때 https:// 를 붙여주지 않아서 계속 404 오류가 나왔었다.. 되게 사소한 실수였지만 시간을 좀 많이 소모했었다.

  fetch(`www.themealdb.com/api/json/v1/1/search.php?s=steak`)
    .then(res => res.json())
    .then(data => console.log(data));
});

2. innerHTML 내에서 map 함수를 사용해서 같은 형태의 내용들을 띄울때 백틱과 ${}을 잘 감싸주어야한다. 그리고 map 함수로 나타낸 div 요소들은 마지막에 join 메서드를 통해 합쳐주어야한다.

            meals.innerHTML = `${data.meals.map(meal => `<div class="meal">
            <img src="${meal.strMealThumb}" alt="${meal.strMeal}">
            <div class="meal-info">
                <h3>${meal.strMeal}</h3>
            </div>
        </div>`)}`

3. 반복문을 통해서 strIngredient1 부터 strIngredient20 까지 출력을 해줘야했는데 콘솔창에

for(let i= 1; i<= 20; i++){
          console.log(data.meals[0].strIngredient`${i}`);
        }

이렇게 입력하면 strIngredient 까지만 인식하고 뒤에 숫자를 인식하지 못했다.

        for(let i= 1; i<= 20; i++){
          console.log(data.meals[0][`strIngredient${i}`]);
        }

이렇게 입력하니 잘 인식했다.

(객체에 대해서 더 공부를 해야할 것 같다)

4. CSS 에서 버튼의 크기가 맞지 않았다

상위 div 에서 margin 0 을 주니 해결됐다.

5. 음식을 검색한후 그 음식 사진을 클릭하면 그 음식에 대한 정보들이 출력 되어야 했다. 그러기 위해서는 클릭을 했을때 그 해당 div 안에서 "meal-info" 라는 클래스를 가진 요소를 가져와야했다.

if (item.classList.contains('meal-info'){...} 

처음에 if 문안에 이렇게 적었었는데, 이렇게 적으면 클래스명이 아예 없는 요소도 있기 때문에 검색은 되지만 cannnot define 오류가 발생했다.

if (item.classList) {
          return item.classList.contains('meal-info');
        } else{ return false};

일단 클래스명이 존재하는지 판단해주고 거기서 meal-info 클래스명을 갖고 있는 요소를 가져왔다.

🔍 Javascript 코드

document.addEventListener("DOMContentLoaded", () => {
 const form = document.getElementById("form");
 const search = document.getElementById("search");
 const resultHeading = document.getElementById("result-heading");
 const meals = document.getElementById("meals");
 const randomBtn = document.getElementById("randomBtn");
 const singleMeal = document.getElementById("single-meal");


 // 검색기능

 function showMeal(e) {
   e.preventDefault();

   if (search.value.trim() !== "") {
     resultHeading.innerHTML = `<h2>${search.value}의 검색 결과 : </h2>`;
     fetch(
       `https://www.themealdb.com/api/json/v1/1/search.php?s=${search.value}`
     )
       .then((res) => res.json())
       .then((data) => {
         if (data.meals === null) {
           resultHeading.innerHTML =
             "<p>검색 결과가 없습니다. 다시 시도해주세요!</p>";
         } else {
           meals.innerHTML = `${data.meals
             .map(
               (meal) => `<div class="meal">
           <img src="${meal.strMealThumb}" alt="${meal.strMeal}">
           <div class="meal-info" data-mealID ="${meal.idMeal}">
               <h3>${meal.strMeal}</h3>
           </div>
       </div>`
             )
             .join("")}`;
           console.log(data);
         }
       });
   } else {
     alert("키워드를 입력해주세요");
   }

   search.value = "";
 }


 //랜덤으로 음식 정보 띄어주기 

 function showRandomMeal() {
   resultHeading.innerHTML = "";
   meals.innerHTML = "";

   fetch(`https://www.themealdb.com/api/json/v1/1/random.php`)
     .then((res) => res.json())
     .then((data) => {
       let strIngredient = [];

       for (let i = 1; i <= 20; i++) {
         if (data.meals[0][`strIngredient${i}`] !== "") {
           strIngredient.push(
             `${data.meals[0][`strIngredient${i}`]} - ${
               data.meals[0][`strMeasure${i}`]
             }`
           );
         } else {
           break;
         }
       }

       console.log(strIngredient);

       const dataMeals = data.meals[0];

       makeMealDiv(dataMeals, strIngredient);
     });
 }

 // 음식 정보, 이미지 띄어주기 

 function makeMealDiv(dataMeals, strIngredient) {
   singleMeal.innerHTML = `<div class="single-meal">
               <h1>${dataMeals.strMeal}</h1>
               <img src="${dataMeals.strMealThumb}" alt="${dataMeals.strMeal}">
               <div class="single-meal-info">
                   <p${dataMeals.strCategory}</p>
                   <p>${dataMeals.strArea}</p>
               </div>
               <div class="main">
                   <p>${dataMeals.strInstructions}</p>
                   <h2>조리법</h2>
                   <ul>${strIngredient
                     .map((item) => `<li>${item}</li>`)
                     .join("")}</ul>

               </div>

           </div>`;
 }

 // 음식 id 가져오기 

 function getMealID(e) {
   
   const mealInfo = e.composedPath().find(item => {
       if (item.classList) {
         return item.classList.contains('meal-info');
       } else{ return false};
     });

     if(mealInfo){
       const mealID = mealInfo.getAttribute('data-mealID');
       showMealDetail(mealID);
     }
 }


 function showMealDetail(mealID){
   fetch(`https://www.themealdb.com/api/json/v1/1/lookup.php?i=${mealID}`).then(res => res.json()).then(data =>{

     let strIngredient = [];

     for (let i = 1; i <= 20; i++) {
       if (data.meals[0][`strIngredient${i}`] !== "") {
         strIngredient.push(
           `${data.meals[0][`strIngredient${i}`]} - ${
             data.meals[0][`strMeasure${i}`]
           }`
         );
       } else {
         break;
       }
     }

     const dataMeals = data.meals[0];

     makeMealDiv(dataMeals, strIngredient);


   })
 }

 form.addEventListener("submit", showMeal);
 randomBtn.addEventListener("click", showRandomMeal);
 meals.addEventListener("click", getMealID);
});

- 완성 화면

profile
https://brgndy.me/ 로 옮기는 중입니다 :)

0개의 댓글