본문 바로가기

Solution & What I learn

[JS - Project] ecommerce-website | Issue & Solution

반응형

자바스크립트로 구현한 쇼핑몰 기능을 담은 프로젝트

 

- mock data를 json으로 직접 만들어 진행

- localStorage로 데이터 저장

 

 

ShoesMall

Goods Choose the product you like All Color Black Blue Brown Green Grey Pink Purple Red White Yellow

heeyeonjeong.github.io

 

📚 구조 & 기능

 

📌 Home

 

header

 

- (mobile) sidebar menu

- scroll시, nav-menu 상단 고정

 

new-section

 

- new goods section - 가로 scroll

- goods 클릭 시, Detail-Page 이동

 

goods-section

 

- mock data 받아와서 동적으로 list 출력

- 가격 1000 단위 절사

- goods pagination

- 색상별 정렬

- goods 클릭 시, Detail-Page로 이동

- 좋아요 클릭 시, WishList에 저장

- icon 색상 변경 (재 클릭 시 원 상태 + WishList에서 삭제)

- 장바구니 클릭시, Cart에 저장

- 장바구니 총 수량 + 1 (최상단에 nav icon에 표시)

- 재 클릭 시, 이미 cart에 들어가 있는 상품 고지 알림

 

footer

- info

 

📌 WishList-Page

 

- WishList-Page에서 상품 삭제 기능

- WishList 비어있을 시, 고지 문구

 

📌 Cart-Page

 

- cart에서 상품 삭제 기능

- goods별 수량 count

- goods별 합계 금액

- goods 총 합계 금액

- cart 비어있을 시, 고지 문구

 

📌 Detail-Page

 

- 좋아요 클릭 시, WishList에 저장

- 장바구니 클릭시, Cart에 저장

 


 

📚 Problem & Solution

 

 

1. 좋아요 클릭 시, WishList-Page에 저장

 

Uncaught (in promise) TypeError: Cannot set property 'innerHTML' of null at displayItemsss

 

오류가 생겼다. innerHTML을 설정할 수 없다는 뜻인데, 각각 다른 HTML 파일에서 js파일 하나를 로드하려다 보니 'itemContainer' 변수를 읽어오지 못해서 생긴 문제였다. 처음에는 그냥 파일을 분리하려 했는데 'createHTML'함수를 재사용해야 하다 보니 무조건 이 파일에서 해결해야 하는 문제였다.. 

 

  if (itemContainer !== null) {
    itemContainer.innerHTML = shoesBox
      .map((shoes) => createHTML(shoes))
      .join("");
  }

 

결론은! itemContainer이 null이 아닌 값에서만 실행되게 하는 if문을 만들었더니 드디어 각 HTML마다 있던 위 오류가 사라졌다..!!

 

 

2. 빈 배열로 다시 돌아가는 현상

 

//wish-storage
let wishObj = localStorage.getItem("wishList")
  ? JSON.parse(localStorage.getItem("wishList"))
  : [];

 

 

3. header, footer 공통 마크업 분리 

 

//header, footer markup data include
async function asyncMarkupData() {
  const allElements = document.getElementsByTagName("*");
  Array.prototype.forEach.call(allElements, function (el) {
    const includePath = el.dataset.includePath;
    if (includePath) {
      const xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
          el.outerHTML = this.responseText;
        }
      };
      xhttp.open("GET", includePath, true);
      xhttp.send();
    }
  });
}

 

<!-- header -->
<div data-include-path="header.html"></div>

<!-- footer -->
<div data-include-path="footer.html"></div>

 

- 공통 마크업을 분리해서 HTML 코드를 확실히 많이 줄일 수 있었다.

 

 

4. pagination

 

//pagination
function pagination(shoesBox) {
  const pageContainer = document.querySelector(".goods-pagination");

  let pageArray = []; //페이지
  let totalCount = shoesBox.length; //총 데이터 수
  let totalPage = Math.ceil(totalCount / 6); //총 페이지 수
  let currentPage = 1; //현재 페이지

  //1 ~ 총 페이지 수 출력
  for (let i = 1; i <= totalPage; i++) {
    pageArray.push(i);
  }

  //페이지 그리기
  if (pageContainer !== null) {
    pageContainer.innerHTML = pageArray
      .map((num) => paginationHTML(num))
      .join("");
  }

  //클릭한 버튼의 page number
  function pageData(e) {
    if (e.target.tagName === "BUTTON") {
      let currentPage = parseInt(e.target.innerHTML);

      displayItems(pageShowBox,currentPage);
      
      loadCart(pageShowBox);
      loadWish(pageShowBox);
    }
  }

  pageContainer && pageContainer.addEventListener("click", pageData);

  displayItems(pageShowBox,currentPage);
}

 

//data slice
let dataPerPage = 6;
let startIndexItem = currentPageNum - 1;

let pageShowBox = shoesBox.slice(
  dataPerPage * startIndexItem,
  dataPerPage * currentPageNum
);

 

- react에서 pagination을 구현해보았지만 js에서 pagination을 구현해본 건 처음이었다.(거꾸로 된 거 같은 기분..) react로 게시판을 만들 때 사용했던 pagination 로직을 떠올리며 비슷하게 구현해보았는데, react에서는 contextAPI나 redux로 상태를 전달할 수 있었지만 js에서는 불가능해서인지 코드가 뭔가 복잡해진 것 같다.. 

 

 

5. 클릭시, 클릭된 데이터 다른 페이지로 이동하기

 

- a 태그의 링크로 클릭한 상품의 id를 detail 페이지의 url 파라미터로 넘기고, 해당 페이지에서 url의 파라미터를 받아왔다.

 

//load detail goods
export function loadDetail(shoesBox) {
  let url = location.search;
  let params = url.substring(url.indexOf("?") + 1, url.length);

  const detailGoods = shoesBox.find((shoes) => {
    return shoes.id === parseInt(params);
  });

  paintDetail(detailGoods);
  detailSelectGoods(detailGoods);
}