메뉴판(부제 : 맛집 리스트)
요구사항
- 음식의 이름,설명,가격이 포함된 메뉴판 만들기
- 카테고리 버튼을 두고 선택시에 해당 카테고리의 음식만 보여주기
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Menu</title>
<!-- font-awesome -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"
/>
<!-- styles -->
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<section>
<div>
<h1>Our Menu</h1>
<hr>
<div class="category-container"></div>
</div>
<div class="menu-container"></div>
</section>
<script src="app.js"> </script>
</body>
</html>
app.js
const menu = [
{
id: 1,
title: "buttermilk pancakes",
category: "breakfast",
price: 15.99,
img: "./images/menu1.jpeg",
desc: `I'm baby woke mlkshk wolf bitters live-edge blue bottle, hammock freegan copper mug whatever cold-pressed `,
},
{
id: 2,
title: "diner double",
category: "lunch",
price: 13.99,
img: "./images/menu2.jpeg",
desc: `vaporware iPhone mumblecore selvage raw denim slow-carb leggings gochujang helvetica man braid jianbing. Marfa thundercats `,
},
{
id: 3,
title: "godzilla milkshake",
category: "shakes",
price: 6.99,
img: "./images/menu3.jpeg",
desc: `ombucha chillwave fanny pack 3 wolf moon street art photo booth before they sold out organic viral.`,
},
{
id: 4,
title: "country delight",
category: "breakfast",
price: 20.99,
img: "./images/menu4.jpeg",
desc: `Shabby chic keffiyeh neutra snackwave pork belly shoreditch. Prism austin mlkshk truffaut, `,
},
{
id: 5,
title: "egg attack",
category: "lunch",
price: 22.99,
img: "./images/menu5.jpeg",
desc: `franzen vegan pabst bicycle rights kickstarter pinterest meditation farm-to-table 90's pop-up `,
},
{
id: 6,
title: "oreo dream",
category: "shakes",
price: 18.99,
img: "./images/menu6.jpeg",
desc: `Portland chicharrones ethical edison bulb, palo santo craft beer chia heirloom iPhone everyday`,
},
{
id: 7,
title: "bacon overflow",
category: "breakfast",
price: 8.99,
img: "./images/menu7.jpeg",
desc: `carry jianbing normcore freegan. Viral single-origin coffee live-edge, pork belly cloud bread iceland put a bird `,
},
{
id: 8,
title: "american classic",
category: "lunch",
price: 12.99,
img: "./images/menu8.jpeg",
desc: `on it tumblr kickstarter thundercats migas everyday carry squid palo santo leggings. Food truck truffaut `,
},
{
id: 9,
title: "quarantine buddy",
category: "shakes",
price: 16.99,
img: "./images/menu9.jpeg",
desc: `skateboard fam synth authentic semiotics. Live-edge lyft af, edison bulb yuccie crucifix microdosing.`,
},
{
id: 10,
title: "bison steak",
category: "dinner",
price: 22.99,
img: "./images/menu10.jpeg",
desc: `skateboard fam synth authentic semiotics. Live-edge lyft af, edison bulb yuccie crucifix microdosing.`,
},
];
let selectedCategory = "all";
function createCategoryBtn(category) {
const $button = document.createElement("button");
$button.classList.add("filter-btn");
$button.textContent = category;
return $button;
}
const $categoryContainer = document.querySelector(".category-container");
const category = menu.reduce(
(values, item) => {
console.log(item.id, values, item.category);
if (!values.includes(item.category)) {
values.push(item.category);
}
return values;
},
["all"]
);
category.forEach((category) => {
const $btn = createCategoryBtn(category);
$btn.addEventListener("click", (event) => {
selectedCategory = event.currentTarget.textContent;
displayMenu();
});
$categoryContainer.append($btn);
});
function createMenuItem(item) {
const { id, title, category, price, img, desc } = item;
const $article = document.createElement("article");
$article.classList.add("menu-item");
const $image = document.createElement("img");
$image.setAttribute("src", img);
$article.appendChild($image);
const $info = document.createElement("div");
$info.classList.add("menu-info");
const $title = document.createElement("h2");
$title.textContent = title;
$info.appendChild($title);
const $price = document.createElement("h2");
$price.textContent = price;
$info.appendChild($price);
const $desc = document.createElement("p");
$desc.textContent = desc;
$info.appendChild($desc);
$article.appendChild($info);
return $article;
}
function clearDisplayMenu() {
const items = document.querySelectorAll(".menu-item");
console.log(items);
if (!items.length) {
console.log("There is no items!");
return;
}
items.forEach((item) => $menuContainer.removeChild(item));
}
function displayMenu() {
clearDisplayMenu();
let displayItem = menu;
if (selectedCategory !== "all") {
displayItem = menu.filter((item) => item.category === selectedCategory);
console.log(displayItem);
}
displayItem.forEach((item) => {
const $item = createMenuItem(item);
$menuContainer.appendChild($item);
});
}
const $menuContainer = document.querySelector(".menu-container");
displayMenu();
style.css
img:not(.logo) {
width: 100%;
}
img {
display: block;
}
/* global classes */
.btn {
text-transform: uppercase;
background: transparent;
color: var(--clr-black);
padding: 0.375rem 0.75rem;
letter-spacing: var(--spacing);
display: inline-block;
transition: var(--transition);
font-size: 0.875rem;
border: 2px solid var(--clr-black);
cursor: pointer;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
border-radius: var(--radius);
}
.btn:hover {
color: var(--clr-white);
background: var(--clr-black);
}
/* section */
.section {
padding: 5rem 0;
}
main {
min-height: 100vh;
display: grid;
place-items: center;
}
/*
===============
Menu
===============
*/
.menu {
padding: 5rem 0;
}
h1 {
text-align: center;
margin-bottom: 2rem;
}
hr {
width: 5rem;
height: 0.25rem;
background: var(--clr-gold);
margin-left: auto;
margin-right: auto;
}
.category-container {
margin-bottom: 4rem;
display: flex;
justify-content: center;
}
.filter-btn {
background: transparent;
border-color: var(--clr-gold);
font-size: 1rem;
text-transform: capitalize;
margin: 0 0.5rem;
letter-spacing: 1px;
border-radius: var(--radius);
padding: 0.375rem 0.75rem;
color: var(--clr-gold);
cursor: pointer;
transition: var(--transition);
}
.filter-btn:hover {
background: var(--clr-gold);
color: var(--clr-white);
}
.menu-container {
width: 90vw;
margin: 0 auto;
max-width: 1170px;
display: grid;
gap: 3rem 2rem;
justify-items: center;
}
.menu-item {
display: grid;
gap: 1rem 2rem;
max-width: 25rem;
}
img {
object-fit: cover;
height: 200px;
border: 0.25rem solid var(--clr-gold);
border-radius: var(--radius);
}
h2 {
display: flex;
justify-content: space-between;
border-bottom: 0.5px dotted var(--clr-grey-5);
}
.item-info h4 {
margin-bottom: 0.5rem;
}
.price {
color: var(--clr-gold);
}
p {
margin-bottom: 0;
padding-top: 1rem;
}
@media screen and (min-width: 768px) {
.menu-item {
grid-template-columns: 225px 1fr;
gap: 0 1.25rem;
max-width: 40rem;
}
.photo {
height: 175px;
}
}
@media screen and (min-width: 1200px) {
.section-center {
width: 95vw;
grid-template-columns: 1fr 1fr;
}
.photo {
height: 150px;
}
}
칵테일 소개 페이지
요구사항
- API를 통해 칵테일에 대한 정보를 받아오기
- 받아온 정보 기반으로 화면에 그려죽;
- 검색을 통해 필터링이 가능하도록 만들어주기
const URL = "https://www.thecocktaildb.com/api/json/v1/1/search.php?s=a";
//1. fetch 사용
function fetchDrinks() {
fetch(URL)
.then((response) => {
return response.json();
})
.then((data) => {
console.log(data);
})
.catch(error=>console.error(error));
}
//2.async await 사용
async function fetchDrinks() {
try {
const response = await fetch(URL);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
console.log("finished!");
}
fetchDrinks();
function fetchDrinks() {
fetch(URL)
.then((response) => {
return response.json();
})
.then((data) => {
// console.log(data.drinks[0]);
const $container = document.querySelector('.item-container')
const $img = document.createElement('img');
$img.setAttribute('src', data.drinks[0].strDrinkThumb);
$container.appendChild($img);
// return fetch(data.drinks[0].strDrinkThumb);
})
.catch(error => console.error(error));
console.log('finish');
// const data = response.json();
// console.log(data);
}
Array 고차함수
고차 함수
- 함수를 파라미터로 전달받거나 연산의 결과로 반환해주는 메서드
- 함수형 프로그래밍의 핵심
forEach()
- for문을 대체하는 고차함수, 반복문을 추상화하여 구현된 메서드이고 내부에서 주어진 배열을 순회하면서 연산을 수행
const numArr = [1,2,3,4,5];
int total = 0;
numArr.forEach((item) => {
total+=item;
});
console.log(total); //15
map()
- forEach와 같이 순회하면서, 콜백함수에서의 실행결과를 리턴한 값으로 이루어진 배열을 만들어 반환
const numArr = [1,2,3,4,5];
const numMaparr = numArr.map((item) => {
return (item%2==0)? 'even' : 'odd';
});
console.log(numArr); //['odd','even','odd','even','odd']
find()
- indexOf()가 찾고자 하는 인덱스
- include()가 찾고자 하는 값을 Bool
- find()는 찾고자 하는 값을 그대로 반환
const numArr = [1,3,3,5,7];
const objectArr = [
{ name: 'Harry', age: 20 },
{ name: 'Kim', age: 30 },
{ name: 'Steve', age: 40 }
];
console.log(objectArr.find(item => {
return item.age === 20; //해당조건에 부합하면 item 값 반환
}); // {name: "Harry", age: 20}
findIndex()
- 배열 메소드 indexOf()의 콜백함수 버전
- 고차함수 find()의 리턴값이 인덱스인 버전
const objectArr = [
{ name: 'Harry', age: 20 },
{ name: 'Kim', age: 30 },
{ name: 'Steve', age: 40 }
];
console.log(objectArr.findIndex(item => {
return item.age === 20 //해당조건에 부합하면 item의 인덱스 반환
}); //0
console.log(objectArr.findIndex(item => item.name === 'Kim')); //1
filter()
- 주어진 배열을 순회하면서 콜백 함수의 반환값이 true에 해당하는 요소로만 구성된 새로운 배열을 생성하여 반환
const numberArr = [1, 2, 3, 4, 5];
const numberFilterArr = numberArr.filter((item) => {
return item % 2 === 0; // 해당조건에 부합으면 item을 넣어 배열 반환
});
console.log(numberFilterArr); // [2, 4]
reduce()
- 콜백 함수의 실행된 반환값을 전달받아 연산의 결과값이 반환
- forEach, map, filter 기능을 reduce로 모두 구현해서 쓸순 있어 고차함수의 부모라고 불린다.
const numberArr = [1, 2, 3, 4, 5];
const sum = numberArr.reduce((previousValue, currentValue, currentIndex, thisArray) => {
console.log('Current Index: ' + currentIndex + ' / Previous Value: ' + previousValue + ' / C
return previousValue + currentValue; // 연산한 결과값을 누산기previousValue에 넣어 최종값을 얻는다.
}, 0);
console.log('Sum: ' + sum);
/*
Current Index: 0 / Previous Value: 0 / Current Value: 1
Current Index: 1 / Previous Value: 1 / Current Value: 2
Current Index: 2 / Previous Value: 3 / Current Value: 3
Current Index: 3 / Previous Value: 6 / Current Value: 4
Current Index: 4 / Previous Value: 10 / Current Value: 5
Sum: 15
*/
💡 initalValue의
sort()
- 배열 정렬. 원 배열이 정렬됨. 콜백 함수를 통해 배열의 원소들을 어느 기준으로 정렬할지 지정
arr.sort(function(a,b) {
if(a>b) return 1;
if(a==b) return 0;
if(a<b) return -1;
});
const arr = [
{name: 'banana', price: 3000},
{name: 'apple', price: 1000},
{name: 'orange', price: 500}
];
arr.sort(function(a, b) {
return a.price - b.price; // price 숫자값을 기준으로 정렬
});
/*
{"name":"orange","price":500}
{"name":"apple","price":1000}
{"name":"banana","price":3000}
*/
some()
- 배열 메소드 include()의 콜백함수 버전
- include는 값이 있냐에 따른 bool이면, some은 함수 로직에 따른 bool
- 배열의 요소들을 주어진 함수(조건)을 통과하는데 한 개라도 통과되면 true, 아닐때에는 false
- 빈 배열로 함수(조건)을 토과하면 무조건 false를 출력. 이와 같이 some이라는 함수(조건)에 부합한 개수가 some이면 true라는 뜻에서 비롯됨
const array = [1, 3, 5];
// 짝수인지 체크
const result = array.some((currentValue) => {
return currentValue % 2 === 0;
})
console.log(result); // 리턴 값 : false
// 그 이유는 array의 3개의 요소 모두 2로 나눌때 나머지가 0이 아니기 때문이다.
// 하나라도 부합한 조건에 맞으면 true, 모두 부합하지 않으면 false
const array2 = [1, 2, 3, 5];
const result2 = array2.some((currentValue) => {
return currentValue % 2 === 0;
})
console.log(result2); // 리턴 값 : true
// 그 이유는 array의 4개의 요소 모두 2로 나눌때 나머지가 0인 요소가 하나라도 있기 때문이다.
// 하나라도 부합한 조건에 맞으면 true, 모두 부합하지 않으면 false
every()
- some() 의 반대 버전
- 배열안의 모든 요소가 주어진 함수(조건)을 모두 통과하면 true, 한 요소라도 통과하지 못하면 false
- 빈 배열을 함수에 적용시키면 무조건 true를 반환
- every이라는 이름은, 함수(조건)에 따라 함수(조건)에 부합한 개수가 every이면 true라는 뜻에서 비롯됨
const array = [1, 30, 39, 29, 13];
const result = array.every((currentValue) => {
return currentValue < 40;
})
console.log(result); // 리턴 값 : true
// 그 이유는 array의 모든 요소가 40보다 작기 때문이다.
// 하나라도 부합한 조건에 맞지 안으면 false, 모두 부합하면 true
// -----------------------------------------------
const array2 = [1, 30, 39, 29, 100, 13];
const result2 = array2.every((currentValue) => {
return currentValue < 40;
})
console.log(result2); // 리턴 값 : false
// 그 이유는 array의 1개의 요소 100이 40보다 크기 때문이다.
// 하나라도 부합한 조건에 맞지 안으면 false, 모두 부합하면 true
'기타 > 글로컬청년취업사관학교' 카테고리의 다른 글
[글로컬청년취업사관학교] [TIL] 240807 (0) | 2024.08.07 |
---|---|
[TIL] 240708 (0) | 2024.07.08 |
[글로컬청년취업사관학교][TIL] 240702 (0) | 2024.07.03 |
[글로컬청년취업사관학교][TIL] 240701 (0) | 2024.07.02 |
[글로컬청년취업사관학교][TIL] 240628 (1) | 2024.06.28 |