일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 미지아
- 국민을 위한 국민연금은 없다
- 코란도스포츠
- 싸이클
- MTB
- 남자육아휴직
- 2024년 합계출산율
- 청주시 지하철
- 중고노트북
- 도로패임
- 픽업트럭
- 저출산
- 대한민국선거
- 자전거
- 감나무전지
- 데이터시각화
- 파리브레스트파리
- 오프로드
- 샤오미
- 액티언스포츠
- 가칭 동남고등학교
- 청주시 일반계 고등학교
- 인공지능
- 육아휴직급여
- 엔진오일
- 콜로라도
- 40대아빠육아
- 준연동형비례대표
- 전동전기톱
- 아빠육아
Archives
- Today
- Total
열심히 일한 당신 떠나라
vue.js 프로젝트: 일정 관리가 포함된 홈페이지 만들기 본문
vue.js를 공부한 다음 인공지능 chatGPT 4o를 사용해서 만들어보았다. 역시 공부하기 전에는 기본 구조부터 프로그램의 돌아가는 원리를 잘 이해하지 못해 gpt를 사용해도 만들지 못했을 것이다. 공부한 후에는 구조와 원리를 파악한 후 수정할 부분을 파악할 수 있었고 익스플로어나 크롬에 있는 개발자 도구를 사용해 버그도 찾아낼 수 있었다.
우선 재사용 가능한 컴포넌트를 만드는데 집중하였고, 그 컴포넌트를 여기저기 쓸 수 있게 되었다. 스케쥴 등록, 수정, 삭제가능한 컴포넌트를 만들었고 그 다음 캘린더 컴포넌트를 붙이고 emit 명령어를 사용하여 연결하였다. 이 과정에서 개발자 도구를 사용하여 에러를 찾아서 수정하였다. 특별히 데이터베이스를 사용하지 않고 로컬 저장소를 사용하여 아주 간단한 로직을 구현하였다.
Calendar.vue
<template>
<div class="calendar">
<div class="header">
<button @click="prevMonth">Prev</button>
<h2>{{ monthNames[currentMonth] }} {{ currentYear }}</h2>
<button @click="nextMonth">Next</button>
</div>
<div class="weekdays">
<div v-for="day in weekDays" :key="day">{{ day }}</div>
</div>
<div class="days">
<div
v-for="day in daysInMonth"
:key="day.date ? day.date.toDateString() : day.index"
:class="{'today': isToday(day.date), 'has-event': hasEvent(day.date)}"
>
<span v-if="day.date">{{ day.date.getDate() }}</span>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
events: Array
},
data() {
return {
currentDate: new Date(),
currentMonth: new Date().getMonth(),
currentYear: new Date().getFullYear(),
weekDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
monthNames: [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
]
};
},
computed: {
daysInMonth() {
const days = [];
const firstDay = new Date(this.currentYear, this.currentMonth, 1).getDay();
const lastDate = new Date(this.currentYear, this.currentMonth + 1, 0).getDate();
for (let i = 0; i < firstDay; i++) {
days.push({ date: null, index: `empty-${i}` });
}
for (let date = 1; date <= lastDate; date++) {
days.push({ date: new Date(this.currentYear, this.currentMonth, date) });
}
return days;
}
},
methods: {
prevMonth() {
if (this.currentMonth === 0) {
this.currentMonth = 11;
this.currentYear--;
} else {
this.currentMonth--;
}
},
nextMonth() {
if (this.currentMonth === 11) {
this.currentMonth = 0;
this.currentYear++;
} else {
this.currentMonth++;
}
},
isToday(date) {
if (!date) return false;
const today = new Date();
return date.getDate() === today.getDate() &&
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear();
},
hasEvent(date) {
if (!date) return false;
return this.events.some(event => {
const eventDate = new Date(event.date);
return eventDate.getDate() === date.getDate() &&
eventDate.getMonth() === date.getMonth() &&
eventDate.getFullYear() === date.getFullYear();
});
}
}
};
</script>
<style scoped>
.calendar {
max-width: 400px;
margin: auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
}
.weekdays {
display: flex;
justify-content: space-between;
margin-top: 10px;
}
.days {
display: flex;
flex-wrap: wrap;
}
.days div {
width: calc(100% / 7);
height: 40px;
display: flex;
justify-content: center;
align-items: center;
margin-top: 10px;
}
.today {
background-color: #42b983;
color: white;
border-radius: 50%;
}
.has-event {
background-color: purple;
color: white;
border-radius: 50%;
}
</style>
Schedule.vue
<template>
<div class="schedule">
<h2>My Schedule</h2>
<ul>
<li v-for="event in events" :key="event.id">
<span @click="editEvent(event)">{{ event.date }} {{ event.time }}: {{ event.title }}</span>
<button @click="deleteEvent(event.id)">Delete</button>
</li>
</ul>
<input v-model="newEventTitle" placeholder="Event Title" />
<input v-model="newEventDate" type="date" />
<input v-model="newEventTime" type="time" />
<button @click="addEvent">Add Event</button>
<button v-if="isEditing" @click="updateEvent">Update Event</button>
</div>
</template>
<script>
export default {
data() {
return {
events: JSON.parse(localStorage.getItem('events') || '[]'),
newEventTitle: '',
newEventDate: '',
newEventTime: '',
isEditing: false,
currentEvent: null
};
},
methods: {
addEvent() {
if (this.newEventTitle && this.newEventDate && this.newEventTime) {
const newEvent = {
id: Date.now(),
title: this.newEventTitle,
date: this.newEventDate,
time: this.newEventTime
};
this.events.push(newEvent);
this.saveEvents();
this.resetForm();
this.$emit('update-events', this.events);
}
},
editEvent(event) {
this.isEditing = true;
this.currentEvent = event;
this.newEventTitle = event.title;
this.newEventDate = event.date;
this.newEventTime = event.time;
},
updateEvent() {
if (this.currentEvent) {
this.currentEvent.title = this.newEventTitle;
this.currentEvent.date = this.newEventDate;
this.currentEvent.time = this.newEventTime;
this.saveEvents();
this.resetForm();
this.$emit('update-events', this.events);
}
},
deleteEvent(id) {
this.events = this.events.filter(event => event.id !== id);
this.saveEvents();
this.$emit('update-events', this.events);
},
saveEvents() {
localStorage.setItem('events', JSON.stringify(this.events));
},
resetForm() {
this.newEventTitle = '';
this.newEventDate = '';
this.newEventTime = '';
this.isEditing = false;
this.currentEvent = null;
}
}
};
</script>
<style scoped>
.schedule {
max-width: 400px;
margin: auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
input {
display: block;
width: 100%;
padding: 8px;
margin: 10px 0;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
padding: 10px 15px;
background-color: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #38a373;
}
ul {
list-style-type: none;
padding: 0;
}
li {
margin: 10px 0;
}
span {
cursor: pointer;
}
</style>
마지막으로 홈페이지 구실을 하기위해 header, menu, article, side, footer를 구성하고 side에 캘린더와 일정 관리를 재사용하였다.
SideBar.vue
<template>
<div>
<Calendar :events="events" />
<Schedule @update-events="updateEvents" />
</div>
</template>
<script>
import Calendar from './Calendar.vue';
import Schedule from './Schedule.vue';
export default {
name: 'SideBar',
components: {
Calendar,
Schedule
},
data() {
return {
events: JSON.parse(localStorage.getItem('events') || '[]')
};
},
methods: {
updateEvents(events) {
this.events = events;
}
}
};
</script>
결과물과 만드는 과정은 아래 링크를 통해서 확인할 수 있다. 단 이 페이지는 최종 완성물이 아니라서 최적화 과정을 거쳐서 자신만의 웹페이지를 만들 수 있으면 한다.
My Personal Website (jocular-boba-1b5d4b.netlify.app)
'정보교육 > 프런트엔드' 카테고리의 다른 글
코딩 자율학습단(Vue.js 프런트엔드 개발 입문) 7일차 (0) | 2024.06.25 |
---|---|
코딩 자율학습단(Vue.js 프런트엔드 개발 입문) 6일차 (0) | 2024.06.24 |
코딩 자율학습단(Vue.js 프런트엔드 개발 입문) 5일차 (0) | 2024.06.22 |
코딩 자율학습단(Vue.js 프런트엔드 개발 입문) 4일차 (0) | 2024.06.20 |
코딩 자율학습단(Vue.js 프런트엔드 개발 입문) 3일차 (0) | 2024.06.19 |