스케줄러 HTML, CSS, JS 구현

  • by



수업시 JS실장을 위해 만든 스케줄러를 더 보완해 만들어 보았다.

기존의

그리고

를 사용하고 있던 HTML을 ul과 li, display flex로 했다.

CSS 상을 조금 디자인했다.

특히 버튼의 경우 코드펜에 올라온 것을 보고 사용… 시험해 보았다.

내용이 길어지거나 스케줄이 여러 개 있으면 디자인 요소를 손상시키기 때문에 오버플로 hidden 처리했다.

JS 기능은 수업에서 배운 것처럼

  1. 날짜란을 누르면 날짜 입력에 날짜가 들어가게 됩니다(캘린더 부분에 입력을 받습니다만, 요일의 한자는 해당하지 않음)
  2. 날짜가 포함된 일정을 입력하고 추가 버튼을 누르면 해당 날짜 아래에 일정이 추가됩니다.

  3. 추가된 스케줄은 e.target에 액세스하고 누르면 삭제됩니다.

클래스와 같은 기능이지만 HTML 구조가 완전히 다르기 때문에 querySelector를 사용하기가 어려웠습니다.

<!
DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>스케쥴러 구현</title> <!
-- Reset CSS --> <link href="https://cdn.jsdelivr.net/npm/[email protected]/reset.min.css" rel="stylesheet"> <!
-- Main CSS --> <link href="./calendar.css" rel="stylesheet"/> <!
-- Main JS --> <script defer src="./calendar.js"></script> </head> <body> <section class="calendar"> <h1 class="part__year-month">2023년 2월</h1> <hr/> <div class="part__week-day"> <ul class="week"> <li class="sunday">日</li> <li>月</li> <li>火</li> <li>水</li> <li>木</li> <li>金</li> <li class="saturday">土</li> </ul> <ul class="day"> <li class="sunday"></li> <li> </li> <li> </li> <li>1 </li> <li>2 </li> <li>3 </li> <li class="saturday">4 </li> </ul> <ul class="day"> <li class="sunday">5 </li> <li>6 </li> <li>7 </li> <li>8 </li> <li>9 </li> <li>10 </li> <li class="saturday">11 </li> </ul> <ul class="day"> <li class="sunday">12 </li> <li>13 </li> <li>14 </li> <li>15 </li> <li>16 </li> <li>17 </li> <li class="saturday">18 </li> </ul> <ul class="day"> <li class="sunday">19 </li> <li>20 </li> <li>21 </li> <li>22 </li> <li>23 </li> <li>24 </li> <li class="saturday">25 </li> </ul> <ul class="day"> <li class="sunday">26 </li> <li>27 </li> <li>28 </li> <li></li> <li></li> <li></li> <li class="saturday"></li> </ul> </div> </section> <section class="contents"> <div class="contents__date"> <input type="text" placeholder="날짜를 클릭하세요." /> <input type="text" placeholder="스케쥴을 입력해주세요."/> <button class="btn">추가</button> </div> </section> </body> </html>

section.calendar {
  position: relative;
  width: 75vw;
  box-shadow: 2px 2px 2px #744c0b;
  border: 1px solid #744c0b;
  margin: 30px auto;
}
section.calendar .part__year-month {
  font-size: 2.2rem;
  font-weight: 700;
  text-align: center;
  color: #bb8d43;
  padding: 50px 0 25px 0;
  text-shadow: 2px 2px 0 #513507;
  transition: all 0.5s ease;
}
section.calendar .part__year-month:hover {
  text-shadow: 0 0 0 #513507;
}

section.calendar hr {
  border: 0;
  border-top: solid 1px #DDD;
  border-color : #C4B5A2;
  width: 80%;

}
section.calendar hr:hover::before {
  transform: translateX(-10px);
}
section.calendar hr:hover::after {
  transform: translateX(10px) rotate(180deg);
}
section.calendar hr::before,
section.calendar hr::after {
  content: '';
  transition: .5s;
  position: absolute;
  top: 105px;
  width: 52px;
  height: 28px;
  background-color: white;
  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGgAAAAcBAMAAAB/gedFAAAAA3NCSVQICAjb4U/gAAAAMFBMVEX///+ii2yii2yii2yii2yii2yii2yii2yii2yii2yii2yii2yii2yii2yii2yii2xf+K23AAAAEHRSTlMAESIzRFVmd4iZqrvM3e7/dpUBFQAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAJoSURBVDiNnVS/b9NQED7HaRSrFLkqCCKeIAMDAwJ3QYHBBMYuKRtskVhRLaZWAqmBgjp0iCPEGg90bstEJ4IZYAlJ/wCqApYqtUS1gMiNm9THvTSJnRopJR7eD/s+f/e+7+4BtB/JhBM8TO/bFmvyYIxQ2QluJUs9ARWz1CBVUREHUwkVRQxQSRbAYCrGo3yqUwRgP/jqyfN/hV95x8drPOqDT1yWiZsWo4jZMCaGuEYTnYACA8wm5wbQXPV7GHTRMhw+qybrnWGcU3GiCORxrk5vLqe736J3acgsYgOSnIoTjXdyA7jOY4uKhrN/YEG03S7I8JQU3J5Fp61b5ncnHFjNJDVpKdUsqTm6IXm3cCt5hBEP8Y2tj62VdLWiUzz5wiomV3+yLDOLmcLKZOlZZHW6eHOvEe+cV8jl917tjBwkzzcndmVmqqZQnuBIi2RYUYTyVQvitr1Nnhkt+agWmS5UXfJmxvNyoH4sy+IuSUGOkgJChaRjHklx7uUlmiRsVlscVG2VUAfR/nX/MaVq049UohFrPsgmh6bWU/ksMFzPt6UwGktoQqzxYmmZ3PJ8UC+9hAMXWu/dmEMpRaI5Doqnk5SqljV+Vt+CVvDT6wkB+Yeb6TvzOe3pl4OpjnqR5dWvn534/pno5o0G+EL4khM/8xLfYq0EYlc9xEI1e7pgmzx7X/KAuY9kDRfrcE8obXfNnWnKZyEzh47wqc9cv4yAyuhBPVx7mddURtBXRsGCzbjzG2HQ2L5RP16wgdaI46ESBolbmINQa/hNmJoOYwBGFvh4rAmHavehLpbhrrChLsv/vJb/AvJXJlGPw7QyAAAAAElFTkSuQmCC);
	background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjEwNHB4IiBoZWlnaHQ9IjI4cHgiIHZpZXdCb3g9IjAgMCAxMDQgMjgiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDEwNCAyOCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8Zz4NCgkJPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiNBMjhCNkMiIGQ9Ik01NiAxMy44OWgwLjA4bDEuNzIgMS43M2wxLjU4LTEuMzZjMCAwIDIuNy0wLjA4IDMuMiAxLjEgYzAgMCAwLjcgMS4yMi0wLjkxIDEuNmMwIDAtMS40MiAwLjE1LTEuMzUtMS4xNGMwIDAtMS4yIDEuOCAxLjEgMi45NmMwIDAgMy4xIDAuOCAzLjM4LTIuNzNsMC40MiAwLjI4bDIuMDYgMi4wOGwzLjkxLTMuOTYgaDEuNzJ2LTAuNTlWMTMuOHYtMC42aC0xLjhsLTMuODMtMy44N2wtMS44MSAxLjgybC0wLjY3IDAuNDZjLTAuMy0zLjU3LTMuMzgtMi43My0zLjM4LTIuNzNjLTIuMzMgMS4xNC0xLjEzIDIuOTYtMS4xMyAzIGMtMC4wNy0xLjI5IDEuMzUtMS4xNCAxLjM1LTEuMTRjMS41OCAwLjQgMC45IDEuNiAwLjkgMS41OWMtMC40NiAxLjIyLTMuMTYgMS4xNC0zLjE2IDEuMTRsLTEuNTgtMS4zNmwtMS43MiAxLjczSDU2IGwwLjA0IDAuMDRMNTYgMTMuODl6IE02My45NiAxMy44OWwzLjMxLTMuMzRsMy4zIDMuMzRsLTMuMyAzLjMzTDYzLjk2IDEzLjg5eiIvPg0KCQk8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbD0iI0EyOEI2QyIgZD0iTTg0Ljg1IDUuMTJsNC4zOSA0LjQ0bC0zLjc5IDMuODNsLTQuNjYtNC41MSBjMCAwLTMuNjggNC4zMi01Ljg2IDMuMTljMCAwLTIuNjMtMC4wOC0yLjctMi45NmMwIDAgMC40NS0yLjgxIDIuMjUtMi4yOGMwIDAgMC42IDAuNjgtMC4yMyAxLjE0YzAgMC0xLjI3IDAuNjgtMC4yMiAyIGMwIDAgMSAxLjcgMi43IDAuMjJjMCAwIDEuMDUtMS4yMSAwLjQ1LTIuNzNjMCAwLTAuOS0yLjItMy4xNS0yLjA1YzAgMC0yLjMzIDAuMjMtMy4xNiAyLjc0YzAgMC0wLjE1IDIuNiAxLjYgMy45IGMwIDAgMS40IDEuNyA0LjUgMS4xM2wwLjMtMC4yM2MwLjgzLTAuMzQgMi4wMS0xLjA5IDMuNTMtMi43M2wzLjgzIDMuNjRsLTMuODMgMy42NGMtMS41Mi0xLjY0LTIuNy0yLjM5LTMuNTMtMi43M2wtMC4zLTAuMjMgYy0zLjA4LTAuNTMtNC41MSAxLjE0LTQuNTEgMS4xNGMtMS43MyAxLjIxLTEuNTggMy44Ny0xLjU4IDMuODdjMC44MyAyLjUgMy4yIDIuNyAzLjIgMi43M2MyLjI1IDAuMSAzLjE1LTIuMDUgMy4xNS0yLjA1IGMwLjYtMS41MS0wLjQ1LTIuNzMtMC40NS0yLjczYy0xLjczLTEuNTItMi43IDAuMjMtMi43IDAuMjNjLTEuMDUgMS40IDAuMiAyIDAuMiAyLjA1YzAuODMgMC41IDAuMiAxLjEgMC4yIDEuMSBjLTEuOCAwLjUzLTIuMjUtMi4yOC0yLjI1LTIuMjhjMC4wNy0yLjg4IDIuNy0yLjk2IDIuNy0yLjk2YzIuMTgtMS4xNCA1LjkgMy4yIDUuOSAzLjE5bDQuNTQtNC40bDMuOTEgMy45NWwtNC4zOSA0LjQgTDg5LjkyIDI4bDUuMDctNS4xMmwtNC40LTQuNDRsMy44My0zLjg3bDQuNTEgNC41NUwxMDQgMTRsLTUuMDctNS4xMmwtNC41MSA0LjU1bC0zLjgzLTMuODdsNC40LTQuNDRMODkuOTIgMEw4NC44NSA1LjEyeiBNODYuMiAyMi44OGwzLjcyLTMuNzZsMy43MSAzLjc2bC0zLjcxIDMuNzVMODYuMiAyMi44OHogTTg2LjIgMTRsMy43Mi0zLjc2TDkzLjYzIDE0bC0zLjcxIDMuNzZMODYuMiAxNHogTTk1LjIxIDE0bDMuNzItMy43NiBsMy43MiAzLjc2bC0zLjcyIDMuNzZMOTUuMjEgMTR6IE04Ni4yIDUuMTJsMy43Mi0zLjc1bDMuNzEgMy43NWwtMy43MSAzLjc2TDg2LjIgNS4xMnoiLz4NCgk8L2c+DQoJPGc+DQoJCTxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsPSIjQTI4QjZDIiBkPSJNNDggMTMuODloLTAuMDhsLTEuNzIgMS43M2wtMS41OC0xLjM2YzAgMC0yLjctMC4wOC0zLjE2IDEuMSBjMCAwLTAuNjcgMS4yIDAuOSAxLjZjMCAwIDEuNCAwLjEgMS4zNS0xLjE0YzAgMCAxLjIgMS44Mi0xLjEzIDIuOTZjMCAwLTMuMDggMC44My0zLjM4LTIuNzNsLTAuNDIgMC4yOGwtMi4wNiAyLjEgbC0zLjkxLTMuOTZIMzEuMXYtMC41OVYxMy44di0wLjZoMS44bDMuODMtMy44N2wxLjgxIDEuODJsMC42NyAwLjQ2YzAuMy0zLjU3IDMuMzgtMi43MyAzLjM4LTIuNzNjMi4zMyAxLjEgMS4xIDMgMS4xIDMgYzAuMDctMS4yOS0xLjM1LTEuMTQtMS4zNS0xLjE0Yy0xLjU4IDAuMzgtMC45MSAxLjU5LTAuOTEgMS41OWMwLjQ2IDEuMiAzLjIgMS4xIDMuMiAxLjE0bDEuNTgtMS4zNmwxLjcyIDEuNzNINDhsLTAuMDQgMCBMNDggMTMuODl6IE00MC4wNCAxMy44OWwtMy4zMS0zLjM0bC0zLjMgMy4zNGwzLjMgMy4zM0w0MC4wNCAxMy44OXoiLz4NCgkJPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiNBMjhCNkMiIGQ9Ik0xOS4xNSA1LjEybC00LjM5IDQuNDRsMy43OSAzLjgzbDQuNjYtNC41MSBjMCAwIDMuNyA0LjMgNS45IDMuMTljMCAwIDIuNjMtMC4wOCAyLjctMi45NmMwIDAtMC40NS0yLjgxLTIuMjUtMi4yOGMwIDAtMC42IDAuNyAwLjIgMS4xNGMwIDAgMS4zIDAuNyAwLjIgMiBjMCAwLTAuOTcgMS43NC0yLjcgMC4yMmMwIDAtMS4wNS0xLjIxLTAuNDUtMi43M2MwIDAgMC45LTIuMiAzLjE1LTIuMDVjMCAwIDIuMyAwLjIgMy4yIDIuNzRjMCAwIDAuMSAyLjY1LTEuNTggMy45IGMwIDAtMS40MyAxLjY2LTQuNTEgMS4xM2wtMC4zLTAuMjNjLTAuODMtMC4zNC0yLjAxLTEuMDktMy41My0yLjczbC0zLjgzIDMuNjRsMy44MyAzLjY0YzEuNTItMS42NCAyLjctMi4zOSAzLjUzLTIuNzNsMC4zLTAuMjMgYzMuMDgtMC41MyA0LjUgMS4xIDQuNSAxLjE0YzEuNzMgMS4yIDEuNiAzLjkgMS42IDMuODdjLTAuODMgMi41LTMuMTYgMi43My0zLjE2IDIuNzNjLTIuMjUgMC4xNS0zLjE1LTIuMDUtMy4xNS0yLjA1IGMtMC42LTEuNTEgMC40NS0yLjczIDAuNDUtMi43M2MxLjczLTEuNTIgMi43IDAuMiAyLjcgMC4yM2MxLjA1IDEuMzYtMC4yMiAyLjA1LTAuMjIgMi4wNWMtMC44MyAwLjQ1LTAuMjMgMS4xNC0wLjIzIDEuMSBjMS44IDAuNSAyLjI1LTIuMjggMi4yNS0yLjI4Yy0wLjA3LTIuODgtMi43LTIuOTYtMi43LTIuOTZjLTIuMTgtMS4xNC01Ljg2IDMuMTktNS44NiAzLjE5bC00LjU0LTQuNGwtMy45MSAzLjk1bDQuMzkgNC40IEwxNC4wOCAyOGwtNS4wNy01LjEybDQuNC00LjQ0bC0zLjgzLTMuODdsLTQuNTEgNC41NUwwIDE0bDUuMDctNS4xMmw0LjUxIDQuNTVsMy44My0zLjg3bC00LjQtNC40NEwxNC4wOCAwTDE5LjE1IDUuMTJ6IE0xNy44IDIyLjg4bC0zLjcyLTMuNzZsLTMuNzEgMy43NmwzLjcxIDMuNzVMMTcuOCAyMi44OHogTTE3LjggMTRsLTMuNzItMy43NkwxMC4zNyAxNGwzLjcxIDMuNzZMMTcuOCAxNHogTTguNzkgMTRsLTMuNzItMy43NiBMMS4zNSAxNGwzLjcyIDMuNzZMOC43OSAxNHogTTE3LjggNS4xMmwtMy43Mi0zLjc1bC0zLjcxIDMuNzVsMy43MSAzLjc2TDE3LjggNS4xMnoiLz4NCgk8L2c+DQo8L2c+DQo8L3N2Zz4=), none;
	background-repeat: no-repeat;
	background-position: 0 center;
}
section.calendar hr::before {
  left: 25px;
}
section.calendar hr::after {
  right : 25px;
  transform: rotate(180deg);
}

section.calendar .part__week-day {}

section.calendar .part__week-day .week {
  display: flex;
  justify-content: space-around;
  margin-top: 35px;
  margin-bottom: 40px;
}
section.calendar .part__week-day .week > li {
  font-size: 1.2rem;
  font-weight: 500;
}

section.calendar .part__week-day .day {
  display: flex;
  justify-content: space-around;
  margin: 20px 0;
}
section.calendar .part__week-day .day > li {
  font-size: 1rem;
  text-align: center;
  width: 80px;
  height: 80px;
  overflow: hidden;
}
section.calendar .part__week-day .day > li:hover {
  font-size: 1.2rem;
  font-weight: 600;
}
/* section.calendar .part__week-day .day > li .day__contents {
  width: 80px;
  height: 70px;
  overflow: hidden;
} */
section.calendar .part__week-day .day > li > div {
  padding: 4px 2px;
  margin: 4px auto;
  border: 1px solid #513507;
  border-radius: 4px;
  background-color: #513507;
  color: white;
  font-weight: 500;
  font-size: 0.8rem;
  width: 75px;
  height: 18px;
  line-height: 20px;
  overflow: hidden;
}

section.calendar .part__week-day .sunday {
  color : red;
}
section.calendar .part__week-day .saturday {
  color : blue;
}


section.contents {
  width: 50vw;
  margin: auto;
}
section.contents input {
  border-radius: 3px;
  padding: 10px 6px;
  font-size: 1rem;
}

section.contents .contents__date {
  margin-bottom: 30px;
  /* text-align: center; */
  position: relative;
}

section.contents .contents__date > input:first-child {
  width: 25%;
}
section.contents .contents__date > input:nth-child(2) {
  width :50%;
  border-color: #d59631;
  margin: 0 4px;
  transition: .4s;
}
section.contents .contents__date > input:nth-child(2):focus {
  background-color: #e2b46b;
  color: black;
  border-color: #d59631;
  outline: #744c0b;
}

section.contents .contents__date .btn {
  font-size: 1.2rem;
  background-color: #744c0b;
  color: white;
  padding: 1px 10px;
  position: absolute;

  right: 3px;
  width: 68px;
  z-index: 2;
  line-height: 40px;
  cursor: pointer;
}
section.contents .contents__date .btn:hover {
  border: none;
}
section.contents .contents__date .btn::before,
section.contents .contents__date .btn::after {
  position: absolute;
  content: "";
  width: 0%;
  height: 0%;
  border: 2px solid;
  z-index: -1;
  transition: all 0.4s ease;
}
section.contents .contents__date .btn::before {
  top: 0;
   left: 0;
   border-bottom-color: transparent;
   border-right-color: transparent;
   border-top-color: #000;
   border-left-color: #000;
}
section.contents .contents__date .btn::after {
  bottom: 0;
  right: 0;
  border-top-color: transparent;
  border-left-color: transparent;
  border-bottom-color: #000;
  border-right-color: #000;
}
section.contents .contents__date .btn:hover::before,
section.contents .contents__date .btn:hover::after {
  border-color: #000;
  height: 100%;
  width: 100%;
}

const dayItem = document.querySelector('.part__week-day');
const dateInputField = document.querySelector('.contents__date > input:first-child');

const addItem = document.querySelector('.day > li');
const textInputField = document.querySelector('.contents__date > input:nth-child(2)');
const addItemBtn = document.querySelector('.btn');

let curTarget;

// 날짜 입력
let clickDateInfo = function(e) {
  curTarget = e.target;
  let tmpDate;

  // 에러 해결- 텍스트 노드가 있을 때만
  if((e.target.childNodes(0) !
== undefined)) { tmpDate = `${e.target.childNodes(0).textContent.trim()}`; } else { return; } if(curTarget.tagName === "LI") { const dateNum = /(0-9)/; if(dateNum.test(tmpDate) === true) { dateInputField.value = `2023년 2월 ${tmpDate}일`; } } } dayItem.addEventListener('click', clickDateInfo); // 추가 버튼 let addItemLi = function(e) { if(textInputField.value === "") { textInputField.placeholder = "스케쥴 입력이 필요합니다.

"; return; } const contentsItem = document.createElement('div'); contentsItem.textContent = textInputField.value; contentsItem.addEventListener('click', function(e) { e.target.remove(); }); if(curTarget.tagName === "LI") { curTarget.appendChild(contentsItem); } textInputField.value = ""; } addItemBtn.addEventListener('click', addItemLi);

재미있지만 아직 힘들어요~

error: Alert: Content selection is disabled!!