[자바스크립트 프로젝트] 쇼핑몰 구현하기 - [장바구니,navbar,카테고리]
팀원들과 함께 쇼핑몰을 구현하기로하였습니다.
처음에는 리액트로 하려고 했으나 기본적인 개념을 이해해야한다고 생각하여
자바스크립트로 진행을 했습니다.
- vite를 이용하여 프로젝트 생성
-효율적인 프로젝스 시간을 위해서 디자인같은경우는 클론으로 하여 제작
백엔드를 담당한 팀원들과 폴더구조를 상의해서 만들고 제작하기로 하였습니다.
로고 및 메뉴 / navbar.js
코드
const header = document.querySelector(".header");
const getItemNav = JSON.parse(localStorage.getItem("cart")) || [];
//카트 숫자넘버 그려지기전에 넣어둬야 작동한다.
let cart_num = getItemNav.length;
// 네비 메뉴
const menu = [
{ text: "상 품", link: "/product" },
{ text: "주문 하기", link: "/cart" },
//{ text: "고객 센터", link: "/customer-service" }
];
// 메뉴 아이템을 생성하는 함수
const menu_li = () => {
const menuItems = menu.map(
(item) =>
`<li><a href="${item.link}" onclick="route()">${item.text}</a></li>`
);
return menuItems.join(""); // 배열을 문자열로 결합하여 반환
};
header.innerHTML = `
<div class="header_section">
<div>
<ul>
<li class="main_login_btn logout"><a href="/login">로그인</a></li>
<li class="main_user_join"><a href="/register">회원가입</a></li>
</ul>
</div>
<div class="main_top_logo"><span style="font-size:40px">Hwasahae</span></div>
<div class="header_right_area">
<ul>
<li class="search_open">
<form action="/" method="post" name="/">
<fieldset>
<input name="search" placeholder="비타민 존맛탱" onkeydown="함수명대체할것." value="" class="MS_search_word">
<a href="javascript:search_submit();" class="search_btn"></a>
</fieldset>
</form>
</li>
<li class="top_myp"></li>
<li class="top_cart">
<span id="user_basket_quantity" class="user_basket_quantity">${cart_num}</span>
</li>
</ul>
</div>
</div>
<nav>
<ul>
${menu_li()}
</ul>
</nav>
`;
//로그인 버튼 => 로그아웃 버튼
const userData = localStorage.getItem("userInfo");
const loginLogoutButton = document.querySelector(".main_login_btn");
window.onload = function () {
if (loginLogoutButton) {
if (userData) {
loginLogoutButton.innerHTML = `<li class="main_login_btn logout"><a href="/login">로그아웃</a></li>`;
} else {
loginLogoutButton.innerHTML = `<li class="main_login_btn logout"><a href="/login">로그인</a></li>`;
}
}
};
const logoutEvent = () => {
loginLogoutButton.addEventListener("click", async (e) => {
e.preventDefault();
const logout_URL = "http://localhost:3000/logout";
fetch(logout_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
}).then((res) => {
console.log(res);
alert("로그아웃 되었습니다");
localStorage.removeItem("userInfo");
location.href = "/login";
});
});
};
if (localStorage.getItem("userInfo")) {
logoutEvent();
}
//메인로고 넣기
const main_log = document.querySelector(".main_top_logo");
// const mainImg = new Image();
// //메인로고 2023.11.11 김나영이 바꿈
// // mainImg.src = "http://skincure.co.kr/design/skincure/0759ansome/top_logo.gif";
// mainImg.src =
// "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdna%2FqEkX2%2Fbtsz61YM6Nk%2FAAAAAAAAAAAAAAAAAAAAAHmsv_KZ-7gLLBR1zTV8ZqT7Ya9NwTytMGB2Rss9fily%2Fimg.jpg%3Fcredential%3DyqXZFxpELC7KVnFOS48ylbz2pIh7yKj8%26expires%3D1753973999%26allow_ip%3D%26allow_referer%3D%26signature%3DyYcp%252Fqm8eMEvsD7acnerhXzubJc%253D";
// main_log.appendChild(mainImg);
main_log.addEventListener("click", () => {
window.location.href = "/index.html"; // 메인 페이지의 URL을 여기에 지정
});
//서치 돋보기 버튼
const search_btn = document.querySelector(".search_btn");
const search_btn_img = new Image();
search_btn_img.src =
"http://skincure.co.kr/design/skincure/0759ansome/btn_search.png";
search_btn.appendChild(search_btn_img);
search_btn.addEventListener("click", () => {
window.location.href = "/index.html"; //추후 돋보기 룅크변경
});
//사람 아이콘
const top_myp = document.querySelector(".top_myp");
const mypImg = new Image();
mypImg.src = "http://skincure.co.kr/design/skincure/0759ansome/btn_mypage2.gif";
top_myp.appendChild(mypImg);
// top_myp.addEventListener("click", () => {
// window.location.href = "/mypage"; //추후 룅크변경
// });
//userData위에 getItem으로 가져옴 const userData = localStorage.getItem("userInfo");
//관리자 여부에 따른 네브바 처리 => 관리자로 로그인 했을 경우 마이페이지 링크가 관리자 페이지로, 구매자가 로그인 했을 경우 구매자페이지로 이동
if (userData) {
const userInfo = JSON.parse(userData);
const isRole = userInfo.role; //role이 구매자인지 관리자인지
if (isRole === "관리자") {
// 마이페이지 아이콘을 관리자 페이지로 연결
top_myp.addEventListener("click", () => {
window.location.href = "/admin"; //추후 룅크변경
});
} else {
// 구매자인 경우 마이페이지로 연결
top_myp.addEventListener("click", () => {
window.location.href = "/mypage"; //추후 룅크변경
});
}
}
//카트 아이콘
const top_cart = document.querySelector(".top_cart");
const cartImg = new Image();
cartImg.src = "http://skincure.co.kr/design/skincure/0759ansome/btn_cart2.gif";
top_cart.appendChild(cartImg);
top_cart.addEventListener("click", () => {
window.location.href = "/cart"; //추후 룅크변경
});
// 위에는 헤더바 아래는 푸터바
const footer = document.querySelector("footer");
footer.innerHTML = `
<div class="ft_sec01">
<div class="bt_inner">
<ul class="fleft">
<li><a href="/shop/page.html?id=1">회사소개</a><span class="bt_bar">|</span></li>
<li><a href="/html/info.html">이용가이드</a><span class="bt_bar">|</span></li>
<li><a href="javascript:bottom_privacy();" style="color:#ac1818; font-weight:700;">개인정보처리방침</a><span class="bt_bar">|</span></li>
<li><a href="javascript:view_join_terms();">이용약관</a></li>
</ul>
<ul class="fright">
<li><a href="https://www.skincure.co.kr">홈으로</a><span class="bt_bar">|</span></li>
<li><a href="#">위로가기</a><span class="bt_bar">|</span></li>
<li><div class="familySite">
<select name="number" onchange="window.open(this.value)">
<option selected="selected">Family Site</option>
<option value="http://eskincure.co.kr">스킨큐어 기업 홈페이지</option>
<option value="http://eskincure.com">스킨큐어 영문 홈페이지</option>
<option value="http://en.skincure.co.kr/">스킨큐어 영문 쇼핑몰</option>
<option value="http://www.skincure.kr">B2B 도매홈페이지</option>
</select>
</div></li>
</ul>
</div>
</div>
<div class="cboth ft_sec02">
<div class="bt_inner">
<div class="fleft cs_area">
<div class="tit_cs">고객센터</div>
<div class="cs_sec"><!-- CUSTOMER CENTER : 정보 -->
<div class="fleft ft_phone">1544-5439</div>
<div class="fleft cs_info">운영시간: 월~금 AM 09:00 - PM 5:30 / 점심시간: PM 12:20 - PM 1:20<br><span class="bk">휴무: 토,일,공휴일</span></div>
</div>
</div>
<div class="fleft bank_area">
<div class="tit_bank">무통장 입금 계좌</div>
<div class="bk_sec"><!-- BANK ACCOUNT : 정보 -->
<div class="fleft bank_info">국민은행 : 290301-04-006396</div>
</div>
</div>
<div class="fleft return_area">
<div class="tit_return">반품/교환 주소 안내</div>
<div class="rt_sec"><!-- 반품주소안내 -->
<div class="fleft rt_info">경기도 용인시 수지구 신수로 767, A동 10층 1007호(동천동, 분당 수지 U-TOWER)<br><span>자세한 사항은 문의게시판 혹은 공지사항을 참고해주세요</span></div>
</div>
</div>
</div>
</div>
<div class="cboth ft_sec03">
<div class="bt_inner">
<div class="fleft com_info">
상호명 : 스킨큐어(주) / 대표이사 : 김명옥 / 경기도 용인시 수지구 신수로 767, A동 10층 1007호(동천동, 분당수지 U-TOWER) / 1544-5439 / FAX : 031-719-5202 <br>
사업자등록번호 : 123-86-09894 <a href="https://www.ftc.go.kr/www/biz/bizCommList.do?key=5375&searchCnd=wrkr_no&searchKrwd=1238609894" target="_blank">[사업자정보확인]</a> / 개인정보 책임자 : 김정기(<a href="mailto:msd02@skincure.co.kr">msd02@skincure.co.kr</a>) / 통신판매업신고 : 제 2016-용인수지-0385 호 </div>
<div class="cboth copyright">COPYRIGHT BY 스킨큐어(주) ALL RIGHTS RESERVED. <!--Hosting by (주)코리아센터닷컴--></div>
<span class="escrow"><div class="ft-escrow"> <a href="http://www.skincure.co.kr" onclick="window.open('https://okbfex.kbstar.com/quics?e2eType=10&page=C021590&cc=b034066%3Ab035526&mHValue=54e0922d4df6a7693fb792989984b118201609091343851 ', 'escrow', 'height=670,width=630'); return false;">
<!-- 하단 에스크로 배너 링크수 삭제-->
</a><!-- 하단 에스크로 배너 링크수정 -->
</div>
</span></div>
</div>
`;
다른페이지에서 공통으로 사용하기 위해서 템플릿화하여 js에서 html 을 만드는 형식으로 제작하였습니다.
장바구니 / cart.js
코드
const getItems = JSON.parse(localStorage.getItem("cart")) || [];
console.log(getItems);
let totalPrice = 0; //총가격 초기
// 각 fetch 요청을 저장할 배열 만들기.
const fetchPromises = getItems.map(async (item) => {
const response = await fetch(`http://localhost:3000/products/${item.id}`);
return await response.json();
});
console.log(fetchPromises);
// fetch 요청으로 위에서 만든 리절트쪽에 있는 데이터를 프로미스 올로 사용.
Promise.all(fetchPromises).then((productDataArray) => {
getItems.forEach((item, index) => {
const data = productDataArray[index]; //각 배열순서에맞는 데이터를 담는다.
console.log(data.images[0]);
// 각 상품의 가격을 화면에 표시되는 가격으로 계산하여 더합니다 //처음화면 진입때 더하기함
let item_su = item.count || 1; //카운트 값이 있으면 넣고 아니면 1을넣느다.
totalPrice += data.price * item_su;
//총 상품 가격
let total_price = () => {
const total_num = data.price * item_su;
return total_num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
};
const MapItem = `
<tr data-index="${index}">
<td><img src="${data.images[0]}" alt="상품 이미지" style="width: 100px; height: 100px;"></td>
<td><span class="product_name">${data.name}</span></td>
<td>
<button class="minus" data-index="${index}">-</button>
<input class="item_many" type="text" value="${item_su}" data-index="${index}">
<button class="plus" data-index="${index}">+</button>
</td>
<td><span class="item_total">${total_price()}</span>원</td>
<td><button class="deleteBtn" data-index="${index}">삭제</button></td>
</tr>
`;
const pageSleeted = document.querySelector("#productTable");
pageSleeted.innerHTML += MapItem; //html
// 장바구니 - 제품수량 증가 및 감소
const plusBtns = document.querySelectorAll(".plus");
const minusBtns = document.querySelectorAll(".minus");
const deleteBtns = document.querySelectorAll(".deleteBtn");
const item_many = document.querySelectorAll(".item_many");
const item_total = document.querySelectorAll(".item_total");
plusBtns.forEach((plusBtn, index) => {
plusBtn.addEventListener("click", (e) => {
e.preventDefault();
handlePlusClick(index);
});
});
minusBtns.forEach((minusBtn, index) => {
minusBtn.addEventListener("click", (e) => {
e.preventDefault();
handleMinusClick(index);
});
});
deleteBtns.forEach((deleteBtn, index) => {
deleteBtn.addEventListener("click", (e) => {
e.preventDefault();
handleDeleteClick(index);
});
});
// 삭제 버튼
const handleDeleteClick = (index) => {
// 해당 인덱스의 상품 삭제
getItems.splice(index, 1);
// 로컬 스토리지에서도 삭제
localStorage.setItem("cart", JSON.stringify(getItems));
// 해당 행 삭제
const tableRow = document.querySelector(
`#productTable tr[data-index="${index}"]`
);
tableRow.parentNode.removeChild(tableRow);
location.reload();
};
// 플러스 버튼
const handlePlusClick = (index) => {
// 카운트 증가
getItems[index].count = (getItems[index].count || 1) + 1;
// UI 업데이트
item_su = getItems[index].count;
item_many[index].value = item_su;
totalPrice += data.price;
item_total[index].innerHTML = total_price();
console.log(item_many[index].value);
// 로컬 스토리지 업데이트
const cartItems = JSON.parse(localStorage.getItem("cart")) || [];
if (cartItems[index]) {
// 로컬 스토리지의 카운트 업데이트
cartItems[index].count = getItems[index].count;
} else {
// 로컬 스토리지에 아이템이 없으면 새로 추가
cartItems[index] = { count: getItems[index].count };
}
// 업데이트된 데이터를 로컬 스토리지에 저장
localStorage.setItem("cart", JSON.stringify(cartItems));
totalElement();
};
// 마이너스 버튼
const handleMinusClick = (index) => {
getItems[index].count = (getItems[index].count || 1) - 1;
// 수량이 1보다 작으면 최소값을 1로 설정
if (getItems[index].count < 1) {
getItems[index].count = 1;
}
item_su = getItems[index].count;
totalPrice -= data.price;
item_many[index].value = item_su;
item_total[index].innerHTML = total_price();
console.log(item_many[index].value); //콘솔 확인용
// 수량 업데이트용 로컬 스토리지에서 데이터 가져오기
const cartItems = JSON.parse(localStorage.getItem("cart")) || [];
if (cartItems[index]) {
cartItems[index].count = item_many[index].value;
// 로컬 스토리지 업데이트된 데이터 저장
localStorage.setItem("cart", JSON.stringify(cartItems));
}
totalElement();
};
const totalElement = () => {
const totalBox = document.getElementById("totalPrice");
totalBox.innerHTML = `총 가격: ${totalPrice
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ",")}원`;
}; // 총 가격을 표시할 위치에 id="totalPrice"인 요소를 추가
totalElement();
const paymentBtn = document.querySelector("#payment_btn");
paymentBtn.addEventListener("click", () => {
const totalMani = totalPrice
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
localStorage.setItem("totalPrice", totalMani);
});
//장바구니 지우기
const allDeleted = document.querySelector("#cartDelete");
allDeleted.addEventListener("click", () => {
window.localStorage.removeItem("cart");
location.reload();
});
});
});
로컬스토리지를 이용한 장바구니 제작.
직면한 문제 - 각각 상품에대한 정보를 index 순서로 데이터를 각각 저장해서 사용하는 방식이었으나 새로고침을하면 로딩순서에 따라서
순서가 무작위로 섞이면서 바뀌는 현상이 나타났다.
해결법 - Promise.all
프로미스 올을 이용하여 각 아이템의 데이터를 전부 받고나서 아이템이 정렬되도록하여 입력된 순서대로 로딩하여 해결.
추가사항
제품을 개별로 한개씩 삭제시 index로 제품 정렬로 인해 새로고침을 실행.
제품 상세 페이지. / itemPage.js
코드
const urlParams = new URL(location.href).searchParams;
const itemId = urlParams.get('id');
console.log(itemId)
fetch(`http://localhost:3000/products/${itemId}`)
.then((response) => response.json()).then((data) =>{
//상품 이미지 추가.
const img_box = document.querySelector('.img_box')
const imgBox = new Image();
imgBox.src = `${data.images}`
img_box.appendChild(imgBox)
//구매 관련 폼
const info = document.querySelector('.info')
const item_date = data;
console.log(item_date)
//상품 갯수
let item_su = 1
//토탈금액 물픔금액 * 갯수
let total_price = () =>{
const total_num = item_date.price * item_su
return total_num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
}
info.innerHTML = `
<h3 class="tit-prd">${item_date.name}</h3>
<ul class="itemInfo">
<li>
<span class="tb-left">판매가격</span>
<div class="tb-left tb-left-in"><span class="pricevalue" id="price">${item_date.price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}</span>원</div>
</li>
<li>
<span class="tb-left">소비자가격</span>
<div class="tb-left tb-left-in"><strike>${item_date.price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}원</strike></div>
</li>
<li>
<span class="tb-left">적립금</span>
<div class="tb-left tb-left-in reserves"><span class="pricevalue">1</span>%</div>
</li>
<li>
<span class="tb-left">용량 및 중량</span>
<div class="tb-left tb-left-in reserves"><span class="pricevalue">200</span>ml</div>
</li>
</ul>
<div class="option_add_area">
<ul>
<li>${item_date.description}</li>
<li>
<input type="text" class="item_many" id="MS_amount_basic_0" name="amount[]" value=${item_su} onfocusout="set_amount(this, 'basic');" size="4" style="text-align: right; float: left;" class="basic_option" maxlength="" data-gtm-form-interact-field-id="0">
<span class="plus area_btn">+</span>
<span class="minus area_btn">-</span>
<strong class="MK_price"><span id="MK_p_price_basic_0">${item_date.price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}</span>원</strong>
</li>
</ul>
</div>
<div>
<ul id="MK_innerOptTotal">
<li>
<p class="totalLeft"><span class="MK_txt-total">총 상품 금액</span></p>
<p class="totalRight">
<strong class="MK_total" id="MK_p_total"></strong>
<span class="MK_txt-won">원</span>
</p>
</li>
</ul>
</div>
<div class="cboth prd-btns">
<a id="buyBtn" href="/payment" class="buy move">BUY NOW</a>
<a id="cartBtn" href="/cart" class="basket move">CART</a>
</div>
`
// 바로구매 / 장바구니 로컬스토리지 넣기.
const buyBtn = document.querySelector('#buyBtn')
const cartBtn = document.querySelector('#cartBtn')
const storedCart = JSON.parse(window.localStorage.getItem('cart') || '[]'); // 가져오기
const userInfo = window.localStorage.getItem('userInfo'); // 로그인 확인용.
//바로결제
buyBtn.addEventListener('click',(e)=>{
if(!userInfo){
e.preventDefault()
window.location.href ="/login"
}
const cartList = []
if (cartList.some(item => item.id === itemId)) {
return;
}else{
cartList.push({
id:itemId,
price:item_date.price,
total_price: total_price(),
count:item_su
});
window.localStorage.setItem('buyItem', JSON.stringify(cartList))
}
})
//장바구니로
cartBtn.addEventListener('click', () => {
const cartList = storedCart;
const itemIndex = cartList.findIndex(item => item.id === itemId);
if (itemIndex !== -1) {
// 이미 장바구니에 있는 경우 count를 갱신합니다.
cartList[itemIndex].count = item_su;
window.localStorage.setItem('cart', JSON.stringify(cartList));
alert("제품의 수량을 업데이트했습니다.");
} else {
// 장바구니에 없는 경우 새로운 아이템을 추가합니다.
cartList.push({
id: itemId,
price: total_price().replace(/,/g, ''),
count: item_su
});
alert("장바구니에 넣었습니다.");
window.localStorage.setItem('cart', JSON.stringify(cartList));
}
});
//제품수량 증가 및 감소
const plus = document.querySelector('.plus')
const minus = document.querySelector('.minus')
const item_many = document.querySelector('.item_many')
const item_total = document.querySelector('#MK_p_total')
item_total.innerHTML = item_date.price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
plus.addEventListener('click', () => {
item_su = item_su+1
item_many.value = item_su
item_total.innerHTML = total_price()
})
minus.addEventListener('click', () => {
if(item_many.value == 1){
item_many.value = 1
return alert("최소수량 입니다")}
item_su = item_su-1
item_many.value = item_su
item_total.innerHTML = total_price()
})
//디테일 이미지. url
const detail_div = document.querySelector('.detail_img')
const detail_text = document.querySelector('.item_detail>div:first-child')
//위에는 선택자
const detail_img = new Image();
detail_img.src = 'http://sandawha.com/sandawha/detail/Sandawha-Natural-Mild-Cleansing-Oil_01.jpg'
detail_div.appendChild(detail_img)
//아래는 상세페이미지가
detail_img.onload = function() { // 이미지로딩 성공했을때
detail_text.style.width = detail_div.offsetWidth + "px";
}
detail_img.onerror = function() {
// 이미지 로딩 중 오류가 발생한 경우 실행할 코드를 여기에 작성합니다.
alert("이미지 로드 오류")
};
});
제품 클릭시 url에 제품의 id 값을 Params 를 이용한 상세페이지 정보를 불러오게 제작.
데이터를 불러와서 아이템에대한 구매 정보를 로컬스토리지에 저장하여 구매페이지or장바구니 페이지로 이동.
카테고리 아이템 정렬 / product.js
코드
const categoryNav = document.querySelector('.list')
let linkName = []
// 카테고리 데이터로 불러와서 만들기.
async function fetchData() {
try {
const storedCart = JSON.parse(window.localStorage.getItem("cart") || "[]"); // 가져오기
const response = await fetch('http://localhost:3000/category');
const data = await response.json();
console.log(data);
const category_item_nav = data.map((item, index) => `
<li><a href="" class="linkName" data-name="${item.name}" key={index}>${item.name}</a></li>
`).join('');
categoryNav.innerHTML = category_item_nav;
const linkBtns = document.querySelectorAll('.linkName');
linkBtns.forEach(linkBtn => {
linkBtn.addEventListener('click', (e) => {
e.preventDefault();
const dataNameValue = linkBtn.getAttribute('data-name');
linkName = []
linkName.push(dataNameValue);
listHtml(linkName)
cartB()
});
});
const cartB = () =>{
setTimeout(()=>{
const cartBtns = document.querySelectorAll(".cartDateBtnMd"); //버튼클래스
const cartList = storedCart; //장바구니 리스트
cartBtns.forEach((cartBtn) => {
const dataValue = cartBtn.dataset.value; //상품의 아이디값
const dataPrice = cartBtn.getAttribute("data-another"); //상품의 가격 데이터
cartBtn.addEventListener("click", (e) => {
if (cartList.some((item) => item.id === dataValue)) {
//장바구니 스토리지 중복확인.
alert("이미 장바구니에 있습니다.");
return;
} else {
cartList.push({
id: dataValue,
price: dataPrice,
count: 1,
}); //상품 아이디를 배열에 넣음
window.localStorage.setItem("cart", JSON.stringify(cartList)); // 스토리지에 장바구니 아이템넣음.
alert("장바구니에 넣었습니다.");
}
});
});
},100)
}
cartB()
} catch (error) {
console.error('Error fetching data:', error);
}
}
fetchData().then(() => {
// fetchData가 완료된 후 listHtml 호출
listHtml(linkName);
});
// const koreanText = '스킨'; // 여기에 실제로 사용하려는 한글 텍스트를 넣어주세요
// fetch(`http://localhost:3000/category/products/${koreanText}`).then((response) => response.json()).then((data)=>console.log(data))
const listHtml = async (link) => {
console.log(link);
const encodedLink = encodeURIComponent(link);
let notLink;
if (link) {
notLink = fetch(`http://localhost:3000/category/products/${encodedLink}`);
} else {
notLink = fetch(`http://localhost:3000/category/products/스킨`);
}
const response = await notLink;
const items = await response.json();
console.log(items);
// 상품 템플릿화
function createProductTemplate(imageSrc, title, price, id) {
const productTemplate = `
<div class="product">
<div class="product-image">
<a href="/item?id=${id}">
<img src="${imageSrc}" alt="상품 섬네일">
</a>
<div class="info_icon">
<span class="cartDateBtnMd" data-value="${id}" data-another="${price}"><img src="http://skincure.co.kr/design/skincure/0759ansome/icon_prd04.gif" alt="미리보기"></span>
</div>
</div>
<div class="product-info">
<div class="product-title">${title}</div>
<div class="product-price">
<span>${price} 원</span>
</div>
</div>
</div>
`;
return productTemplate;
}
// 동적 상품 추가
const productContainer = document.querySelector('.product-container');
// 반복해서 상품을 추가
productContainer.innerHTML = '';
items.forEach((item) => {
const productElement = createProductTemplate(item.images[0], item.name, item.price, item._id);
productContainer.innerHTML += productElement;
});
};
listHtml();
document.addEventListener("DOMContentLoaded", function() {
const liElements = document.querySelectorAll("#productClass .cate-wrap .class-list ul li");
liElements.forEach(function(li) {
li.addEventListener("mouseover", function() {
// 마우스 호버 시 배경색과 테두리 색 변경
li.classList.add("active");
});
li.addEventListener("mouseout", function() {
// 마우스가 빠져나가면 배경색과 테두리 색을 제거하여 원래대로 돌립니다.
li.classList.remove("active");
});
});
});
카테고리 클릭에따라 data-name 의 어트리뷰트 이름을 가져와서
데이터를 다시 카테고리에 맞는 아이템으로 다시 로딩을 시킨다.
문제점 - 클릭시 데이터 로딩보다 view그려지는속도가 빨라서 오류가있었는데
해결 - async/await 를 이용하여 로딩이 될때까지 기다리게하여 해결하였다.