日历

v-calendar 组件用于在每日、每周或每月视图中显示信息。每日视图有一个全天或定时元素的插槽,每周和每月视图有一个每天的插槽。您可以选择传入一个事件数组,它们将在适当的日期和时间内呈现。

用例

日历具有类型和值,该类型和值决定在多长时间内显示何种类型的日历。这显示了最简单的配置,一个带有 name, startend 属性的事件数组。 end 是可选的,它默认为 start。如果 start定义了时间,那么它被认为是一个定时事件,并将相应地显示在日视图中。事件可以跨越数天,并将相应地呈现。

template script


  1. <template>
  2. <div>
  3. <v-sheet
  4. tile
  5. height="54"
  6. color="grey lighten-3"
  7. class="d-flex"
  8. >
  9. <v-btn
  10. icon
  11. class="ma-2"
  12. @click="$refs.calendar.prev()"
  13. >
  14. <v-icon>mdi-chevron-left</v-icon>
  15. </v-btn>
  16. <v-select
  17. v-model="type"
  18. :items="types"
  19. dense
  20. outlined
  21. hide-details
  22. class="ma-2"
  23. label="type"
  24. ></v-select>
  25. <v-select
  26. v-model="mode"
  27. :items="modes"
  28. dense
  29. outlined
  30. hide-details
  31. label="event-overlap-mode"
  32. class="ma-2"
  33. ></v-select>
  34. <v-select
  35. v-model="weekday"
  36. :items="weekdays"
  37. dense
  38. outlined
  39. hide-details
  40. label="weekdays"
  41. class="ma-2"
  42. ></v-select>
  43. <v-spacer></v-spacer>
  44. <v-btn
  45. icon
  46. class="ma-2"
  47. @click="$refs.calendar.next()"
  48. >
  49. <v-icon>mdi-chevron-right</v-icon>
  50. </v-btn>
  51. </v-sheet>
  52. <v-sheet height="600">
  53. <v-calendar
  54. ref="calendar"
  55. v-model="value"
  56. :weekdays="weekday"
  57. :type="type"
  58. :events="events"
  59. :event-overlap-mode="mode"
  60. :event-overlap-threshold="30"
  61. :event-color="getEventColor"
  62. @change="getEvents"
  63. ></v-calendar>
  64. </v-sheet>
  65. </div>
  66. </template>
  1. <script>
  2. export default {
  3. data: () => ({
  4. type: 'month',
  5. types: ['month', 'week', 'day', '4day'],
  6. mode: 'stack',
  7. modes: ['stack', 'column'],
  8. weekday: [0, 1, 2, 3, 4, 5, 6],
  9. weekdays: [
  10. { text: 'Sun - Sat', value: [0, 1, 2, 3, 4, 5, 6] },
  11. { text: 'Mon - Sun', value: [1, 2, 3, 4, 5, 6, 0] },
  12. { text: 'Mon - Fri', value: [1, 2, 3, 4, 5] },
  13. { text: 'Mon, Wed, Fri', value: [1, 3, 5] },
  14. ],
  15. value: '',
  16. events: [],
  17. colors: ['blue', 'indigo', 'deep-purple', 'cyan', 'green', 'orange', 'grey darken-1'],
  18. names: ['Meeting', 'Holiday', 'PTO', 'Travel', 'Event', 'Birthday', 'Conference', 'Party'],
  19. }),
  20. methods: {
  21. getEvents ({ start, end }) {
  22. const events = []
  23. const min = new Date(`${start.date}T00:00:00`)
  24. const max = new Date(`${end.date}T23:59:59`)
  25. const days = (max.getTime() - min.getTime()) / 86400000
  26. const eventCount = this.rnd(days, days + 20)
  27. for (let i = 0; i < eventCount; i++) {
  28. const allDay = this.rnd(0, 3) === 0
  29. const firstTimestamp = this.rnd(min.getTime(), max.getTime())
  30. const first = new Date(firstTimestamp - (firstTimestamp % 900000))
  31. const secondTimestamp = this.rnd(2, allDay ? 288 : 8) * 900000
  32. const second = new Date(first.getTime() + secondTimestamp)
  33. events.push({
  34. name: this.names[this.rnd(0, this.names.length - 1)],
  35. start: this.formatDate(first, !allDay),
  36. end: this.formatDate(second, !allDay),
  37. color: this.colors[this.rnd(0, this.colors.length - 1)],
  38. })
  39. }
  40. this.events = events
  41. },
  42. getEventColor (event) {
  43. return event.color
  44. },
  45. rnd (a, b) {
  46. return Math.floor((b - a + 1) * Math.random()) + a
  47. },
  48. formatDate (a, withTime) {
  49. return withTime
  50. ? `${a.getFullYear()}-${a.getMonth() + 1}-${a.getDate()} ${a.getHours()}:${a.getMinutes()}`
  51. : `${a.getFullYear()}-${a.getMonth() + 1}-${a.getDate()}`
  52. },
  53. },
  54. }
  55. </script>

Calendars(日历) - 图1

API

从下面选择您想要的组件,并查看可用的属性、插槽、事件和函数。

Calendars(日历) - 图2

实战场

template script style


  1. <template>
  2. <v-row>
  3. <v-col
  4. sm="12"
  5. lg="3"
  6. class="mb-4 controls"
  7. >
  8. <v-btn
  9. fab
  10. small
  11. absolute
  12. left
  13. color="primary"
  14. @click="$refs.calendar.prev()"
  15. >
  16. <v-icon dark>mdi-chevron-left</v-icon>
  17. </v-btn>
  18. <v-btn
  19. fab
  20. small
  21. absolute
  22. right
  23. color="primary"
  24. @click="$refs.calendar.next()"
  25. >
  26. <v-icon dark>mdi-chevron-right</v-icon>
  27. </v-btn>
  28. <br><br><br>
  29. <v-select
  30. v-model="type"
  31. :items="typeOptions"
  32. label="Type"
  33. hide-details
  34. outlined
  35. dense
  36. ></v-select>
  37. <v-checkbox
  38. v-model="dark"
  39. label="Dark"
  40. hide-details
  41. ></v-checkbox>
  42. <v-checkbox
  43. v-model="shortIntervals"
  44. label="Short intervals"
  45. hide-details
  46. ></v-checkbox>
  47. <v-checkbox
  48. v-model="shortMonths"
  49. label="Short months"
  50. hide-details
  51. ></v-checkbox>
  52. <v-checkbox
  53. v-model="shortWeekdays"
  54. label="Short weekdays"
  55. hide-details
  56. ></v-checkbox>
  57. <v-select
  58. v-model="color"
  59. :items="colorOptions"
  60. class="mt-3"
  61. label="Color"
  62. hide-details
  63. outlined
  64. dense
  65. ></v-select>
  66. <v-menu
  67. ref="startMenu"
  68. v-model="startMenu"
  69. :close-on-content-click="false"
  70. :nudge-right="40"
  71. :return-value.sync="start"
  72. transition="scale-transition"
  73. min-width="290px"
  74. offset-y
  75. >
  76. <template v-slot:activator="{ on }">
  77. <v-text-field
  78. v-model="start"
  79. class="mt-3"
  80. label="Start Date"
  81. prepend-icon="event"
  82. dense
  83. readonly
  84. outlined
  85. hide-details
  86. v-on="on"
  87. ></v-text-field>
  88. </template>
  89. <v-date-picker
  90. v-model="start"
  91. no-title
  92. scrollable
  93. >
  94. <v-spacer></v-spacer>
  95. <v-btn
  96. text
  97. color="primary"
  98. @click="startMenu = false"
  99. >
  100. Cancel
  101. </v-btn>
  102. <v-btn
  103. text
  104. color="primary"
  105. @click="$refs.startMenu.save(start)"
  106. >
  107. OK
  108. </v-btn>
  109. </v-date-picker>
  110. </v-menu>
  111. <v-menu
  112. v-if="hasEnd"
  113. ref="endMenu"
  114. v-model="endMenu"
  115. :close-on-content-click="false"
  116. :nudge-right="40"
  117. :return-value.sync="end"
  118. transition="scale-transition"
  119. min-width="290px"
  120. offset-y
  121. >
  122. <template v-slot:activator="{ on }">
  123. <v-text-field
  124. v-model="end"
  125. class="mt-3"
  126. label="End Date"
  127. prepend-icon="event"
  128. dense
  129. readonly
  130. outlined
  131. hide-details
  132. v-on="on"
  133. ></v-text-field>
  134. </template>
  135. <v-date-picker
  136. v-model="end"
  137. no-title
  138. scrollable
  139. >
  140. <v-spacer></v-spacer>
  141. <v-btn
  142. text
  143. color="primary"
  144. @click="endMenu = false"
  145. >
  146. Cancel
  147. </v-btn>
  148. <v-btn
  149. text
  150. color="primary"
  151. @click="$refs.endMenu.save(end)"
  152. >
  153. OK
  154. </v-btn>
  155. </v-date-picker>
  156. </v-menu>
  157. <v-menu
  158. ref="nowMenu"
  159. v-model="nowMenu"
  160. :close-on-content-click="false"
  161. :nudge-right="40"
  162. :return-value.sync="now"
  163. transition="scale-transition"
  164. min-width="290px"
  165. offset-y
  166. >
  167. <template v-slot:activator="{ on }">
  168. <v-text-field
  169. v-model="now"
  170. class="mt-3"
  171. label="Today"
  172. prepend-icon="event"
  173. dense
  174. readonly
  175. outlined
  176. hide-details
  177. v-on="on"
  178. ></v-text-field>
  179. </template>
  180. <v-date-picker
  181. v-model="now"
  182. no-title
  183. scrollable
  184. >
  185. <v-spacer></v-spacer>
  186. <v-btn
  187. text
  188. color="primary"
  189. @click="nowMenu = false"
  190. >
  191. Cancel
  192. </v-btn>
  193. <v-btn
  194. text
  195. color="primary"
  196. @click="$refs.nowMenu.save(now)"
  197. >
  198. OK
  199. </v-btn>
  200. </v-date-picker>
  201. </v-menu>
  202. <v-select
  203. v-model="mode"
  204. :items="modeOptions"
  205. dense
  206. outlined
  207. hide-details
  208. class="mt-3"
  209. label="Event Overlap Mode"
  210. ></v-select>
  211. <v-select
  212. v-model="weekdays"
  213. :items="weekdaysOptions"
  214. dense
  215. outlined
  216. hide-details
  217. class="mt-3"
  218. label="Weekdays"
  219. ></v-select>
  220. <v-text-field
  221. v-if="type === 'custom-weekly'"
  222. v-model="minWeeks"
  223. dense
  224. outlined
  225. hide-details
  226. class="mt-3"
  227. label="Minimum Weeks"
  228. type="number"
  229. ></v-text-field>
  230. <v-select
  231. v-if="hasIntervals"
  232. v-model="intervals"
  233. :items="intervalsOptions"
  234. dense
  235. outlined
  236. hide-details
  237. class="mt-3"
  238. label="Intervals"
  239. ></v-select>
  240. <v-select
  241. v-if="type === 'custom-daily'"
  242. v-model="maxDays"
  243. :items="maxDaysOptions"
  244. dense
  245. outlined
  246. hide-details
  247. class="mt-3"
  248. label="# of Days"
  249. ></v-select>
  250. <v-select
  251. v-if="hasIntervals"
  252. v-model="styleInterval"
  253. :items="styleIntervalOptions"
  254. dense
  255. outlined
  256. hide-details
  257. class="mt-3"
  258. label="Styling"
  259. ></v-select>
  260. </v-col>
  261. <v-col
  262. sm="12"
  263. lg="9"
  264. class="pl-4"
  265. >
  266. <v-sheet height="600">
  267. <v-calendar
  268. ref="calendar"
  269. v-model="start"
  270. :type="type"
  271. :start="start"
  272. :end="end"
  273. :min-weeks="minWeeks"
  274. :max-days="maxDays"
  275. :now="now"
  276. :dark="dark"
  277. :weekdays="weekdays"
  278. :first-interval="intervals.first"
  279. :interval-minutes="intervals.minutes"
  280. :interval-count="intervals.count"
  281. :interval-height="intervals.height"
  282. :interval-style="intervalStyle"
  283. :show-interval-label="showIntervalLabel"
  284. :short-intervals="shortIntervals"
  285. :short-months="shortMonths"
  286. :short-weekdays="shortWeekdays"
  287. :color="color"
  288. :events="events"
  289. :event-overlap-mode="mode"
  290. :event-overlap-threshold="45"
  291. :event-color="getEventColor"
  292. @change="getEvents"
  293. ></v-calendar>
  294. </v-sheet>
  295. </v-col>
  296. </v-row>
  297. </template>
  1. <script>
  2. const weekdaysDefault = [0, 1, 2, 3, 4, 5, 6]
  3. const intervalsDefault = {
  4. first: 0,
  5. minutes: 60,
  6. count: 24,
  7. height: 48,
  8. }
  9. const stylings = {
  10. default (interval) {
  11. return undefined
  12. },
  13. workday (interval) {
  14. const inactive = interval.weekday === 0 ||
  15. interval.weekday === 6 ||
  16. interval.hour < 9 ||
  17. interval.hour >= 17
  18. const startOfHour = interval.minute === 0
  19. const dark = this.dark
  20. const mid = dark ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)'
  21. return {
  22. backgroundColor: inactive ? (dark ? 'rgba(0,0,0,0.4)' : 'rgba(0,0,0,0.05)') : undefined,
  23. borderTop: startOfHour ? undefined : '1px dashed ' + mid,
  24. }
  25. },
  26. past (interval) {
  27. return {
  28. backgroundColor: interval.past ? (this.dark ? 'rgba(0,0,0,0.4)' : 'rgba(0,0,0,0.05)') : undefined,
  29. }
  30. },
  31. }
  32. export default {
  33. data: () => ({
  34. dark: false,
  35. startMenu: false,
  36. start: '2019-01-12',
  37. endMenu: false,
  38. end: '2019-01-27',
  39. nowMenu: false,
  40. minWeeks: 1,
  41. now: null,
  42. events: [],
  43. colors: ['blue', 'indigo', 'deep-purple', 'cyan', 'green', 'orange', 'grey darken-1'],
  44. names: ['Meeting', 'Holiday', 'PTO', 'Travel', 'Event', 'Birthday', 'Conference', 'Party'],
  45. type: 'month',
  46. typeOptions: [
  47. { text: 'Day', value: 'day' },
  48. { text: '4 Day', value: '4day' },
  49. { text: 'Week', value: 'week' },
  50. { text: 'Month', value: 'month' },
  51. { text: 'Custom Daily', value: 'custom-daily' },
  52. { text: 'Custom Weekly', value: 'custom-weekly' },
  53. ],
  54. mode: 'stack',
  55. modeOptions: [
  56. { text: 'Stack', value: 'stack' },
  57. { text: 'Column', value: 'column' },
  58. ],
  59. weekdays: weekdaysDefault,
  60. weekdaysOptions: [
  61. { text: 'Sunday - Saturday', value: weekdaysDefault },
  62. { text: 'Mon, Wed, Fri', value: [1, 3, 5] },
  63. { text: 'Mon - Fri', value: [1, 2, 3, 4, 5] },
  64. { text: 'Mon - Sun', value: [1, 2, 3, 4, 5, 6, 0] },
  65. ],
  66. intervals: intervalsDefault,
  67. intervalsOptions: [
  68. { text: 'Default', value: intervalsDefault },
  69. { text: 'Workday', value: { first: 16, minutes: 30, count: 20, height: 48 } },
  70. ],
  71. maxDays: 7,
  72. maxDaysOptions: [
  73. { text: '7 days', value: 7 },
  74. { text: '5 days', value: 5 },
  75. { text: '4 days', value: 4 },
  76. { text: '3 days', value: 3 },
  77. ],
  78. styleInterval: 'default',
  79. styleIntervalOptions: [
  80. { text: 'Default', value: 'default' },
  81. { text: 'Workday', value: 'workday' },
  82. { text: 'Past', value: 'past' },
  83. ],
  84. color: 'primary',
  85. colorOptions: [
  86. { text: 'Primary', value: 'primary' },
  87. { text: 'Secondary', value: 'secondary' },
  88. { text: 'Accent', value: 'accent' },
  89. { text: 'Red', value: 'red' },
  90. { text: 'Pink', value: 'pink' },
  91. { text: 'Purple', value: 'purple' },
  92. { text: 'Deep Purple', value: 'deep-purple' },
  93. { text: 'Indigo', value: 'indigo' },
  94. { text: 'Blue', value: 'blue' },
  95. { text: 'Light Blue', value: 'light-blue' },
  96. { text: 'Cyan', value: 'cyan' },
  97. { text: 'Teal', value: 'teal' },
  98. { text: 'Green', value: 'green' },
  99. { text: 'Light Green', value: 'light-green' },
  100. { text: 'Lime', value: 'lime' },
  101. { text: 'Yellow', value: 'yellow' },
  102. { text: 'Amber', value: 'amber' },
  103. { text: 'Orange', value: 'orange' },
  104. { text: 'Deep Orange', value: 'deep-orange' },
  105. { text: 'Brown', value: 'brown' },
  106. { text: 'Blue Gray', value: 'blue-gray' },
  107. { text: 'Gray', value: 'gray' },
  108. { text: 'Black', value: 'black' },
  109. ],
  110. shortIntervals: true,
  111. shortMonths: false,
  112. shortWeekdays: false,
  113. }),
  114. computed: {
  115. intervalStyle () {
  116. return stylings[this.styleInterval].bind(this)
  117. },
  118. hasIntervals () {
  119. return this.type in {
  120. week: 1, day: 1, '4day': 1, 'custom-daily': 1,
  121. }
  122. },
  123. hasEnd () {
  124. return this.type in {
  125. 'custom-weekly': 1, 'custom-daily': 1,
  126. }
  127. },
  128. },
  129. methods: {
  130. viewDay ({ date }) {
  131. this.start = date
  132. this.type = 'day'
  133. },
  134. getEventColor (event) {
  135. return event.color
  136. },
  137. showIntervalLabel (interval) {
  138. return interval.minute === 0
  139. },
  140. getEvents ({ start, end }) {
  141. const events = []
  142. const min = new Date(`${start.date}T00:00:00`)
  143. const max = new Date(`${end.date}T23:59:59`)
  144. const days = (max.getTime() - min.getTime()) / 86400000
  145. const eventCount = this.rnd(days, days + 20)
  146. for (let i = 0; i < eventCount; i++) {
  147. const allDay = this.rnd(0, 3) === 0
  148. const firstTimestamp = this.rnd(min.getTime(), max.getTime())
  149. const first = new Date(firstTimestamp - (firstTimestamp % 900000))
  150. const secondTimestamp = this.rnd(2, allDay ? 288 : 8) * 900000
  151. const second = new Date(first.getTime() + secondTimestamp)
  152. events.push({
  153. name: this.names[this.rnd(0, this.names.length - 1)],
  154. start: this.formatDate(first, !allDay),
  155. end: this.formatDate(second, !allDay),
  156. color: this.colors[this.rnd(0, this.colors.length - 1)],
  157. })
  158. }
  159. this.events = events
  160. },
  161. rnd (a, b) {
  162. return Math.floor((b - a + 1) * Math.random()) + a
  163. },
  164. formatDate (a, withTime) {
  165. return withTime
  166. ? `${a.getFullYear()}-${a.getMonth() + 1}-${a.getDate()} ${a.getHours()}:${a.getMinutes()}`
  167. : `${a.getFullYear()}-${a.getMonth() + 1}-${a.getDate()}`
  168. },
  169. },
  170. }
  171. </script>
  1. <style scoped>
  2. .controls {
  3. position: relative;
  4. }
  5. </style>

Calendars(日历) - 图3

示例

下面是一些简单到复杂的例子。

每周

这是一个事件日历示例,其中包含类型为 week 的全天事件和定时事件。

template script style


  1. <template>
  2. <v-row>
  3. <v-col>
  4. <v-sheet height="400">
  5. <v-calendar
  6. ref="calendar"
  7. :now="today"
  8. :value="today"
  9. :events="events"
  10. color="primary"
  11. type="week"
  12. ></v-calendar>
  13. </v-sheet>
  14. </v-col>
  15. </v-row>
  16. </template>
  1. <script>
  2. export default {
  3. data: () => ({
  4. today: '2019-01-08',
  5. events: [
  6. {
  7. name: 'Weekly Meeting',
  8. start: '2019-01-07 09:00',
  9. end: '2019-01-07 10:00',
  10. },
  11. {
  12. name: 'Thomas\' Birthday',
  13. start: '2019-01-10',
  14. },
  15. {
  16. name: 'Mash Potatoes',
  17. start: '2019-01-09 12:30',
  18. end: '2019-01-09 15:30',
  19. },
  20. ],
  21. }),
  22. mounted () {
  23. this.$refs.calendar.scrollToTime('08:00')
  24. },
  25. }
  26. </script>
  1. <style scoped>
  2. .my-event {
  3. overflow: hidden;
  4. text-overflow: ellipsis;
  5. white-space: nowrap;
  6. border-radius: 2px;
  7. background-color: #1867c0;
  8. color: #ffffff;
  9. border: 1px solid #1867c0;
  10. font-size: 12px;
  11. padding: 3px;
  12. cursor: pointer;
  13. margin-bottom: 1px;
  14. left: 4px;
  15. margin-right: 8px;
  16. position: relative;
  17. }
  18. .my-event.with-time {
  19. position: absolute;
  20. right: 4px;
  21. margin-right: 0px;
  22. }
  23. </style>

Calendars(日历) - 图4

每日

这是一个日历示例,每个间隔时段都有内容,类型为 day

template script


  1. <template>
  2. <v-row>
  3. <v-col>
  4. <v-sheet height="400">
  5. <v-calendar
  6. color="primary"
  7. type="day"
  8. >
  9. <template v-slot:day-header="{ present }">
  10. <template
  11. v-if="present"
  12. class="text-center"
  13. >
  14. Today
  15. </template>
  16. </template>
  17. <template v-slot:interval="{ hour }">
  18. <div
  19. class="text-center"
  20. >
  21. {{ hour }} o'clock
  22. </div>
  23. </template>
  24. </v-calendar>
  25. </v-sheet>
  26. </v-col>
  27. </v-row>
  28. </template>
  1. <script>
  2. export default {
  3. data: () => ({}),
  4. }
  5. </script>

Calendars(日历) - 图5

Parallax Free

This beautiful single page parallax is a great home page for any application.

ads by Vuetify

](https://parallax-theme-free.johnleider.com?ref=vuetifyjs.com)

插槽

插槽允许您定义每天的内容、每日视图的时间间隔和各种标签。

template script


  1. <template>
  2. <v-row>
  3. <v-col>
  4. <v-sheet height="500">
  5. <v-calendar
  6. :now="today"
  7. :value="today"
  8. color="primary"
  9. >
  10. <template v-slot:day="{ present, past, date }">
  11. <v-row
  12. class="fill-height"
  13. >
  14. <template v-if="past && tracked[date]">
  15. <v-sheet
  16. v-for="(percent, i) in tracked[date]"
  17. :key="i"
  18. :title="category[i]"
  19. :color="colors[i]"
  20. :width="`${percent}%`"
  21. height="100%"
  22. tile
  23. ></v-sheet>
  24. </template>
  25. </v-row>
  26. </template>
  27. </v-calendar>
  28. </v-sheet>
  29. </v-col>
  30. </v-row>
  31. </template>
  1. <script>
  2. export default {
  3. data: () => ({
  4. today: '2019-01-10',
  5. tracked: {
  6. '2019-01-09': [23, 45, 10],
  7. '2019-01-08': [10],
  8. '2019-01-07': [0, 78, 5],
  9. '2019-01-06': [0, 0, 50],
  10. '2019-01-05': [0, 10, 23],
  11. '2019-01-04': [2, 90],
  12. '2019-01-03': [10, 32],
  13. '2019-01-02': [80, 10, 10],
  14. '2019-01-01': [20, 25, 10],
  15. },
  16. colors: ['#1867c0', '#fb8c00', '#000000'],
  17. category: ['Development', 'Meetings', 'Slacking'],
  18. }),
  19. }
  20. </script>

Calendars(日历) - 图6

事件

这是一个带有附加事件处理程序和控制日历显示的外部组件的计划器示例。

template script


  1. <template>
  2. <v-row class="fill-height">
  3. <v-col>
  4. <v-sheet height="64">
  5. <v-toolbar flat color="white">
  6. <v-btn outlined class="mr-4" color="grey darken-2" @click="setToday">
  7. Today
  8. </v-btn>
  9. <v-btn fab text small color="grey darken-2" @click="prev">
  10. <v-icon small>mdi-chevron-left</v-icon>
  11. </v-btn>
  12. <v-btn fab text small color="grey darken-2" @click="next">
  13. <v-icon small>mdi-chevron-right</v-icon>
  14. </v-btn>
  15. <v-toolbar-title>{{ title }}</v-toolbar-title>
  16. <v-spacer></v-spacer>
  17. <v-menu bottom right>
  18. <template v-slot:activator="{ on }">
  19. <v-btn
  20. outlined
  21. color="grey darken-2"
  22. v-on="on"
  23. >
  24. <span>{{ typeToLabel[type] }}</span>
  25. <v-icon right>mdi-menu-down</v-icon>
  26. </v-btn>
  27. </template>
  28. <v-list>
  29. <v-list-item @click="type = 'day'">
  30. <v-list-item-title>Day</v-list-item-title>
  31. </v-list-item>
  32. <v-list-item @click="type = 'week'">
  33. <v-list-item-title>Week</v-list-item-title>
  34. </v-list-item>
  35. <v-list-item @click="type = 'month'">
  36. <v-list-item-title>Month</v-list-item-title>
  37. </v-list-item>
  38. <v-list-item @click="type = '4day'">
  39. <v-list-item-title>4 days</v-list-item-title>
  40. </v-list-item>
  41. </v-list>
  42. </v-menu>
  43. </v-toolbar>
  44. </v-sheet>
  45. <v-sheet height="600">
  46. <v-calendar
  47. ref="calendar"
  48. v-model="focus"
  49. color="primary"
  50. :events="events"
  51. :event-color="getEventColor"
  52. :now="today"
  53. :type="type"
  54. @click:event="showEvent"
  55. @click:more="viewDay"
  56. @click:date="viewDay"
  57. @change="updateRange"
  58. ></v-calendar>
  59. <v-menu
  60. v-model="selectedOpen"
  61. :close-on-content-click="false"
  62. :activator="selectedElement"
  63. offset-x
  64. >
  65. <v-card
  66. color="grey lighten-4"
  67. min-width="350px"
  68. flat
  69. >
  70. <v-toolbar
  71. :color="selectedEvent.color"
  72. dark
  73. >
  74. <v-btn icon>
  75. <v-icon>mdi-pencil</v-icon>
  76. </v-btn>
  77. <v-toolbar-title v-html="selectedEvent.name"></v-toolbar-title>
  78. <v-spacer></v-spacer>
  79. <v-btn icon>
  80. <v-icon>mdi-heart</v-icon>
  81. </v-btn>
  82. <v-btn icon>
  83. <v-icon>mdi-dots-vertical</v-icon>
  84. </v-btn>
  85. </v-toolbar>
  86. <v-card-text>
  87. <span v-html="selectedEvent.details"></span>
  88. </v-card-text>
  89. <v-card-actions>
  90. <v-btn
  91. text
  92. color="secondary"
  93. @click="selectedOpen = false"
  94. >
  95. Cancel
  96. </v-btn>
  97. </v-card-actions>
  98. </v-card>
  99. </v-menu>
  100. </v-sheet>
  101. </v-col>
  102. </v-row>
  103. </template>
  1. <script>
  2. export default {
  3. data: () => ({
  4. focus: '',
  5. type: 'month',
  6. typeToLabel: {
  7. month: 'Month',
  8. week: 'Week',
  9. day: 'Day',
  10. '4day': '4 Days',
  11. },
  12. start: null,
  13. end: null,
  14. selectedEvent: {},
  15. selectedElement: null,
  16. selectedOpen: false,
  17. events: [],
  18. colors: ['blue', 'indigo', 'deep-purple', 'cyan', 'green', 'orange', 'grey darken-1'],
  19. names: ['Meeting', 'Holiday', 'PTO', 'Travel', 'Event', 'Birthday', 'Conference', 'Party'],
  20. }),
  21. computed: {
  22. title () {
  23. const { start, end } = this
  24. if (!start || !end) {
  25. return ''
  26. }
  27. const startMonth = this.monthFormatter(start)
  28. const endMonth = this.monthFormatter(end)
  29. const suffixMonth = startMonth === endMonth ? '' : endMonth
  30. const startYear = start.year
  31. const endYear = end.year
  32. const suffixYear = startYear === endYear ? '' : endYear
  33. const startDay = start.day + this.nth(start.day)
  34. const endDay = end.day + this.nth(end.day)
  35. switch (this.type) {
  36. case 'month':
  37. return `${startMonth} ${startYear}`
  38. case 'week':
  39. case '4day':
  40. return `${startMonth} ${startDay} ${startYear} - ${suffixMonth} ${endDay} ${suffixYear}`
  41. case 'day':
  42. return `${startMonth} ${startDay} ${startYear}`
  43. }
  44. return ''
  45. },
  46. monthFormatter () {
  47. return this.$refs.calendar.getFormatter({
  48. timeZone: 'UTC', month: 'long',
  49. })
  50. },
  51. },
  52. mounted () {
  53. this.$refs.calendar.checkChange()
  54. },
  55. methods: {
  56. viewDay ({ date }) {
  57. this.focus = date
  58. this.type = 'day'
  59. },
  60. getEventColor (event) {
  61. return event.color
  62. },
  63. setToday () {
  64. this.focus = this.today
  65. },
  66. prev () {
  67. this.$refs.calendar.prev()
  68. },
  69. next () {
  70. this.$refs.calendar.next()
  71. },
  72. showEvent ({ nativeEvent, event }) {
  73. const open = () => {
  74. this.selectedEvent = event
  75. this.selectedElement = nativeEvent.target
  76. setTimeout(() => this.selectedOpen = true, 10)
  77. }
  78. if (this.selectedOpen) {
  79. this.selectedOpen = false
  80. setTimeout(open, 10)
  81. } else {
  82. open()
  83. }
  84. nativeEvent.stopPropagation()
  85. },
  86. updateRange ({ start, end }) {
  87. const events = []
  88. const min = new Date(`${start.date}T00:00:00`)
  89. const max = new Date(`${end.date}T23:59:59`)
  90. const days = (max.getTime() - min.getTime()) / 86400000
  91. const eventCount = this.rnd(days, days + 20)
  92. for (let i = 0; i < eventCount; i++) {
  93. const allDay = this.rnd(0, 3) === 0
  94. const firstTimestamp = this.rnd(min.getTime(), max.getTime())
  95. const first = new Date(firstTimestamp - (firstTimestamp % 900000))
  96. const secondTimestamp = this.rnd(2, allDay ? 288 : 8) * 900000
  97. const second = new Date(first.getTime() + secondTimestamp)
  98. events.push({
  99. name: this.names[this.rnd(0, this.names.length - 1)],
  100. start: this.formatDate(first, !allDay),
  101. end: this.formatDate(second, !allDay),
  102. color: this.colors[this.rnd(0, this.colors.length - 1)],
  103. })
  104. }
  105. this.start = start
  106. this.end = end
  107. this.events = events
  108. },
  109. nth (d) {
  110. return d > 3 && d < 21
  111. ? 'th'
  112. : ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th'][d % 10]
  113. },
  114. rnd (a, b) {
  115. return Math.floor((b - a + 1) * Math.random()) + a
  116. },
  117. formatDate (a, withTime) {
  118. return withTime
  119. ? `${a.getFullYear()}-${a.getMonth() + 1}-${a.getDate()} ${a.getHours()}:${a.getMinutes()}`
  120. : `${a.getFullYear()}-${a.getMonth() + 1}-${a.getDate()}`
  121. },
  122. },
  123. }
  124. </script>

Calendars(日历) - 图7