안녕하세요

1주차 과제 장바구니(완료) - 모달창 다음 단계로, 드래그 기능 본문

복습스터디과제

1주차 과제 장바구니(완료) - 모달창 다음 단계로, 드래그 기능

sakuraop 2023. 1. 18. 01:59

[1주차 과제 장바구니 사이트] (2023-01-13 ~ 2023-01-18 약 일주일)

 

React App

 

youngentry.github.io

 

 


Point. 확장성을 고려한 설계

모달 stage별로 다음 단계로 넘어가기 위한 조건은 모두 다르기 때문에 

stage각각에 필요한 함수를 만드는 것이 아닌,

검사할 조건을 전달하여 true면 다음 단계로 넘어가도록 합니다.

 

ex) 

0 => 1

nextStage(구매금액검사함수, stage+1)

1 => 2

nextStage(개인정보입력검사함수, stage+1)

2 => 3

nextStage(결제검사함수, stage+1)


모달창 다음 단계로 넘기기

=> 장바구니에 제품을 담고 구매하기 버튼을 누르면 모달창을 띄웁니다.

 

 

=> 개인정보를 입력하고 다음으로 버튼을 클릭하면 영수증 단계로 넘어갑니다. 

 

 

=> 이전으로 버튼을 클릭하면 개인정보입력 단계로 되돌아갑니다.

 

 

1) 여러 단계가 존재할 것을 고려해 stage별로 다른 창을 보여줍니다.

  const [modalStage, setModalStage] = useState(0);

=> 단계별로 보여줄 화면을 설계합니다.

0: 모달창 없음

1: 개인정보입력 모달

2: 영수증 모달

 

 

          <div className={`modal show infoModal ${modalStage === 1 ? "stageVisible" : "stageInvisible"}`}>

=> 0이면 모달창이 보이지 않음

=> 1이면 개인정보 모달이 나타나기

 

          <div className={`modal show receiptModal ${modalStage === 2 ? "stageVisible" : "stageInvisible"}`}>

=> 2면 영수증 모달이 나타나기

.stageVisible {
  display: block;
}
.stageInvisible {
  display: none;
}

 

2) 버튼 클릭하면 stage를 바꾸는 함수 적용하기

                <Button
                  onClick={() => {
                    openBuyModal();
                    setModalStage(1);
                  }}
                  variant="primary"
                >
                  구매하기
                </Button>

=> 구매하기 버튼을 클릭하면 modalStage가 1이 됩니다.

 

                <Button
                  variant="primary"
                  onClick={() => {
                    flipModalStage(modalStage);
                  }}
                >
                  다음으로
                </Button>

=> 다음으로 버튼을 클릭하면 modalStage가 2가 됩니다.

 

                <Button variant="secondary" onClick={() => setModalStage(1)}>
                  이전으로
                </Button>

=> 이전으로 버튼을 클릭하면 modalStage가 1이 됩니다.

 

3) 개인정보 입력이 되어있지 않다면 다음 단계로 넘어가지 않도록 검사하기

flipModalStage 함수를 만들어 첫번째 인자로는 입력 검사 함수,

두번째 인자로는 modalStage를 전달하도록 합니다.

                <Button
                  variant="primary"
                  onClick={() => {
                    flipModalStage(isValidateInfo, modalStage);
                  }}
                >
                  다음으로
                </Button>

 

입력 검사함수는 문제가 있다면 alert창을 띄우고,

문제가 없다면 true를 반환하도록 합니다.

  // ----- 제출 시 입력값 검사하기 -----
  // input 창이 비어있으면 다음단계로 넘어가지 않고 focus 해주도록 함
  const nameInputRef = useRef();
  const phoneInputRef = useRef();

  const isValidateInfo = () => {
    if (name === "") {
      window.alert("이름을 입력해주세요.");
      return nameInputRef.current.focus();
    }
    if (phoneNumber.length < 10) {
      window.alert("올바른 전화번호를 입력해주세요. : 10자리 미만");
      return phoneInputRef.current.focus();
    }
    return true;
  };
  // ----- 제출 시 입력값 검사하기 -----

 

flipModalStage 함수에 입력 검사 함수를 전달하고, 

조건문을 통해서 문제가 없다면 modalStage를 +1 하도록 합니다.

  // ----- 모달창 다음 단계로 넘기기 -----
  const flipModalStage = (validateInput, stage) => {
    const validation = validateInput();
    if (validation) {
      setModalStage(stage + 1);
    }
  };
  // ----- 모달창 다음 단계로 넘기기

드래그 기능 구현

1) 드래그를 시작할 대상을 선택합니다. onDragStart

                      <Card 
                      className="itemCard" 
                      data-id={data.id} 
                      key={data.id} 
                      style={{ width: "18rem" }} 
                      onDragStart={(e) => e.dataTransfer.setData("id", data.id)}>

=> e.dataTransfer.setData("전달할 값을 담을 변수이름", 변수에 할당할 값)

 

onDragStart={(e) => e.dataTransfer.setData("id", data.id)}

=> "id"에 제품 id를 담습니다.

 

2) 드래그하여 놓은 지점을 선택합니다. onDrageOver, onDrop

              <ListGroup.Item
                onDragOver={(e) => e.preventDefault()}
                onDrop={(e) => {
                  let productId = parseInt(e.dataTransfer.getData("id"));
                  addItemIntoCartList(productId);
                }}
              >

=> onDragOver() 이벤트에 e.preventDefalut()를 적용합니다. (필수 조건)

=> onDrop() 이벤트에는 전달받은 id를 이용해서 수행할 함수를 넣어줍니다.

 

                  let productId = parseInt(e.dataTransfer.getData("id"));

=> 드래그 데이터에 담긴 아이디를 productId에 할당합니다. 

=> 변수에 저장되는 데이터는 String 이기 때문에 parseInt함수를 이용하여 id를 int 형으로 변환합니다.

 

                  addItemIntoCartList(productId);

=> productId를 장바구니에 추가 함수에 전달합니다.

 

3) 드래그하여 장바구니에 담기는지 확인하기

=> 사진을 끌어다 장바구니에 가져다 놓습니다.

 

=> 장바구니에 아이템이 추가됩니다.

 

아마도...

드래거블한 객체는 img 뿐이었습니다.

"Red Knit"와 같은 span 태그

"장바구니에 추가"와 같은 button 태그는 불가능 하였습니다.

 

4) 지정 객체를 통째로 드래그할 수 있는 객체로 만들기 draggable="true"

                      <Card 
                      className="itemCard" 
                      data-id={data.id} 
                      key={data.id} 
                      style={{ width: "18rem" }} 
                      onDragStart={(e) => e.dataTransfer.setData("id", data.id)} 
                      draggable="true">

=> draggable="true" 속성을 드래그하고자 하는 객체에 추가합니다.

 

=> 와우. 선택한 객체가 통째로 드래그 됩니다.

 

하지만 여전히 사진을 끌면 사진만 딸려옵니다.

=> 사진에 draggable="false"를 적용하면 되지 않을까요.

바로 해봅시다.

                        <Card.Img 
                        variant="top" 
                        src={`https://codingapple1.github.io/shop/shoes${data.id + 1}.jpg`} 
                        draggable="false" />

 

사진을 드래그 해봤더니 통째로 딸려옵니다.


추가로 시도해볼 만한 것들...

1) 드래그 중일 때 드래그 대상 객체 강조하는 css 설정

2) 드랍 지점에 마우스가 놓여 있을 때 "OOO 제품 장바구니에 추가하기"로 나타내기

3) 추가된 제품을 1초간 강조하는 css 설정