유데미에서 Brad Traversy의 20 Web Projects With Vanilla JavaScript
를 하나씩 직접 코딩해보면서 정리하기 위한 글이다.
데모 페이지
vanillawebprojects.com/projects/meal-finder/
코드 링크
github.com/rshak8912/20-Web-Projects
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css"/>
<link rel="stylesheet" href="style.css">
<title>Meal Finder</title>
</head>
<body>
<div class="container">
<h1>Meal Finder</h1>
<div class="flex">
<form id="submit" class="flex">
<input type="text" id="search" placeholder="Search for meals or keywords">
<button class="search-btn" type="submit">
<i class="fas fa-search"></i>
</button>
</form>
<button class="random-btn" id="random"><i class="fas fa-random"></i></button>
</div>
<div id="result-heading"></div>
<div id="meals" class="meals"></div>
<div id="single-meal"></div>
</div>
<script src="script.js"></script>
</body>
</html>
style.css
* {
box-sizing: border-box;
}
body {
background: #2d2013;
color: #fff;
font-family: Verdana, Geneva, Tahoma, sans-serif;
margin: 0;
}
.container {
margin: auto;
max-width: 800px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
}
.flex {
display: flex;
}
input, button {
border: 1px solid #dedede;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
font-size: 14px;
padding: 8px 10px;
margin: 0;
}
input[type='text'] {
width: 300px;
}
.search-btn {
cursor: pointer;
border-left: 0;
border-radius: 0 4px 4px 0;
}
.random-btn {
cursor: pointer;
margin-left: 10px;
}
.meals {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 20px;
margin-top: 20px;
}
.meal {
cursor: pointer;
position: relative;
height: 180px;
width: 180px;
text-align: center;
}
.meal img {
width: 100%;
height: 100%;
border: 4px #fff solid;
border-radius: 2px;
}
.meal-info {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: rgba(0, 0, 0, 0.7);
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.2s ease-in;
opacity: 0;
}
.meal:hover .meal-info {
opacity: 1;
}
.single-meal {
margin: 30px auto;
width: 70%;
}
.single-meal img {
width: 300px;
margin: 15px;
border: 4px #fff solid;
border-radius: 2px;
}
.single-meal-info {
margin: 20px;
padding: 10px;
border: 2px #e09850 dashed;
border-radius: 5px;
}
.single-meal p {
margin: 0;
letter-spacing: 0.5px;
line-height: 1.5;
}
.single-meal ul {
padding-left: 0;
list-style-type: none;
}
.single-meal ul li {
border: 1px solid #ededed;
border-radius: 5px;
background-color: #fff;
display: inline-block;
color: #2d2013;
font-size: 12px;
font-weight: bold;
padding: 5px;
margin: 0 5px 5px 0;
}
@media (max-width: 800px) {
.meals {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 700px) {
.meals {
grid-template-columns: repeat(2, 1fr);
}
.meal {
height: 200px;
width: 200px;
}
}
@media (max-width: 500px) {
input[type='text'] {
width: 100%;
}
.meals {
grid-template-columns: 1fr;
}
.meal {
height: 300px;
width: 300px;
}
}
script.js
const search = document.getElementById('search');
const submit = document.getElementById('submit');
const random = document.getElementById('random');
const mealsEl = document.getElementById('meals');
const resultHeading = document.getElementById('result-heading');
const single_mealEl = document.getElementById('single-meal');
const searchMeal = (e) => {
e.preventDefault();
single_mealEl.innerHTML = '';
const term = search.value;
if (term.trim()) {
fetch(`https://www.themealdb.com/api/json/v1/1/search.php?s=${term}`)
.then(res => res.json())
.then(data => {
console.log(data);
resultHeading.innerHTML = `<h2>Search results for '${term}':</h2>`;
if (data.meals === null) {
resultHeading.innerHTML = `<p>There are no search results. Try again!</p>`;
} else {
mealsEl.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('');
}
});
// Clear search text
search.value ='';
} else {
alert('Please enter a search term');
}
}
const getRandomMeal = () => {
// Clear meals and heading
mealsEl.innerHTML = '';
resultHeading.innerHTML = '';
fetch(`https://www.themealdb.com/api/json/v1/1/random.php`)
.then(res => res.json())
.then(data => {
const meal = data.meals[0];
addMealToDOM(meal);
});
}
function addMealToDOM(meal) {
const ingredients = [];
for (let i = 1; i <= 20; i++) {
if (meal[`strIngredient${i}`]) {
ingredients.push(
`${meal[`strIngredient${i}`]} - ${meal[`strMeasure${i}`]}`
);
} else {
break;
}
}
single_mealEl.innerHTML = `
<div class="single-meal">
<h1>${meal.strMeal}</h1>
<img src="${meal.strMealThumb}" alt="${meal.strMeal}" />
<div class="single-meal-info">
${meal.strCategory ? `<p>${meal.strCategory}</p>` : ''}
${meal.strArea ? `<p>${meal.strArea}</p>` : ''}
</div>
<div class="main">
<p>${meal.strInstructions}</p>
<h2>Ingredients</h2>
<ul>
${ingredients.map(ing => `<li>${ing}</li>`).join('')}
</ul>
</div>
</div>
`;
}
const getMealById = (mealId) => {
fetch(`https://www.themealdb.com/api/json/v1/1/lookup.php?i=${mealId}`)
.then(res => res.json())
.then(data => {
const meal = data.meals[0];
addMealToDOM(meal);
});
}
// Event Listeners
submit.addEventListener('submit', searchMeal);
random.addEventListener('click', getRandomMeal);
mealsEl.addEventListener('click', e => {
const mealInfo = e.path.find(item => {
if (item.classList) {
return item.classList.contains('meal-info');
} else {
return false;
}
});
if (mealInfo) {
const mealID = mealInfo.getAttribute('data-mealid');
getMealById(mealID);
}
});
강의를 통해 배운 점(생각, 내용 정리)
- fetch를 사용하여 외부 api를 받아오고 데이터 바인딩을 하는법을 익힐 수 있었음
- data- attribute에 대해 알게 되었음
- css grid에 대해 알게 되었고, 추후 심화 정리 예정
'HTML&CSS&Javascript' 카테고리의 다른 글
[Udemy]20 Web Projects With Vanilla JavaScript -Project#10 (0) | 2020.12.30 |
---|---|
[Udemy]20 Web Projects With Vanilla JavaScript -Project#9 (0) | 2020.12.29 |
[Udemy]20 Web Projects With Vanilla JavaScript -Project#7 (0) | 2020.12.11 |
[Udemy]20 Web Projects With Vanilla JavaScript -Project#6 (0) | 2020.12.11 |
[Udemy]20 Web Projects With Vanilla JavaScript -Project#5 (0) | 2020.12.10 |