내일배움단 11일메이킹챌린지 7일차

·2021년 7월 24일
0

오늘도 장바구니

localStorage를 이용한 장바구니 개발 마무리해야한다!

로컬스토리지에 저장한 key값이 순서가 뒤죽박죽 되어버리는 문제를 어떻게 해결할 것인가? 찾아보니 비슷한 질문을 하신 분이 있었다!
https://www.inflearn.com/questions/38188

아무래도 우선 로컬스토리지의 데이터를 전부 다 불러와서 어딘가 저장한 뒤에, 그걸 다시 sort로 정렬을 하고 그 정렬된 데이터를 가지고 처리하는 방식을 시도해봐야겠다.

localStorage.getItem(key)로 값 가져오고 나서,
["id"]를 해도 id값이 안 나와서 뭐지, 했는데
JSON형태라서 console.log로 찍어봤을 때는 모양이 꼭 객체처럼 생겨서 객체를 가져온 것 같지만 사실 그냥 string type이었기 때문...
JSON.parse(localStorage.getItem(key))로 객체로 만들어서 저장해준 다음 ["id"]하니까 잘만 나온다. 헤헤.

javascript, localStorage를 이용한 장바구니 기능 구현

localStorage에 "장바구니담기"를 누른 메뉴를 저장하기

if (localStorage.length > 0) {
  for (let i = 0; i < localStorage.length; i++) {
    if (Number(index) < Number(localStorage.key(i))) { //maxIndex 구하기
      index = localStorage.key(i);
      var cartItem = JSON.parse(localStorage.getItem(localStorage.key(i)));
      if ( //menu와 option이 같으면 같은 메뉴이므로 price와 count만 바꿔준다
        JSON.stringify(cartItem.menu) == JSON.stringify(menu) &&
        JSON.stringify(cartItem.option) == JSON.stringify(option)
      ) {
        isSame = true;
        price = cartItem.price;
        count = cartItem.count;
        break;
      }
    }
  }
}

(원본: https://velog.io/@sdsdsrd/localStorage%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9E%A5%EB%B0%94%EA%B5%AC%EB%8B%88-%EA%B5%AC%ED%98%84)

구글에서 찾은 선배님의 소스코드 중 일부를 아래와 같이 수정했다.(key값이 순서대로 나오지 않는 문제를 해결하기 위해) -> localStorage.key() 를 쓰지 않고 .getItem()으로 변경

for (let i = 0; i < localStorage.length; i++) {
  if (Number(index) < Number(localStorage.key(i))) { //maxIndex 구하기
    index = localStorage.key(i);
for (let i = 1; i < localStorage.length+1; i++) {
  if (Number(index) < i) { //maxIndex 구하기
    let cartItem = JSON.parse(localStorage.getItem(i))
    index = cartItem.id;

(for문을 통해 localStorage.key(0)을 넣으면 맨 처음 넣은 녀석이 나와야하는데 두번째로 넣은 녀석이 나와서 문제가 생겼었다)

if (localStorage.length > 0) {
  for (let i = 1; i < localStorage.length+1; i++) {
    if (Number(index) < i) { //maxIndex 구하기
      let cartItem = JSON.parse(localStorage.getItem(i))
      index = cartItem.id;

      //menu 이름이 같으면 같은 메뉴
      if(JSON.stringify(cartItem.menu) === JSON.stringify(menu)){
        isSame = true;
        price = cartItem.price;
        count = cartItem.count;
        break;
      }
    }
  }
}

장바구니에 상품 담는(localStorage에 저장) 부분 1차 완성 코드

HTML

<div class="card-body">
  <a target="_blank" href="#" class="card-title">어묵볶음</a>
  <p class="card-text">가격 : <span class="price">4000</span></p>
  <p class="card-text comment">수량 : <span class="count">1</span></p>
  <button onclick="addToCart(this)">장바구니 넣기</button>
</div>

javascript

function addToCart(e){
  const menu = $(e).closest('div').find('a').text();
  let price_new = $(e).closest('div').find('.price').text();
  let count_new = $(e).closest('div').find('.count').text();
  let img_url = $(e).closest('div').siblings('img').attr('src');
  let price = 0;
  let count = 0;
  let index = 0; //새로운 메뉴가 들어갈 index (maxIndex + 1)
  let isSame = false; //중복되는 메뉴가 있는지
  let value = [];

  if (localStorage.length > 0) {
    for (let i = 1; i < localStorage.length+1; i++) {
      if (Number(index) < i) { //maxIndex 구하기
        let cartItem = JSON.parse(localStorage.getItem(i))
        index = cartItem.id;

        //menu 이름이 같으면 같은 메뉴
        if(JSON.stringify(cartItem.menu) === JSON.stringify(menu)){
          isSame = true;
          price = cartItem.price;
          count = cartItem.count;
          break;
        }
      }
    }
  }
  if (isSame === true) { //중복되는 물건이 장바구니에 있는 경우 price와 count만 바꿔준다
    value = {
      id: Number(index),
      menu: menu,
      price: Number(price) + Number(price_new),
      count: Number(count) + Number(count_new),
      img_url: img_url
    };
  } else { //새로운 메뉴인 경우 maxIndex + 1을 key로 하여 저장한다
    index = Number(index) + 1;
    value = {
      id: Number(index),
      menu: menu,
      price: Number(price_new),
      count: Number(count_new),
      img_url: img_url
    };
  }

  localStorage.setItem(index, JSON.stringify(value)); //localStorage에 저장
}

장바구니에서 localStorage에 저장된 내용 가져와서 보여주는 기능

<script>
  $(document).ready(function () {
  	showOrders();
  });

function showOrders(){
  let temp_html = ``;
  let menu = '';
  let price = 0;
  let count = 0;
  let index = 0;
  let img_url = '';
  let price_all = 0;
  if (localStorage.length > 0) {
    for (let i = 1; i < localStorage.length+1; i++) {
      let cartItem = JSON.parse(localStorage.getItem(i))
      index = cartItem.id;
      menu = cartItem.menu;
      price = cartItem.price;
      count = cartItem.count;
      img_url = cartItem.img_url;
      price_all += Number(price)
      temp_html += `
        <tr>
        <td>${index}</td>
        <td><img class="thumbnail" src="${img_url}" /></td>
        <td>${menu}</td>
        <td>${count}<button class="plus">+</buttn><button class="minus">-</button></td>
        <td>${price}원</td>
        <td>${price_all}원</td>
        </tr>
      `;
    }
  }

  $("#orderTable").append(temp_html)
}
</script>

개선할 사항:
1. 금액합계인 price_all은 마지막에만 따로 보여줄 것
2. 장바구니에서 + - 버튼으로 각 상품별 수량조절하거나 특정 메뉴 삭제하는 기능 추가 구현 필요

삭제기능

삭제버튼을 만들어 위쪽의 key값이 1인 메뉴를 장바구니에서 삭제하였더니 for문에서 에러가 발생.

i = 1부터 순서대로 도는데,
key값이 1인 메뉴가 사라지니 let cartItem = JSON.parse(localStorage.getItem(i)) 에 값이 없고, 그에 따라 뒤에 코드들에 에러 발생하는 것으로 보임.

장바구니에 데이터 넣는 코드에는 if문에 localStorage.getItem(i) !== null 라는 조건을 추가하고,
localStorage의 데이터를 가져와 장바구니에 담긴 메뉴들을 보여주는 코드에는 if문을 새로 하나 만들어 localStorage.getItem(i) !== null라는 조건을 추가했다.

그랬더니 또 다른 에러가 발생했는데, localStorage.length를 이용해 for문의 반복횟수를 결정하다보니 삭제에 따라 length값은 줄었는데 남아있는 key값은 2. length는 1이라 for문은 한번밖에 안 돌아서 key값이 2인 주문을 불러오지를 못했다.

대략 아래 네 가지 정도의 해결방법을 생각해봤다.
1. 반복문의 반복횟수를 localStorage.length가 아닌 다른 방식으로 구현해서 실제 값이 있는 데이터들만 불러오기
2. 삭제할 때 key값까지 다 삭제하지말고 value쪽만 삭제하는 방식 -> 목록에서 보이는 숫자도 따로 신경써주어야함
3. 아예 메뉴 하나당 key하나를 할당하지말고 장바구니라는 하나의 key에 value로 객체 안의 객체로 다 넣고, 생성이나 삭제 시 전체 객체를 불러와서 재정렬 후 다시 전부를 갱신시키는 방법
4. 삭제할 때 삭제 한 뒤 남은 데이터들을 불러와서 key값을 앞에서부터 채우도록 재정렬해서 넣는 코드를 짜서 같이 돌리기

4번째 방법을 우선 채택했다. key값을 낮은 숫자부터 순서대로 돌리는 for문이 양쪽(장바구니 담기와 삭제)에서 다 쓰이고 있어서, key값이 중간이 빈 채로 있으면 곤란하다.

function deleteMenu(e){
  //현재 버튼 누른 메뉴의 index값 불러와서 localStorage에서 삭제
  let del_index = $(e).closest('tr').find('.index').text();
  localStorage.removeItem(del_index);

  //localStorage의 남은 값들을 모두 불러와서 index를 앞쪽숫자부터 다시 부여해서 순서대로 재등록(index와 cart페이지의 for문이 정상적으로 돌도록)
  if (localStorage.length > 0) {
    //새로운 index를 앞에서부터 차례로 부여해주기 위한 j 변수 선언
    let j = 0;
    //+2인 이유: 0부터가 아닌 1부터 시작하므로 +1, 이미 지워진 하나때문에 값이 하나씩 밀려있으므로 getItem(i)가 끝까지 다 가려면 +1
    for (let i = 1; i < localStorage.length+2; i++) {
      if (localStorage.getItem(i) !== null) {
        j++;
        //전부 가져와서 그대로 재등록하기.(key, id값만 변경됨)
        let cartItem = JSON.parse(localStorage.getItem(i))
        //console.log(cartItem)
        let index = j;
        let id = Number(index);
        let menu = cartItem.menu;
        let price = cartItem.price;
        let count = cartItem.count;
        let img_url = cartItem.img_url;
        let value = {
          id: id,
          menu: menu,
          price: price,
          count: count,
          img_url: img_url
        };
        //지금 새로 등록하려는 데이터를 localStorage에서 삭제(삭제하지 않으면 중복으로 남아있게 됨)
        localStorage.removeItem(i);
        localStorage.setItem(index, JSON.stringify(value)); //localStorage에 저장
      }
    }
  }
  window.location.reload();
}

수량 +, - 기능

  1. + or - 버튼을 누르면 같은 함수인데, +1 or -1 값을 갖고 들어와서 그것에 따라 count값 변경
  2. price 총 가격 값도 개수에 따라 같이 변경되어야함
  3. 개수는 1개에서 더 내려갈 수 없음(0개 == 삭제)

HTML

<button onclick="updateCount(this,1)" class="plus">+</buttn><button onclick="updateCount(this,-1)" class="minus">-</button>

javascript

function updateCount(e, num){
  //현재 고치려고 하는 데이터의 index값 찾기
  let target = $(e).closest('tr').find('.index').text();
  //해당 index의 데이터 불러오기
  let cartItem = JSON.parse(localStorage.getItem(target))
  //가져온 데이터에서 수량값이 현재 1이거나 그 이하이고 마이너스버튼을 눌렀을 경우엔 안내메시지 띄우고 중단
  if(cartItem.count < 2 && num === -1){
    alert("수량은 최소 1개입니다. 삭제를 원하실 경우 삭제버튼을 이용해주세요.");
    return false;
  }
  //나머지는 그대로, 수량count과 가격price만 변경하여 기존 데이터를 삭제하고 다시 넣기
  let index = Number(target);
  let id = Number(index);
  let menu = cartItem.menu;
  //총 가격에서 개수를 나눠 단가를 계산한 뒤, num을 곱해 +인지 -인지 결정
  let price = cartItem.price + num*(cartItem.price/cartItem.count);
  let count = cartItem.count + num;
  let img_url = cartItem.img_url;
  let value = {
    id: id,
    menu: menu,
    price: price,
    count: count,
    img_url: img_url
  };

  localStorage.setItem(index, JSON.stringify(value)); //localStorage에 저장(덮어쓰기)
  window.location.reload();
}

튜터님께 질문할 것

profile
백엔드 개발자. 공동의 목표를 함께 이해한 상태에서 솔직하게 소통하며 일하는 게 가장 즐겁고 효율적이라고 믿는 사람.

0개의 댓글