클론코딩해보기/TodoList

[Todo list] 08. 모달 창

js0616 2024. 8. 20. 22:44

목록 구현

  • 수정버튼을 눌렀을때 수정모달이 띄워져야 한다.

모달 구현

  • 할일 / 진행중에 수정버튼 또는 아이콘을 누르면 모달창이 떠야한다.
  • 모달창은 X 버튼을 누르거나 모달 바깥영역을 선택하거나 키보드의 ESC 를 누르면 닫혀야 한다.
  • 모달창은 입력폼과 동일하게 제목과 내용이 입력가능하다.
  • 각 입력창에는 수정하기 이전의 티켓 내용이 입력되어 있어야 한다.
  • validator 나 시간은 입력폼과 동일한 스펙을 갖는다.

모달이란?? 

-> 기존 페이지 위에 검은배경 깔리고, 집중하게 페이지 작은거 하나 보여주는것.  css 로 다른거 못누르게 만드는것.. 

 

모달은 어떻게 만드는 걸까..? 

방법 1. display 속성을 block none 을 조절하는 방법

방법 2. state 를 관리하여 모달을 보여주거나 사라지게 함 .

--> state 비슷한걸 쓰고있으니 2번방법으로 진행

 

모달은 어디를 기준으로 어떻게 생겨야 될까?.. 

각 Item 에 따라 '모달' 버튼 클릭시 모달창이 떠야된다. 

-> Item에 새로운 속성 Modal 을 설정하고 true /false 로 관리 (토글같은느낌) 

div 하나 만들고 해당 dom 에 < ItemModal.js > 컴포넌트가 생기거나 안생기거나로 하면될꺼 같다. 

 

       {
          seq: 1,
          title: '선배!!',
          contents: '마라탕 사주세요',
          date: '2024.08.17. 02:43:00',
          workState: 'wait',
          write: false,
          modal: false,
        },

 

<Item.js> 에서 modal : true 일때 해당 컨포넌트를 생성하여 보여주도록 함. 

 mounted() {
    const { item, updateItem, currentTime } = this.props;
    item.modal
      ? new ItemModal(
          this.$target.querySelector(`[data-Item${item.seq}] .modalBox`),
          {
            item: item,
            updateItem: updateItem,
            currentTime: currentTime,
          },
        )
      : '';
  }

 

 

// src/components/ItemModal.js

import Component from '../core/Component.js';

export default class ItemModal extends Component {
  template() {
    const { item } = this.props;
    return `
        <div class=mdInnerBox>
          <span class='mdCloseBtn'> X </span>
          <div>
            <b> No. ${item.seq} </b>
          </div>
          <div>
            제목
            <input class ='mdTitle' value = '${item.title}' >
          </div>
          <div>
            내용
            <input class ='mdContents' value = '${item.contents}' >
          </div>
          <div class='error'></div>
          <div>
            상태 : ${item.workState == 'wait' ? '대기중' : '진행중'}
          </div>
          <div>
            작성일 : ${item.date}
          </div>

          <div class ='mdBtn'>
            <button class='mdupBtn'>수정</button>
          </div>
        </div>
    `;
  }

  setEvent() {
    const { item, updateItem, currentTime } = this.props;

    // X 버튼 , 배경 클릭시 모달 닫힘
    this.addEvent('click', '.mdCloseBtn, .modalBox', e => {
      // 내부 모달 클릭시에는 동작 안하도록
      ['modalBox', 'mdCloseBtn'].includes(e.target.classList.value)
        ? updateItem(item.seq, { modal: false })
        : '';
    });

    // 수정 버튼 클릭시
    this.addEvent('click', '.mdupBtn', () => {
      // dom
      let title = document.querySelector(
        `[data-Item${item.seq}] .mdTitle`,
      ).value;
      let contents = document.querySelector(
        `[data-Item${item.seq}] .mdContents`,
      ).value;
      let error = document.querySelector(`[data-Item${item.seq}] .error`);

      // 로직
      if (title == '' || contents == '') {
        error.innerHTML = '입력 값을 확인해 주세요';
      } else {
        updateItem(item.seq, {
          title: title,
          contents: contents,
          modal: false,
          date: currentTime(),
        });
      }
    });
  }
}

 

 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        /* 임시 스타일 */
        .itemList>div {
            margin: 10px;
            padding: 10px;
            border: 1px solid;
            width: 400px
        }

        .modalBox {
            /* 검은색 배경 */
            width: 100%;
            height: 100%;
            position: fixed;
            top: 0;
            left: 0;
            /* mdInnerBox 의 위치 조정 */
            display: flex;
            justify-content: center;
            align-items: center;
            background: rgba(0, 0, 0, 0.5);
        }
        .mdInnerBox{
            width: 500px;
            height: 250px;
            background-color: white;
            padding: 50px 50px;
            font-size: 28px;
            display: flex;
            flex-direction: column;
            /* 'X' 위치 조정 */
            position: relative;
        }
        .mdInnerBox input {
            font-size: 26px;
        }

        .mdInnerBox .mdCloseBtn{
            top : 10px;
            right : 20px;
            text-align: right;
            cursor: pointer;
            position: absolute;
        }

    </style>
</head>

<body>
    <div id="app"></div>


    <!-- build 전에 확인용 -->
    <script src="./js/main.js" type="module"></script>
</body>

</html>

 

기존에 했던 update 랑 유사한듯하다.. 

 

 

목록 구현

  • 수정버튼을 눌렀을때 수정모달이 띄워져야 한다.

모달 구현

  • 할일 / 진행중에 수정버튼 또는 아이콘을 누르면 모달창이 떠야한다.
  • 모달창은 X 버튼을 누르거나 모달 바깥영역을 선택하거나 키보드의 ESC 를 누르면 닫혀야 한다.
  • 모달창은 입력폼과 동일하게 제목과 내용이 입력가능하다.
  • 각 입력창에는 수정하기 이전의 티켓 내용이 입력되어 있어야 한다.
  • validator 나 시간은 입력폼과 동일한 스펙을 갖는다. ... ?

 

키보드의 ESC 를 누르면 닫혀야 한다.

--> 음... Item 에서 모달 클릭시 focus 이동 후 

    // esc 누를때, 모달 닫기
    this.addEvent('keyup', '.modalBox', e => {
      // console.log(e.key);
      if (e.key == 'Escape') {
        updateItem(item.seq, { modal: false });
      }
    });

 

 

 

https://github.com/js0616/todoList