What I want to solves
I am creating a calendar with Vuetify. There is something I don't understand in the Vuetify code. I'm trying to understand it by looking at the sample code on the official site, but it looks like the Vuetify methods are passed unique arguments in the script methods, I've also checked the API, are the arguments to get the time and other events derived from Vuetify?
Code
template
<template>
<v-row >
<v-col>
<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 v-slot:event="{ event, timed, eventSummary }">
<div
v-html="eventSummary()"
></div>
<div
v-if="timed"
@mousedown.stop="extendBottom(event)"
></div>
</template>
</v-calendar>
</v-sheet>
</v-col>
</v-row>
</template>
script
<script>
export default {
data: () => ({
value: '',
events: [],
colors: ['#2196F3', '#3F51B5', '#673AB7', '#00BCD4', '#4CAF50', '#FF9800', '#757575'],
names: ['Meeting', 'Holiday', 'PTO', 'Travel', 'Event', '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 // minutes
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>
For example, startDrag in the method takes event and timed as arguments. Also, in the click section that I am referring to while looking at the sample, it is showEvent ({ nativeEvent, event }), and I think the arguments for nativeEvent and event are also wrong. There was also another method called updateRange ({ start, end }). Furthermore, it also takes the arguments (tms) and (event), but there are no values passed in the template, so I wonder why it is working. The following is the official website of Vuetify. https://vuetifyjs.com/en/components/calendars/#click
CodePudding user response:
Event handling in Vue
When the value of the v-on directive (@ for shorthand) is a function name, the template compiler converts it into a function call that includes the event argument.
For example, this markup:
<CustomButton @submit="upload">Submit</CustomButton>
...is equivalent to:
<CustomButton @submit="(e) => upload(e)">Submit</CustomButton>
The event argument (e) is the data the CustomButton passed when emitting the submit event. Assume CustomButton's doSomething() is called here:
// CustomButton.vue
export default {
methods: {
doSomething() {
const eventData = { name: 'product 1', quantity: 100 }
this.$emit('submit', eventData)
}
}
}
Notice the type of event argument is:
{
name: string,
quantity: number,
}
Given the @submit handling setup above, the parent would recieve the submit event, and call upload() with that event argument:
// Parent.vue
export default {
methods: {
upload(eventData) {
console.log({ name: eventData.name, quantity: eventData.quantity })
}
}
}
With object destructuring in the argument list, that code can be rewritten as this:
// Parent.vue
export default {
methods: {
upload({ name, quantity }) {
console.log({ name, quantity })
}
}
}
And that's the pattern you're seeing in the sample code.
Events
The Vuetify API docs for each component list all events and their arguments (v-calendar's API / events).
Given the event arguments below, it makes sense to see the following method signatures...
@mousedown:event="startDrag"
Event argument for mousedown:event:
{
event: any,
⋮
timed: boolean,
⋮
}
Method signature:
export default {
methods: {
startDrag({ event, timed }) {⋯}
}
}
@click:event="showEvent"
Event argument for click:event:
{
event: any,
⋮
nativeEvent: MouseEvent | TouchEvent
}
Method signature:
export default {
methods: {
showEvent({ event, nativeEvent }) {⋯}
}
}
@change="updateRange"
Event argument for change:
{
start: {⋯},
end: {⋯}
}
Method signature:
export default {
methods: {
updateRange({ start, end }) {⋯}
}
}
