Vue encapsulates a calendar component
First put the effect diagram, the style is more casual, we understand the article ideas, you can change.
This is used in the company’s internal SASS system
This is the component of Element-UI
Copy the code
Writing a calendar, first of all to find his data typesetting rules, like a pupil looking for rules.
- In order to keep the overall calendar height from changing with the month, the height is generally designed to be 6 lines, including the days of the last month and the next month (generally set to gray).
- Find out what day the first day of the month is, as shown in the picture above,
2020-11-01
On Sunday,getDay = 0
I’ll show you last month’s total7 minus 0 is 7
Number of days. The tail number is42 - Total number of days before
Usually you don’t need to be able to calculate tail days
Some of their own encapsulation of the simple time function, in order to prevent the main program to write too much code
function getYearMonthDay (value) {
const date = new Date(value)
const year = date.getFullYear()
const month = date.getMonth()
const day = date.getDate()
return { year, month, day }
}
function getDate (year, month, day = 1) {
return new Date(year, month, day)
}
export default {
getYearMonthDay,
getDate
}
Copy the code
The visibleDays shown in the calendar are ok in the template as long as the for loop loops through visibleDays
computed: {
visibleDays() {
// Get the first day of the month
const currentFirstDay = utils.getDate(this.timer.year, this.timer.month, 1)
// Get the day of the week to move forward a few days
let week = currentFirstDay.getDay()
// The beginning of the calendar month is moved forward 7 days if it falls on a Sunday
week = week === 0 ? 7 : week
const startDay = currentFirstDay - week * 60 * 60 * 1000 * 24
// Loop 42 days, 6 rows and 7 columns
const arr = []
for (let i = 0; i < 42; i++) {
arr.push(new Date(startDay + i * 60 * 60 * 1000 * 24))}return arr
}
}
Copy the code
How to present the visibleDays data in the template, which is also a question of finding patterns
<div v-for="i in 6" :key="i">
<span
v-for="j in 7"
:key="j"
class="cell"
:class="[
{ notCurrentMonth: !isCurrentMonth(visibleDays[(i -1) * 7 + (j - 1)]) },
{ today: isToday(visibleDays[(i -1) * 7 + (j - 1)]) }
]"
@click="selectDay(visibleDays[(i -1) * 7 + (j - 1)])">
<span :class="{ selected: isSelect(visibleDays[(i -1) * 7 + (j - 1)]) }">{{ visibleDays[(i -1) * 7 + (j - 1)].getDate() }}</span>
</span>
</div>
Copy the code
Complete component code
<template> <div v-click-outsize> <input :value="formDate" type="text" /> <div v-if="isVisible" class="panel"> <div class="panel-nav"> <span @click="pervMonth"> < < </span> <span>{{timer. Month + 1}} month </span> <span @click="nextMonth"> > </span> <span>{{timer. > </span> </div> <div class="panel-content"> <p class="panel-week"> <span v-for="w in week" :key="'-' + w">{{ w }}</span> </p> <! - similar to the 9 * 9 times table -- -- > < div v - for = "I in 6:" key = "I" > < span v - for = "j in 7:" key = "j" class = "cell:" class = "[{ notCurrentMonth: !isCurrentMonth(visibleDays[(i -1) * 7 + (j - 1)]) }, { today: isToday(visibleDays[(i -1) * 7 + (j - 1)]) } ]" @click="selectDay(visibleDays[(i -1) * 7 + (j - 1)])"> <span :class="{ selected: isSelect(visibleDays[(i -1) * 7 + (j - 1)]) }">{{ visibleDays[(i -1) * 7 + (j - 1)].getDate() }}</span> </span> </div> </div> <div class="panel-footer"></div> </div> </template> <script> import utils from '.. /utils/index.js' export default { name: 'DatePicker', directives: { clickOutsize: { bind(el, binding, vnode) { const handler = (e) => { if (el.contains(e.target)) { if (! vnode.context.isVisible) { vnode.context.focus() } } else { if (vnode.context.isVisible) { vnode.context.blur() } } } el.handler = handler document.addEventListener('click', handler) }, unbind(el) { document.removeEventListener('ckick', el.handler) } } }, props: { value: { type: [Date, String] } }, computed: { formDate() { const { year, month, day } = utils.getYearMonthDay(this.value) return `${year}-${month + 1}-${day}` }, VisibleDays () {const currentFirstDay = utils.getDate(this.timer. Year, this.timer. Month, this.timer. 1) // Let week = currentFirstDay.getDay() // If the calendar month is Sunday, move 7 days forward week = week === 0? 7: week const startDay = currentFirstday-week * 60 * 60 * 1000 * 24 const arr = [] for (let I = 0; i < 42; i++) { arr.push(new Date(startDay + i * 60 * 60 * 1000 * 24)) } return arr } }, data() { return { isVisible: false, timer: { year: '', month: '' }, week: }}, mounted() {const {year, month, day } = utils.getYearMonthDay(this.value) this.timer.year = year this.timer.month = month }, methods: { focus() { this.isVisible = true }, blur() { this.isVisible = false }, isCurrentMonth(date) { const { year, month } = utils.getYearMonthDay(utils.getDate(this.timer.year, this.timer.month, 1)) const { year: y, month: m } = utils.getYearMonthDay(date) return year === y && month === m }, isToday(date) { const { year, month, day } = utils.getYearMonthDay(new Date) const { year: y, month: m, day: d } = utils.getYearMonthDay(date) return year === y && month === m && day === d }, selectDay(date) { this.timer = utils.getYearMonthDay(date) this.$emit('input', date) this.blur() }, isSelect(date) { const { year, month, day } = utils.getYearMonthDay(this.value) const { year: y, month: m, day: d } = utils.getYearMonthDay(date) return year === y && month === m && day === d }, pervMonth() { const d = utils.getDate(this.timer.year, this.timer.month, 1) d.setMonth(--this.timer.month) this.timer = utils.getYearMonthDay(d) }, nextMonth() { const d = utils.getDate(this.timer.year, this.timer.month, 1) d.setMonth(++this.timer.month) this.timer = utils.getYearMonthDay(d) } } } </script> <style lang="scss" scoped> * { padding: 0; margin: 0; } .panel { position: absolute; background-color: #fff; Box-shadow: 0px 0px 10px 0px Rgba (153, 153, 153, 0.5); .panel-nav { text-align: center; span:first-child, span:last-child { cursor: pointer; } } .panel-content { .panel-week { span { display: inline-block; width: 32px; height: 32px; text-align: center; line-height: 32px; font-weight: bold; font-size: 14px; } } .cell { display: inline-flex; justify-content: center; align-items: center; width: 32px; height: 32px; text-align: center; box-sizing: border-box; font-weight: bold; font-size: 14px; box-sizing: border-box; cursor: pointer; span { display: inline-block; width: 20px; height: 20px; } &:hover { opacity: .3; } } .notCurrentMonth { color: gray; } .today { color: #1890FF; } .selected { background-color: #1890FF; color: #fff; border-radius: 50%; } } } </style>Copy the code
Post a GitHub address: If you need to paste and copy, the MySimpleCalendar. Vue component is responsive. Github.com/HuDaDa0/cal…