Project 생성
책에서 보고 설치 했었던 CLI가 현재 버전보다 꽤 많이 낮아서 새로운 버전으로 교체를 하였다.
새 버전은 vue create로 프로젝트를 만들 수 있었는데 아직 이전 버전도 안 써봤으므로
이전 버전에서 제공하는 걸로 진행을 했다.
1 2 3 4
| npm uninstall vue-cli -g npm i @vue/cli -g npm i @vue/cli-init vue init webpack my_calendar_app
|
CSS
CSS 프레임워크를 쓰고 싶어서 bulma를 설치 했다.
글로벌 CSS는 src/App.vue에 import를 하면 되었다.
1 2 3 4 5 6 7
| <script> import "bulma/css/bulma.css";
export default { name: "App", }; </script>
|
.prettierrc.js
자동 줄맞춤으로 prettier를 쓰고 있는데 줄맞춤할 때마다 script에 ‘가 “로 변환 되고
마지막 ,가 사라져서 lint에 걸려 가지고 고통 받다가 검색을 통해 해결법을 찾음
.prettierrc.js 생성
1 2 3 4
| module.exports = { singleQuote: true, trailingComma: "all", };
|
달력 만들기
이전에 date-picker등은 자주 써봤으나 달력 구현은 이번이 처음이였다.
먼저 요일을 고정이니 반복문이 필요 했는데 v-for 지시자를 통해 테이블의 헤더에 삽입 하였다.
책에서 학습 할 때는 v-for만 적었었는데 key라는 속성을 안 넣어주면 lint 오류가 떴었다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <template> <section class="section"> <div class="container"> <table class="table has-text-centered is-fullwidth"> <thead> <th v-for="day in days" :key="day">{{ day }}</th> </thead> </table> </div> </section> </template>
<script> export default { data() { return { days: [ '일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일', ], } } } </script>
|
달력의 날짜들을 어떻게 구할지 고민을 하다가 이차원 배열에 1차 배열은 주로 잡고 2차 배열은
날짜들을 담으면 되겠다는 생각이 들었고 다른 캘린더를 보니 테이블에 그릴 때 1일이
어느 요일에서 시작 하는지 알아야 했으며 그 전에 남은 셀이 있다면 저번 달의 날짜들을
채웠어야 했고 마지막 주에 남은 셀이 있으면 다음 달의 날짜를 채웠어야 했다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| <template> <section class="section"> <div class="container"> <h2 class="subtitle has-text-centered"> {{ year }}년 {{ month }}월 </h2> <table class="table has-text-centered is-fullwidth"> <thead> <th v-for="day in days" :key="day">{{ day }}</th> </thead> <tbody> <tr v-for="(date, idx) in dates" :key="idx"> <td v-for="(day, secondIdx) in date" :key="secondIdx" > {{ day }} </td> </tr> </tbody> </table> </div> </section> </template>
<script> export default { data() { return { days: [ '일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일', ], dates: [], currentYear: 0, currentMonth: 0, year: 0, month: 0, }; }, created() { const date = new Date(); this.year = date.getFullYear(); this.month = date.getMonth() + 1; this.calendarData(); }, methods: { calendarData() { const [ monthFirstDay, monthLastDate, lastMonthLastDate, ] = this.getFirstDayLastDate(this.year, this.month); this.dates = this.getMonthOfDays( monthFirstDay, monthLastDate, lastMonthLastDate, ); }, getFirstDayLastDate(year, month) { const firstDay = new Date(year, month - 1, 1).getDay(); const lastDate = new Date(year, month, 0).getDate(); let lastYear = year; let lastMonth = month - 1; if (month === 1) { lastMonth = 12; lastYear -= 1; } const prevLastDate = new Date(lastYear, lastMonth, 0).getDate(); return [firstDay, lastDate, prevLastDate]; }, getMonthOfDays( monthFirstDay, monthLastDate, prevMonthLastDate, ) { let day = 1; let prevDay = (prevMonthLastDate - monthFirstDay) + 1; const dates = []; let weekOfDays = []; while (day <= monthLastDate) { if (day === 1) { for (let j = 0; j < monthFirstDay; j += 1) { weekOfDays.push(prevDay); prevDay += 1; } } weekOfDays.push(day); if (weekOfDays.length === 7) { dates.push(weekOfDays); weekOfDays = []; } day += 1; } const len = weekOfDays.length; if (len > 0 && len < 7) { for (let k = 1; k <= 7 - len; k += 1) { weekOfDays.push(k); } } if (weekOfDays.length > 0) dates.push(weekOfDays); return dates; }, }, }; </script>
|
특별할 거 없이 여전히 v-for만을 이용해서 달력을 그리기까지 완성 하였다.
이후에는 버튼을 통해 이전 달, 다음 달의 캘린더, 그리고 현재 달력의 오늘 날짜, 지난 달의
날짜, 다음 달의 날짜들은 색깔을 주고 싶어서 시도를 해 보았다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
| <template> <section class="section"> <div class="container"> <h2 class="subtitle has-text-centered"> <button class="button is-small is-primary is-outlined mr-5" @click="calendarData(-1)"><</button> {{ year }}년 {{ month }}월 <button class="button is-small is-primary is-outlined ml-5" @click="calendarData(1)">></button> </h2> <table class="table has-text-centered is-fullwidth"> <thead> <th v-for="day in days" :key="day">{{ day }}</th> </thead> <tbody> <tr v-for="(date, idx) in dates" :key="idx"> <td v-for="(day, secondIdx) in date" :key="secondIdx" :class="{ 'has-text-info-dark': idx === 0 && day >= lastMonthStart, 'has-text-danger': dates.length - 1 === idx && nextMonthStart > day, 'has-text-primary': day === today && month === currentMonth && year === currentYear }" > {{ day }} </td> </tr> </tbody> </table> </div> </section> </template>
<script> export default { data() { return { days: [ '일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일', ], dates: [], currentYear: 0, currentMonth: 0, year: 0, month: 0, lastMonthStart: 0, nextMonthStart: 0, today: 0, }; }, created() { const date = new Date(); this.currentYear = date.getFullYear(); this.currentMonth = date.getMonth() + 1; this.year = this.currentYear; this.month = this.currentMonth; this.today = date.getDate(); this.calendarData(); }, methods: { calendarData(arg) { if (arg < 0) { this.month -= 1; } else if (arg === 1) { this.month += 1; } if (this.month === 0) { this.year -= 1; this.month = 12; } else if (this.month > 12) { this.year += 1; this.month = 1; } const [ monthFirstDay, monthLastDate, lastMonthLastDate, ] = this.getFirstDayLastDate(this.year, this.month); this.dates = this.getMonthOfDays( monthFirstDay, monthLastDate, lastMonthLastDate, ); }, getFirstDayLastDate(year, month) { const firstDay = new Date(year, month - 1, 1).getDay(); const lastDate = new Date(year, month, 0).getDate(); let lastYear = year; let lastMonth = month - 1; if (month === 1) { lastMonth = 12; lastYear -= 1; } const prevLastDate = new Date(lastYear, lastMonth, 0).getDate(); return [firstDay, lastDate, prevLastDate]; }, getMonthOfDays( monthFirstDay, monthLastDate, prevMonthLastDate, ) { let day = 1; let prevDay = (prevMonthLastDate - monthFirstDay) + 1; const dates = []; let weekOfDays = []; while (day <= monthLastDate) { if (day === 1) { for (let j = 0; j < monthFirstDay; j += 1) { if (j === 0) this.lastMonthStart = prevDay; weekOfDays.push(prevDay); prevDay += 1; } } weekOfDays.push(day); if (weekOfDays.length === 7) { dates.push(weekOfDays); weekOfDays = []; } day += 1; } const len = weekOfDays.length; if (len > 0 && len < 7) { for (let k = 1; k <= 7 - len; k += 1) { weekOfDays.push(k); } } if (weekOfDays.length > 0) dates.push(weekOfDays); this.nextMonthStart = weekOfDays[0]; return dates; }, }, }; </script>
|
클래스를 제어하기 위해서는 :class 지시자를 사용 했다.
오늘 날짜는 별도로 가지고 있다가 해당 조건일 때만 색을 변경 하였고, 현재 달력에서 지난 달의
날짜는 첫 주에서만 가지고 있으니 첫 주의 제일 작은 수를 가지고 있다가 그 수보다 큰 경우에만
색을 변경해 주었고 마찬가지로 현재 달력에서 다음 달의 날짜는 마지막 주에서 0번째의 날짜를
가지고 있다가 그 수보다 작은 경우에만 색을 변경해 주었다.
다음 목표로는 일정을 추가 하고 볼 수 있게 만들어 봐야 겠다.
참고
[Vue.JS] Vue-CLI 3 시작하기
Single quotes are being replaced with double quotes