• 로그인
  • 장바구니에 상품이 없습니다.

home2 게시판 JavaScript, TS 게시판 웹개발 기능대회: 검색후 나온 상품목록의 drag 이벤트

웹개발 기능대회: 검색후 나온 상품목록의 drag 이벤트

6 글 보임 - 1 에서 6 까지 (총 6 중에서)
  • 글쓴이
  • #73324

    김진선
    참가자
    검색기능을 통해 나온 상품목록을 drag해서 장바구니에 넣으면 1개씩이 아니라 2개씩 들어가게 되네요.
    콘솔로 확인해 보니 이벤트가 2번씩 발생하더라구요. '담기'버튼으로 넣으면 1개씩 잘 들어가는데 drag만 하면 
    2개씩 들어가는 이유를 전혀 모르겠습니다..ㅠ,.ㅠ
    
    

     

    //===========================
    //상품진열기능
    //===========================
    const productList = document.querySelector('.product-list');
    const cartList = document.querySelector('.cart-list');
    const purchase = document.querySelector('.purchase');
    const totalPrice = document.querySelector('#final-price');
    const modal1 = document.querySelector('.modal1');
    const modal2 = document.querySelector('.modal2');
    const search = document.querySelector('#search');
    let products = [];
    let cart = [];
    //===========================
    //상품진열기능
    //===========================
    fetch('./data/store.json')
      .then((res) => res.json())
      .then((data) => {
        products = data.products;
        for (let i = 0; i < products.length; i++) {
          const template = `
          <li class="item" draggable="true" data-id='${products[i].id}'> 
            <div class="image">
              <img " src="./images/${products[i].photo}" alt="${products[i].title}">
            </div>
            <div class="item-title">${products[i].title}</div>
            <div class="item-brand">${products[i].brand}</div>
            <div class="item-price">가격:<span>${products[i].price}</span></div>
            <button class="btn btn-primary btn-dark" type="submit" id="addProduct">담기</button>
          </li>
          `;
          productList.insertAdjacentHTML('beforeend', template);
        }
        //========================
        //담기버튼 클릭
        //========================
        productList.addEventListener('click', function (e) {
          checkDuplId(e);
          //담기버튼 누를 때 마다 장바구니 박스에 let cart 안에 있던 {} 갯수만큼 html 생성
          cartList.innerHTML = '';
          cart.forEach((a) => {
            const template = `
                <li class="item" draggable="true" data-id='${a.id}'> 
                  <div class="image">
                    <img " src="./images/${a.photo}" alt="${a.title}">
                  </div>
                  <div class="item-title">${a.title}</div>
                  <div class="item-brand">${a.brand}</div>
                  <div class="item-price">가격:<span>${a.price}</span></div>
                  <input type="number" value="${a.count}" class="item-count w-100">
                </li>
              `;
            cartList.insertAdjacentHTML('beforeend', template);
          });
          //총가격 계산해서 표기해주는 기능
          calculatePrice();
          //input값 조절해도 총가격 계산해서 표기해줘야될듯
          document.querySelectorAll('.item-count').forEach((a) => {
            a.addEventListener('input', () => {
              calculatePrice();
            });
          });
        });
        //===================
        //.item 드래그로 장바구니에 추가기능
        //===================
        dragItems();
      });
    //========================
    //담기버튼 누르면 일어날 일들
    //========================
    function checkDuplId(e) {
      let productId;
      if (e.target.id === 'addProduct') {
        //지금누른 상품번호
        productId = e.target.parentElement.dataset.id;
      }
      // arr.findIndex(callback), 반환 타입 number, 없다면 -1
      // 담기버튼 누를 때 let cart = [] 에 상품을 {} 형태로 보관부터하고
      // let cart에 상품이 이미있는지 찾고 없으면 let cart에 {}추가, 있으면 수량만 ++;
      let arrNum = cart.findIndex((a) => {
        return a.id == productId;
      });
      if (arrNum == -1) {
        let curItem = products.find((a) => {
          return a.id == productId;
        });
        curItem.count = 1;
        cart.push(curItem);
      } else {
        cart[arrNum].count++;
      }
    }
    //===================
    //.item 드래그로 장바구니에 추가기능
    //===================
    function dragItems() {
      const items = document.querySelectorAll('.item');
      items.forEach((item) => {
        item.addEventListener('dragstart', (e) => {
          e.dataTransfer.setData('id', e.target.dataset.id);
        });
      });
      cartList.addEventListener('dragover', (e) => {
        e.preventDefault();
      });
      cartList.addEventListener('drop', (e) => {
        let productId = e.dataTransfer.getData('id');
        //여기서 장바구니 추가기능 똑같이 만들면 되는데
        //귀찮아서 그냥 $('.add')버튼 강제 클릭으로 대체함
        document.querySelectorAll('#addProduct')[productId].click();
      });
    }
    //===========================
    // 최종가격 계산
    //===========================
    function calculatePrice() {
      const itemPrice = document.querySelectorAll('.item-price span');
      const itemCount = document.querySelectorAll('.item-count');
      let finalPrice = 0;
      for (let i = 0; i < itemCount.length; i++) {
        let price = itemPrice[i].innerText;
        let count = itemCount[i].value;
        finalPrice += parseFloat(price * count);
      }
      totalPrice.innerHTML = `${finalPrice}`;
    }
    //===========================
    //주문 누르면 뜨는 모달창, 영수증 기능
    //===========================
    //최하단 주문버튼 누르면 모달창1 띄우는 기능
    purchase.addEventListener('click', (e) => {
      if (e.target.id === 'buy-btn') {
        document.querySelector('.modal1').style.display = 'block';
      } else if (e.target.id === 'clear-btn') {
        cartList.innerHTML = '';
        cart = [];
        totalPrice.innerHTML = '';
      }
    });
    //모달창1에 뭐 입력하면 전역변수에 저장해둠
    let fullname = '';
    let phone = '';
    modal1.addEventListener('input', (e) => {
      if (e.target.id === 'name') {
        fullname = document.querySelector('#name').value;
      } else if (e.target.id === 'phone') {
        phone = document.querySelector('#phone').value;
      }
    });
    //모달창1의 완료버튼 누르면 모달창2 (영수증) 보여줌
    //거기안엔 canvas태그로 그림그려줌
    modal1.addEventListener('click', (e) => {
      if (e.target.id === 'receipt') {
        modal1.style.display = 'none';
        modal2.style.display = 'block';
        let canvas = document.querySelector('#canvas');
        let c = canvas.getContext('2d');
        c.font = '16px dotum';
        c.fillText('구매자: ' + fullname, 20, 30);
        c.fillText('연락처: ' + phone, 20, 60);
        c.fillText('--------------------------------------', 20, 90);
        cart.forEach((a, i) => {
          c.fillText(`${a.title}`, 20, 120 + i * 30);
          c.fillText(`${a.count}`, 220, 120 + i * 30);
          c.fillText(`${a.price}`, 280, 120 + i * 30);
        });
        c.fillText(
          '--------------------------------------',
          20,
          120 + cart.length * 30
        );
        c.fillText('총 구매가격: ', 20, 150 + cart.length * 30);
        c.fillText(`${totalPrice.innerText}`, 280, 150 + cart.length * 30);
        //상품명들 보여주려면 장바구니 상품만큼 c.fillText() 하면 되겠군요
      } else if (e.target.className === 'close') {
        modal1.style.display = 'none';
      }
    });
    modal2.addEventListener('click', function (e) {
      if (e.target.className === 'close') {
        modal2.style.display = 'none';
      }
    });
    //===========================
    //검색기능
    //===========================
    search.addEventListener('keyup', function (e) {
      let keyword;
      if (e.key === 'Enter') {
        keyword = search.value;
        //지금입력한 글자가 제목에 있으면 let products에서 검색어있는 것만 남기기
        let newProducts = products.filter((a) => {
          return a.title.includes(keyword) || a.brand.includes(keyword);
        });
        productList.innerHTML = '';
        if (newProducts.length === 0) {
          productList.innerHTML = '찾으시는 상품이 없습니다.';
        }
        newProducts.forEach((a) => {
          const template = `
          <li class="item" draggable="true" data-id='${a.id}'>
            <div class="image">
              <img " src="./images/${a.photo}" alt="${a.title}">
            </div>
            <div class="item-title">${a.title}</div>
            <div class="item-brand">${a.brand}</div>
            <div class="item-price">가격:<span>${a.price}</span></div>
            <button class="btn btn-primary btn-dark" type="submit" id="addProduct">담기</button>
          </li>
          `;
          productList.insertAdjacentHTML('beforeend', template);
        });
        dragItems();
      }
      changeKeyword(keyword);
    });
    function changeKeyword(keyword) {
      const title = document.querySelectorAll('.item-title');
      const brand = document.querySelectorAll('.item-brand');
      title.forEach((a) => {
        a.innerHTML = a.innerHTML.replaceAll(
          keyword,
          `<span style="background : yellow">${keyword}</span>`
        );
      });
      brand.forEach((a) => {
        a.innerHTML = a.innerHTML.replaceAll(
          keyword,
          `<span style="background : yellow">${keyword}</span>`
        );
      });
    }
     
    #73327

    codingapple
    키 마스터
    드래그후엔 cart 변수에 수량이 의도대로 잘 추가되고있나 출력부터 해봅시다
     
    #73343

    김진선
    참가자
    cart 변수에 수량이 2개가 들어가 있습니다..ㅠ,.ㅠ
    
    
    
    #73367

    codingapple
    키 마스터
    curItem 변수도 cart변수에 집어넣기 전에 출력도 해봅시다 
    2번출력되는게 수상해보이는데 이벤트리스너도 2번실행되는건 아닌가 확인합시다
    #73429

    김진선
    참가자
    애플코딩님 drop이벤트리스트너가 2번 실행되는걸 확인했고 왜 2번실해되나 봤더니
    아무래도 이벤트 버블링문제 같았습니다.
    e.stopPropagation()을 사용했더니 여전히 2번 실행되어서 e.stopImmediatePropagation()을 사용했더니
    1번만 실행되네요. 솔직히 아직도 왜 이러는지 딱 이해는 안가네요..ㅠ,ㅠ
    
    
    cartList.addEventListener('drop', (e) => {
        e.stopImmediatePropagation();
        let productId = e.dataTransfer.getData('id');
        document.querySelectorAll('#addProduct')[productId].click();
      });
    #73446

    codingapple
    키 마스터
    드롭하는 곳에 쓸데없는 박스같은게 하나 더 있어서 그럴 수도 있습니다
6 글 보임 - 1 에서 6 까지 (총 6 중에서)
  • 답변은 로그인 후 가능합니다.

About

현재 월 700명 신규수강중입니다.

  (09:00~20:00) 빠른 상담은 카톡 플러스친구 코딩애플 (링크)
  admin@codingapple.com
  이용약관, 개인정보처리방침
ⓒ Codingapple, 강의 예제, 영상 복제 금지
top

© Codingapple, All rights reserved. 슈퍼로켓 에듀케이션 / 서울특별시 강동구 고덕로 19길 30 / 사업자등록번호 : 212-26-14752 온라인 교육학원업 / 통신판매업신고번호 : 제 2017-서울강동-0002 호 / 개인정보관리자 : 박종흠