| <script> | 
| import fecha from 'element-ui/src/utils/date'; | 
| import { range as rangeArr, getFirstDayOfMonth, getPrevMonthLastDays, getMonthDays, getI18nSettings, validateRangeInOneMonth } from 'element-ui/src/utils/date-util'; | 
|   | 
| export default { | 
|   props: { | 
|     selectedDay: String, // formated date yyyy-MM-dd | 
|     range: { | 
|       type: Array, | 
|       validator(val) { | 
|         if (!(val && val.length)) return true; | 
|         const [start, end] = val; | 
|         return validateRangeInOneMonth(start, end); | 
|       } | 
|     }, | 
|     date: Date, | 
|     hideHeader: Boolean, | 
|     firstDayOfWeek: Number | 
|   }, | 
|   | 
|   inject: ['elCalendar'], | 
|   | 
|   methods: { | 
|     toNestedArr(days) { | 
|       return rangeArr(days.length / 7).map((_, index) => { | 
|         const start = index * 7; | 
|         return days.slice(start, start + 7); | 
|       }); | 
|     }, | 
|   | 
|     getFormateDate(day, type) { | 
|       if (!day || ['prev', 'current', 'next'].indexOf(type) === -1) { | 
|         throw new Error('invalid day or type'); | 
|       } | 
|       let prefix = this.curMonthDatePrefix; | 
|       if (type === 'prev') { | 
|         prefix = this.prevMonthDatePrefix; | 
|       } else if (type === 'next') { | 
|         prefix = this.nextMonthDatePrefix; | 
|       } | 
|       day = `00${day}`.slice(-2); | 
|       return `${prefix}-${day}`; | 
|     }, | 
|   | 
|     getCellClass({ text, type}) { | 
|       const classes = [type]; | 
|       if (type === 'current') { | 
|         const date = this.getFormateDate(text, type); | 
|         if (date === this.selectedDay) { | 
|           classes.push('is-selected'); | 
|         } | 
|         if (date === this.formatedToday) { | 
|           classes.push('is-today'); | 
|         } | 
|       } | 
|       return classes; | 
|     }, | 
|   | 
|     pickDay({ text, type }) { | 
|       const date = this.getFormateDate(text, type); | 
|       this.$emit('pick', date); | 
|     }, | 
|   | 
|     cellRenderProxy({ text, type }) { | 
|       let render = this.elCalendar.$scopedSlots.dateCell; | 
|       if (!render) return <span>{ text }</span>; | 
|   | 
|       const day = this.getFormateDate(text, type); | 
|       const date = new Date(day); | 
|       const data = { | 
|         isSelected: this.selectedDay === day, | 
|         type: `${type}-month`, | 
|         day | 
|       }; | 
|       return render({ date, data }); | 
|     } | 
|   }, | 
|   | 
|   computed: { | 
|     WEEK_DAYS() { | 
|       return getI18nSettings().dayNames; | 
|     }, | 
|     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'); | 
|     }, | 
|   | 
|     formatedToday() { | 
|       return this.elCalendar.formatedToday; | 
|     }, | 
|   | 
|     isInRange() { | 
|       return this.range && this.range.length; | 
|     }, | 
|   | 
|     rows() { | 
|       let days = []; | 
|       // if range exists, should render days in range. | 
|       if (this.isInRange) { | 
|         const [start, end] = this.range; | 
|         const currentMonthRange = rangeArr(end.getDate() - start.getDate() + 1).map((_, index) => ({ | 
|           text: start.getDate() + index, | 
|           type: 'current' | 
|         })); | 
|         let remaining = currentMonthRange.length % 7; | 
|         remaining = remaining === 0 ? 0 : 7 - remaining; | 
|         const nextMonthRange = rangeArr(remaining).map((_, index) => ({ | 
|           text: index + 1, | 
|           type: 'next' | 
|         })); | 
|         days = currentMonthRange.concat(nextMonthRange); | 
|       } else { | 
|         const date = this.date; | 
|         let firstDay = getFirstDayOfMonth(date); | 
|         firstDay = firstDay === 0 ? 7 : firstDay; | 
|         const firstDayOfWeek = typeof this.firstDayOfWeek === 'number' ? this.firstDayOfWeek : 1; | 
|         const offset = (7 + firstDay - firstDayOfWeek) % 7; | 
|         const prevMonthDays = getPrevMonthLastDays(date, offset).map(day => ({ | 
|           text: day, | 
|           type: 'prev' | 
|         })); | 
|         const currentMonthDays = getMonthDays(date).map(day => ({ | 
|           text: day, | 
|           type: 'current' | 
|         })); | 
|         days = [...prevMonthDays, ...currentMonthDays]; | 
|         const nextMonthDays = rangeArr(42 - days.length).map((_, index) => ({ | 
|           text: index + 1, | 
|           type: 'next' | 
|         })); | 
|         days = days.concat(nextMonthDays); | 
|       } | 
|       return this.toNestedArr(days); | 
|     }, | 
|   | 
|     weekDays() { | 
|       const start = this.firstDayOfWeek; | 
|       const { WEEK_DAYS } = this; | 
|   | 
|       if (typeof start !== 'number' || start === 0) { | 
|         return WEEK_DAYS.slice(); | 
|       } else { | 
|         return WEEK_DAYS.slice(start).concat(WEEK_DAYS.slice(0, start)); | 
|       } | 
|     } | 
|   }, | 
|   | 
|   render() { | 
|     const thead = this.hideHeader ? null : (<thead> | 
|       { | 
|         this.weekDays.map(day => <th key={day}>{ day }</th>) | 
|       } | 
|     </thead>); | 
|     return ( | 
|       <table | 
|         class={{ | 
|           'el-calendar-table': true, | 
|           'is-range': this.isInRange | 
|         }} | 
|         cellspacing="0" | 
|         cellpadding="0"> | 
|         { | 
|           thead | 
|         } | 
|         <tbody> | 
|           { | 
|             this.rows.map((row, index) => <tr | 
|               class={{ | 
|                 'el-calendar-table__row': true, | 
|                 'el-calendar-table__row--hide-border': index === 0 && this.hideHeader | 
|               }} | 
|               key={index}> | 
|               { | 
|                 row.map((cell, key) => <td key={key} | 
|                   class={ this.getCellClass(cell) } | 
|                   onClick={this.pickDay.bind(this, cell)}> | 
|                   <div class="el-calendar-day"> | 
|                     { | 
|                       this.cellRenderProxy(cell) | 
|                     } | 
|                   </div> | 
|                 </td>) | 
|               } | 
|             </tr>) | 
|           } | 
|         </tbody> | 
|       </table>); | 
|   } | 
| }; | 
| </script> |