Vuetify - популярный UI-фреймворк для приложений Vue.
В этой статье мы рассмотрим, как работать с фреймворком Vuetify.
Категории календаря
Мы можем разделить календарные события на различные категории.
Например, мы можем написать:
<template> <v-container> <v-row class="text-center"> <v-col col="12"> <v-sheet height="64"> <v-toolbar flat color="white"> <v-btn outlined class="mr-4" color="grey darken-2" @click="setToday">Today</v-btn> <v-btn fab text small color="grey darken-2" @click="prev"> <v-icon small>mdi-chevron-left</v-icon> </v-btn> <v-btn fab text small color="grey darken-2" @click="next"> <v-icon small>mdi-chevron-right</v-icon> </v-btn> <v-toolbar-title v-if="$refs.calendar">{{ $refs.calendar.title }}</v-toolbar-title> <v-spacer></v-spacer> </v-toolbar> </v-sheet> <v-sheet height="600"> <v-calendar ref="calendar" v-model="focus" color="primary" type="category" category-show-all :categories="categories" :events="events" :event-color="getEventColor" @change="fetchEvents" ></v-calendar> </v-sheet> </v-col> </v-row> </v-container> </template> <script> export default { name: "HelloWorld", data: () => ({ focus: "", events: [], colors: [ "blue", "indigo", "deep-purple" ], names: [ "Meeting", "Holiday", "Leave" ], categories: ["John Smith", "Mary Walker"], }), mounted() { this.$refs.calendar.checkChange(); }, methods: { getEventColor(event) { return event.color; }, setToday() { this.focus = ""; }, prev() { this.$refs.calendar.prev(); }, next() { this.$refs.calendar.next(); }, fetchEvents({ start, end }) { const events = []; const min = new Date(`${start.date}T00:00:00`); const max = new Date(`${end.date}T23:59:59`); const days = (max.getTime() - min.getTime()) / 86400000; const eventCount = this.rnd(days, days + 20); for (let i = 0; i < eventCount; i++) { const allDay = this.rnd(0, 3) === 0; const firstTimestamp = this.rnd(min.getTime(), max.getTime()); const first = new Date(firstTimestamp - (firstTimestamp % 900000)); const secondTimestamp = this.rnd(2, allDay ? 288 : 8) * 900000; const second = new Date(first.getTime() + secondTimestamp); events.push({ name: this.names[this.rnd(0, this.names.length - 1)], start: first, end: second, color: this.colors[this.rnd(0, this.colors.length - 1)], timed: !allDay, category: this.categories[this.rnd(0, this.categories.length - 1)], }); } this.events = events; }, rnd(a, b) { return Math.floor((b - a + 1) * Math.random()) + a; }, }, }; </script>
Мы устанавливаем categories
для категорий, которые хотим отобразить.
category-show-all
показывает все категории.
Кроме того, мы устанавливаем для свойства type
значение category
, чтобы отображать категории событий.
Перетащить и отпустить
Мы можем перетаскивать события в календаре.
Например, мы можем написать:
<template> <v-container> <v-row class="text-center"> <v-col col="12"> <v-sheet height="600"> <v-calendar ref="calendar" v-model="value" color="primary" type="4day" :events="events" :event-color="getEventColor" :event-ripple="false" @change="getEvents" @mousedown:event="startDrag" @mousedown:time="startTime" @mousemove:time="mouseMove" @mouseup:time="endDrag" @mouseleave.native="cancelDrag" > <template #event="{ event, timed, eventSummary }"> <div class="v-event-draggable" v-html="eventSummary()"></div> <div v-if="timed" class="v-event-drag-bottom" @mousedown.stop="extendBottom(event)"></div> </template> </v-calendar> </v-sheet> </v-col> </v-row> </v-container> </template> <script> export default { name: "HelloWorld", data: () => ({ value: "", events: [], colors: [ "red", "green", "blue", ], names: [ "Birthday", "Conference", "Party", ], dragEvent: null, dragStart: null, createEvent: null, createStart: null, extendOriginal: null, }), methods: { startDrag({ event, timed }) { if (event && timed) { this.dragEvent = event; this.dragTime = null; this.extendOriginal = null; } }, startTime(tms) { const mouse = this.toTime(tms); if (this.dragEvent && this.dragTime === null) { const start = this.dragEvent.start; this.dragTime = mouse - start; } else { this.createStart = this.roundTime(mouse); this.createEvent = { name: `Event #${this.events.length}`, color: this.rndElement(this.colors), start: this.createStart, end: this.createStart, timed: true, }; this.events.push(this.createEvent); } }, extendBottom(event) { this.createEvent = event; this.createStart = event.start; this.extendOriginal = event.end; }, mouseMove(tms) { const mouse = this.toTime(tms); if (this.dragEvent && this.dragTime !== null) { const start = this.dragEvent.start; const end = this.dragEvent.end; const duration = end - start; const newStartTime = mouse - this.dragTime; const newStart = this.roundTime(newStartTime); const newEnd = newStart + duration; this.dragEvent.start = newStart; this.dragEvent.end = newEnd; } else if (this.createEvent && this.createStart !== null) { const mouseRounded = this.roundTime(mouse, false); const min = Math.min(mouseRounded, this.createStart); const max = Math.max(mouseRounded, this.createStart); this.createEvent.start = min; this.createEvent.end = max; } }, endDrag() { this.dragTime = null; this.dragEvent = null; this.createEvent = null; this.createStart = null; this.extendOriginal = null; }, cancelDrag() { if (this.createEvent) { if (this.extendOriginal) { this.createEvent.end = this.extendOriginal; } else { const i = this.events.indexOf(this.createEvent); if (i !== -1) { this.events.splice(i, 1); } } } this.createEvent = null; this.createStart = null; this.dragTime = null; this.dragEvent = null; }, roundTime(time, down = true) { const roundTo = 15; const roundDownTime = roundTo * 60 * 1000; return down ? time - (time % roundDownTime) : time + (roundDownTime - (time % roundDownTime)); }, toTime(tms) { return new Date( tms.year, tms.month - 1, tms.day, tms.hour, tms.minute ).getTime(); }, getEventColor(event) { const rgb = parseInt(event.color.substring(1), 16); const r = (rgb >> 16) & 0xff; const g = (rgb >> 8) & 0xff; const b = (rgb >> 0) & 0xff; return event === this.dragEvent ? `rgba(${r}, ${g}, ${b}, 0.7)` : event === this.createEvent ? `rgba(${r}, ${g}, ${b}, 0.7)` : event.color; }, getEvents({ start, end }) { const events = []; const min = new Date(`${start.date}T00:00:00`).getTime(); const max = new Date(`${end.date}T23:59:59`).getTime(); const days = (max - min) / 86400000; const eventCount = this.rnd(days, days + 20); for (let i = 0; i < eventCount; i++) { const timed = this.rnd(0, 3) !== 0; const firstTimestamp = this.rnd(min, max); const secondTimestamp = this.rnd(2, timed ? 8 : 288) * 900000; const start = firstTimestamp - (firstTimestamp % 900000); const end = start + secondTimestamp; events.push({ name: this.rndElement(this.names), color: this.rndElement(this.colors), start, end, timed, }); } this.events = events; }, rnd(a, b) { return Math.floor((b - a + 1) * Math.random()) + a; }, rndElement(arr) { return arr[this.rnd(0, arr.length - 1)]; }, }, }; </script>
У нас есть события mousedown
и mouseup
, позволяющие обрабатывать перетаскивание событий.
Время начала и окончания события при перемещении события.
Событие startTime
устанавливает this.createEvent
, когда мы перемещаем элемент календаря.
Затем в методе mouseMove
мы устанавливаем дату начала и дату окончания.
Теперь мы увидим обновление события, когда перетащим его.
Заключение
Мы можем создавать календари, которые перемещают события и устанавливают категории.