<template> <div class="el-calendar"> <div class="el-calendar__header"> <div class="el-calendar__title"> {{ i18nDate }} </div> <div class="el-calendar__button-group" v-if="validatedRange.length === 0"> <el-button-group> <el-button type="plain" size="mini" @click="selectDate('prev-month')"> {{ t('el.datepicker.prevMonth') }} </el-button> <el-button type="plain" size="mini" @click="selectDate('today')"> {{ t('el.datepicker.today') }} </el-button> <el-button type="plain" size="mini" @click="selectDate('next-month')"> {{ t('el.datepicker.nextMonth') }} </el-button> </el-button-group> </div> </div> <div class="el-calendar__body" v-if="validatedRange.length === 0" key="no-range"> <date-table :date="date" :selected-day="realSelectedDay" :first-day-of-week="realFirstDayOfWeek" @pick="pickDay" /> </div> <div v-else class="el-calendar__body" key="has-range"> <date-table v-for="(range, index) in validatedRange" :key="index" :date="range[0]" :selected-day="realSelectedDay" :range="range" :hide-header="index !== 0" :first-day-of-week="realFirstDayOfWeek" @pick="pickDay" /> </div> </div> </template> <script> import Locale from 'element-ui/src/mixins/locale'; import fecha from 'element-ui/src/utils/date'; import ElButton from 'element-ui/packages/button'; import ElButtonGroup from 'element-ui/packages/button-group'; import DateTable from './date-table'; import { validateRangeInOneMonth } from 'element-ui/src/utils/date-util'; const validTypes = ['prev-month', 'today', 'next-month']; const weekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; const oneDay = 86400000; export default { name: 'ElCalendar', mixins: [Locale], components: { DateTable, ElButton, ElButtonGroup }, props: { value: [Date, String, Number], range: { type: Array, validator(range) { if (Array.isArray(range)) { return range.length === 2 && range.every( item => typeof item === 'string' || typeof item === 'number' || item instanceof Date); } else { return true; } } }, firstDayOfWeek: { type: Number, default: 1 } }, provide() { return { elCalendar: this }; }, methods: { pickDay(day) { this.realSelectedDay = day; }, selectDate(type) { if (validTypes.indexOf(type) === -1) { throw new Error(`invalid type ${type}`); } let day = ''; if (type === 'prev-month') { day = `${this.prevMonthDatePrefix}-01`; } else if (type === 'next-month') { day = `${this.nextMonthDatePrefix}-01`; } else { day = this.formatedToday; } if (day === this.formatedDate) return; this.pickDay(day); }, toDate(val) { if (!val) { throw new Error('invalid val'); } return val instanceof Date ? val : new Date(val); }, rangeValidator(date, isStart) { const firstDayOfWeek = this.realFirstDayOfWeek; const expected = isStart ? firstDayOfWeek : (firstDayOfWeek === 0 ? 6 : firstDayOfWeek - 1); const message = `${isStart ? 'start' : 'end'} of range should be ${weekDays[expected]}.`; if (date.getDay() !== expected) { console.warn('[ElementCalendar]', message, 'Invalid range will be ignored.'); return false; } return true; } }, computed: { prevMonthDatePrefix() { const temp = new Date(this.date.getTime()); temp.setDate(0); return fecha.format(temp, 'yyyy-MM'); }, curMonthDatePrefix() { return fecha.format(this.date, 'yyyy-MM'); }, nextMonthDatePrefix() { const temp = new Date(this.date.getFullYear(), this.date.getMonth() + 1, 1); return fecha.format(temp, 'yyyy-MM'); }, formatedDate() { return fecha.format(this.date, 'yyyy-MM-dd'); }, i18nDate() { const year = this.date.getFullYear(); const month = this.date.getMonth() + 1; return `${year} ${this.t('el.datepicker.year')} ${this.t('el.datepicker.month' + month)}`; }, formatedToday() { return fecha.format(this.now, 'yyyy-MM-dd'); }, realSelectedDay: { get() { if (!this.value) return this.selectedDay; return this.formatedDate; }, set(val) { this.selectedDay = val; const date = new Date(val); this.$emit('input', date); } }, date() { if (!this.value) { if (this.realSelectedDay) { const d = this.selectedDay.split('-'); return new Date(d[0], d[1] - 1, d[2]); } else if (this.validatedRange.length) { return this.validatedRange[0][0]; } return this.now; } else { return this.toDate(this.value); } }, // if range is valid, we get a two-digit array validatedRange() { let range = this.range; if (!range) return []; range = range.reduce((prev, val, index) => { const date = this.toDate(val); if (this.rangeValidator(date, index === 0)) { prev = prev.concat(date); } return prev; }, []); if (range.length === 2) { const [start, end] = range; if (start > end) { console.warn('[ElementCalendar]end time should be greater than start time'); return []; } // start time and end time in one month if (validateRangeInOneMonth(start, end)) { return [ [start, end] ]; } const data = []; let startDay = new Date(start.getFullYear(), start.getMonth() + 1, 1); const lastDay = this.toDate(startDay.getTime() - oneDay); if (!validateRangeInOneMonth(startDay, end)) { console.warn('[ElementCalendar]start time and end time interval must not exceed two months'); return []; } // 绗竴涓湀鐨勬椂闂磋寖鍥� data.push([ start, lastDay ]); // 涓嬩竴鏈堢殑鏃堕棿鑼冨洿锛岄渶瑕佽绠椾竴涓嬭鏈堢殑绗竴涓懆璧峰鏃� const firstDayOfWeek = this.realFirstDayOfWeek; const nextMontFirstDay = startDay.getDay(); let interval = 0; if (nextMontFirstDay !== firstDayOfWeek) { if (firstDayOfWeek === 0) { interval = 7 - nextMontFirstDay; } else { interval = firstDayOfWeek - nextMontFirstDay; interval = interval > 0 ? interval : 7 + interval; } } startDay = this.toDate(startDay.getTime() + interval * oneDay); if (startDay.getDate() < end.getDate()) { data.push([ startDay, end ]); } return data; } return []; }, realFirstDayOfWeek() { if (this.firstDayOfWeek < 1 || this.firstDayOfWeek > 6) { return 0; } return Math.floor(this.firstDayOfWeek); } }, data() { return { selectedDay: '', now: new Date() }; } }; </script>