日历
<pre><code class="language-markdown">
<template>
<div class="calendar-container">
<div class="calendar__header">
<div class="header__title">
<p> {{ selectedYear }}年</p>
<p>{{selectedMonth}}月{{actDate}}日 <span>星期{{calendarHeader[this.getDayIndex]}}</span></p>
</div>
<div class="toggle">
<div class="header__pre toggle-btn" @click="pre"></div>
<div class="header__next toggle-btn" @click="next"></div>
</div>
</div>
<div class="line"/>
<div class="calendar__main">
<div
class="main__block-head"
v-for="(item, index) in calendarHeader"
:key="index"
>
{{ item }}
</div>
<template v-if="type === 'month' ">
<div
:class="
`main__block ${
item.type === 'pre' || item.type === 'next'
? 'main__block-not'
: ''
} ${isAct(item) ? 'day-select':''} ${multiSelect && hascontent(item) ? `day-select-week day-select-week${hascontent(item)}`:''} ${item.className||''}`
"
@click="handleDayClick(item)"
v-for="(item, index) in monthDays"
:key="item.type + item.content + `${index}`"
>
<p class="dateNum">{{ setContent(item.month, item.content) }}</p>
</div>
</template>
<template v-else>
<div
:class="
`main__block ${
item.type === 'pre' || item.type === 'next'
? 'main__block-not'
: ''
} ${isAct(item) ? 'day-select':''} ${item.className || ''}`
"
@click="handleDayClick(item)"
v-for="(item, index) in daysItem"
:key="item.type + item.content + `${index}`"
>
<p class="dateNum">{{ setContent(item.month, item.content) }}</p>
</div>
</template>
</div>
<slot>
</slot>
</div>
</template>
<script>
import _ from 'lodash'
import moment from 'moment'
import { addZero } from '../../../../../utils/momentUtils'
const DEFAULT_DAY = new Date()
export default {
name: 'calendar',
props: {
moreDataList: {
required: false,
type: Array,
default: () => []
},
selectDay:{
required: false,
type:String,
defautlt:''
},
multiSelect:{
required: false,
type: Boolean,
default: false
},
isActiveClick: {//是否标记
required: false,
type: Boolean,
default: false
},
maxDate: {
required: false,
type: String,
default: ''
},
minDate: {
required: false,
type: String,
default: ''
}
},
mixins: [],
components: {},
data() {
return {
monthDays: '',
lastDay: '',
multiSelectArr:[],
type: 'month',
calendarHeader: ['日', '一', '二', '三', '四', '五', '六'],
selectedYear: DEFAULT_DAY.getFullYear(),
selectedMonth: DEFAULT_DAY.getMonth() + 1,
selectedDate: DEFAULT_DAY.getDate(),
actMonth: DEFAULT_DAY.getMonth() + 1,
actDate: DEFAULT_DAY.getDate(),
actDay: `${this.selectedYear}-${addZero(this.actMonth)}-${addZero(this.actDate)}`,
today: this.getDateStr(0),
handleDayClickStatus: false,
isFirst: true,
handleDayClickType: 'normal',
daysItem: [],//所选的第几周
days: [],//本月所有天数按周分割
weeksNum: null,//第几周
allDaysData: []
}
},
watch: {
selectDay:{
handler(newV, oldV) {
if(newV){
this.selectedMonth = new Date(newV).getMonth()+1;
let fullyear= new Date(newV).getFullYear();
this.actDate = new Date(newV).getDate();
this.actMonth = new Date(newV).getMonth()+1;
this.monthDays = this.allDaysData[this.selectedMonth - 1];
//this.initMultiWeek(age+'-'+ this.selectedMonth+'-'+this.actDate);
this.handleDayClick({year:fullyear,month:this.selectedMonth,content:this.actDate})
}
}
},
moreDataList: {
handler(newV, oldV) {
const isEqual = _.differenceBy(newV, oldV, 'date')
if (newV.length || isEqual.length !== 0) {
this.allDaysData = this.displayDaysPerMonthT(this.selectedYear)
this.monthDays = this.allDaysData[this.selectedMonth - 1]
this.days = []
for (let i = 0, len = this.monthDays.length; i < len; i += 7) {
this.days.push(this.monthDays.slice(i, i + 7))
}
this.daysItem = this.days[this.weeksNum]
}
}
},
selectedYear: {
handler(newV, oldV) {
if (+newV !== +oldV) {
console.log(newV, oldV)
this.allDaysData = this.displayDaysPerMonthT(newV)
this.$emit('changeDay', `${this.selectedYear}-${this.selectedMonth}`)
}
},
immediate: true
},
selectedMonth: {
handler(v) {
this.monthDays = this.allDaysData[this.selectedMonth - 1]
this.days = []
for (let i = 0, len = this.monthDays.length; i < len; i += 7) {
this.days.push(this.monthDays.slice(i, i + 7))
}
let actIndex = null
this.days[this.days.length - 1].forEach((item, index) => {
if (item.type === 'next' && actIndex == null) {
actIndex = index - 1
}
})
if (actIndex == null) actIndex = 6
this.lastDay = this.days[this.days.length - 1][actIndex].content
this.$emit('changeDay', `${this.selectedYear}-${this.selectedMonth}`)
},
immediate: true
}
},
computed: {
getDayIndex() {
return moment(`${this.selectedYear}-${this.selectedMonth}-${this.actDate}`).day()
}
},
created() {
},
mounted() {
this.monthDays = this.allDaysData[this.selectedMonth - 1]
this.$nextTick(() => {
this.weeksNum = this.getMonthWeek(this.selectedYear, this.selectedMonth, this.selectedDate) - 1
this.toggle(true);
this.initMultiWeek({year:DEFAULT_DAY.getFullYear(),month:DEFAULT_DAY.getMonth()+1, content:DEFAULT_DAY.getDate()});
})
},
methods: {
setDate(date) {
const index = this.moreDataList.findIndex(
(item) => item.date === date
)
if(index < 0) return;
if (this.moreDataList[index].className && this.moreDataList[index].className.indexOf('recent-update-days') !== -1) {
this.$set(this.moreDataList, index, {
date: date,
className: 'has-plan-day'
})
}
const formatDate = moment(date).format('YYYY-MM-DD')
const year = formatDate.slice(0, 4)
const month = formatDate.slice(5, 7)
const day = formatDate.slice(8, 10)
this.selectedYear = year
this.selectedMonth = month
this.actMonth = month
this.selectedDate = day
this.actDate = day
this.$nextTick(() => {
this.weeksNum = this.getMonthWeek(this.selectedYear, this.selectedMonth, this.selectedDate) - 1
this.toggle(true)
this.handleDayClick({
content: day,
type: 'normal',
isClick: true,
month: month,
year: year
}, true)
})
},
isAct(item) {
return item.content === this.actDate && item.type === 'normal' && this.selectedMonth === this.actMonth
},
getDateStr(AddDayCount, dateStr, type) {
// console.log('getDateStr', AddDayCount, dateStr, type)
let dd
if (!dateStr) {
dd = new Date()
} else {
// 判断是否为IOS
const isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
let formatDateStr = isIOS ? dateStr.replace(/-/g, '/') : dateStr
dd = new Date((formatDateStr.length < 12) ? formatDateStr + ' 00:00:00' : formatDateStr)
}
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
let y = dd.getFullYear()
let m
let d
if (type === 'lhRili') {
m = dd.getMonth() + 1
d = dd.getDate()
} else {
let currentMon = (dd.getMonth() + 1)
let getDate = dd.getDate()
m = currentMon
d = getDate
//m = currentMon < 10 ? '0' + currentMon : currentMon // 获取当前月份的日期,不足10补0
//d = getDate < 10 ? '0' + getDate : getDate // 获取当前几号,不足10补0
}
return y + '-' + m + '-' + d
},
findPreMonthDay() {
this.$nextTick(() => {
let actIndex = null
this.days[this.days.length - 1].forEach((item, index) => {
if (item.type === 'next' && actIndex == null) {
actIndex = index - 1
}
})
if (actIndex == null) actIndex = 6
this.handleDayClick(this.days[this.days.length - 1][actIndex])
})
},
findNextMonthDay() {
this.$nextTick(() => {
let actIndex = null
this.days[0].forEach((item, index) => {
if (item.type === 'normal' && actIndex == null) {
actIndex = index
}
})
if (actIndex == null) actIndex = 0
this.handleDayClick(this.days[0][actIndex])
})
},
preDay() {
const index = this.daysItem.findIndex(item => item.isClick === true)
if (this.type === 'week') {
//周切换
if (this.actDate === 1) {
//本月的第一周 需调用上一个月
this.pre()
this.findPreMonthDay()
return
}
if (index === 0) {
//所选周第一天
const item = this.days[this.weeksNum - 1]
this.pre()
this.handleDayClick(item[6])
return
}
//在本周直接切换
this.handleDayClick(this.daysItem[index - 1])
} else {
//月切换
let actDayIndex = null
let actDay = null
let actIndex = null
this.days.forEach((item, index) => {
item.forEach((v, i) => {
if (v.isClick && actIndex == null) {
actDayIndex = i
actDay = v.content
actIndex = index
}
})
})
if (+actDay === 1 && +actIndex === 0) {
//本月第一周
this.pre()
this.findPreMonthDay()
} else {
if (actDayIndex === 0) {
this.handleDayClick(this.days[actIndex - 1][6])
} else {
// 直接切换
this.handleDayClick(this.days[actIndex][actDayIndex - 1])
}
}
}
},
nextDay() {
const index = this.daysItem.findIndex(item => item.isClick === true)
if (this.type === 'week') {
//周切换
if (this.actDate === this.lastDay) {
//本月的第一周 需调用上一个月
this.next()
this.findNextMonthDay()
return
}
if (index === 6) {
//所选周最后一天
const item = this.days[this.weeksNum + 1]
this.next()
this.handleDayClick(item[0])
return
}
//在本周直接切换
this.handleDayClick(this.daysItem[index + 1])
} else {
//月切换
let actDayIndex = null
let actDay = null
let actIndex = null
this.days.forEach((item, index) => {
item.forEach((v, i) => {
if (v.isClick && actIndex == null) {
actDayIndex = i
actDay = v.content
actIndex = index
}
})
})
if (+actDay === this.lastDay) {
//本月最后一周
this.next()
this.findNextMonthDay()
} else {
if (actDayIndex === 6) {
this.handleDayClick(this.days[actIndex + 1][0])
} else {
// 直接切换
this.handleDayClick(this.days[actIndex][actDayIndex + 1])
}
}
}
},
setContent(month, content) {
if (!content) return ''
return `${this.selectedYear}-${month}-${content}` === this.today ? '今' : content
},
toggle(flag, toggleWeek) {
// this.days = []
// const monthDays = this.displayDaysPerMonthT(this.selectedYear)[this.selectedMonth - 1]
if (!flag || !this.isFirst) {
if (this.type === 'week' || this.actMonth !== this.selectedMonth) {
this.weeksNum = 0
} else {
this.weeksNum = this.getMonthWeek(this.selectedYear, this.selectedMonth, this.actDate) - 1
}
} else {
if (this.isFirst === false) this.isFirst = true
}
/* for (let i = 0, len = monthDays.length; i < len; i += 7) {
this.days.push(monthDays.slice(i, i + 7))
}*/
if (toggleWeek) this.weeksNum = this.days.length - 1
this.daysItem = this.days[this.weeksNum]
},
toggleType() {
if (this.type === 'week') {
this.type = 'month'
} else {
this.type = 'week'
// this.$emit('isWeek', true)
// this.days = []
// this.weeksNum = 0
// const monthDays = this.displayDaysPerMonthT(this.selectedYear)[this.selectedMonth - 1]
if (this.selectedMonth !== this.actMonth) {
this.weeksNum = 0
} else {
this.weeksNum = this.getMonthWeek(this.selectedYear, this.selectedMonth, this.actDate) - 1
}
// for (let i = 0, len = monthDays.length; i < len; i += 7) {
// this.days.push(monthDays.slice(i, i + 7))
// }
this.daysItem = this.days[this.weeksNum]
this.handleDayClickStatus = false
}
},
getMonthWeek(a, b, c) {
let date = new Date(a, parseInt(b) - 1, c), w = date.getDay(), d = date.getDate()
return Math.ceil((d + 6 - w) / 7)
},
displayDaysPerMonthT(year) {
//定义每个月的天数,如果是闰年第二月改为29天
let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) {
daysInMonth[1] = 29
}
let daysPreMonth = [].concat(daysInMonth)
daysPreMonth.unshift(daysPreMonth.pop())
let addDaysFromPreMonth = new Array(12).fill(null).map((item, index) => {
let day = new Date(year, index, 1).getDay()
if (day === 0) {
return 6
} else {
return day - 1
}
})
let total_calendar_list = new Array(12)
.fill([])
.map((month, monthIndex) => {
let addDays = addDaysFromPreMonth[monthIndex] + 1,
daysCount = daysInMonth[monthIndex],
daysCountPre = daysPreMonth[monthIndex],
monthDate = []
if (addDays >= 7) {
addDays = addDays - 7
}
let __month
let __year = year
monthIndex === 0 ? __month = 13 : __month = monthIndex + 1
monthIndex === 0 ? __year = --__year : __year
for (; addDays > 0; addDays--) {
let m = __month
let obj = {
content: daysCountPre--,
type: 'pre',
isClick: false,
month: --m,
year: __year
}
monthDate.unshift(obj)
}
for (let i = 0; i < daysCount;) {
let day = ++i
let obj = {
content: day,
type: 'normal',
isClick: (day === this.actDate && this.actMonth === monthIndex + 1),
className: this.isAddClass(day, monthIndex + 1, year),
month: monthIndex + 1,
year: year
}
monthDate.push(obj)
}
if (monthDate.length > 35) {
let _month
let _year = year
monthIndex === 11 ? _month = -1 : _month = monthIndex
monthIndex === 11 ? _year = ++_year : _year
for (let i = 42 - monthDate.length, j = 0; j < i;) {
let obj = {
content: ++j,
type: 'next',
isClick: false,
month: _month + 2,
year: _year
}
monthDate.push(obj)
}
} else {
let _month
let _year = year
monthIndex === 11 ? _month = -1 : _month = monthIndex
monthIndex === 11 ? _year = ++_year : _year
for (let i = 35 - monthDate.length, j = 0; j < i;) {
let obj = {
content: ++j,
type: 'next',
isClick: false,
month: _month + 2,
year: _year
}
monthDate.push(obj)
}
}
return monthDate
})
return total_calendar_list
},
hascontent(obj){
const index = this.multiSelectArr.findIndex(_=>_.day == obj.content && _.year == obj.year && _.month == obj.month);
if(index > -1){
return index + 1;
}else{
return false;
}
},
getAllWeekToday(d) {
const oneDayTime = 1000 * 60 * 60 * 24;
const today = new Date(d);
const todayDay = today.getDay() || 7; // 若那一天是周末时,则强制赋值为7
const startDate = new Date(
today.getTime() - oneDayTime * (todayDay - 1)
);
let dateList = [startDate];
for (let i = 0; i < 7; i++) {
dateList.push(new Date(startDate.getTime() + oneDayTime * i));
}
return dateList.map(_=>({year:new Date(_).getFullYear(),month:new Date(_).getMonth()+1,day:new Date(_).getDate()}));
},
handleDayClick(item, externalTrigger) {
const handleClickDay = `${item.year}-${addZero(item.month)}`
if (this.maxDate && this.minDate) {
if (!moment(moment(handleClickDay).format('YYYY-MM')).isBetween(this.minDate, this.maxDate, 'month', '[]')) {
return this.$message.error('超过最大期限了哦~')
}
}
console.log('item',item);
console.log('externalTrigger',externalTrigger)
this.selectedDate = Number(item.content)
this.actDate = Number(item.content)
if (item.type === 'normal') {
if (item.month !== this.selectedMonth) this.selectedMonth = item.month
this.actMonth = this.selectedMonth
this.selectedYear = item.year
this.handleDayClickStatus = false
}
if (item.type === 'next') {
let year = item.year
if (this.handleDayClickType !== item.type) {
let month = +this.selectedMonth + 1
this.actMonth = month === 13 ? '01' : month
this.selectedMonth = month === 13 ? '01' : month
if (month === 13) this.selectedYear = year
this.handleDayClickStatus = true
}
}
if (item.type === 'pre') {
let year = item.year
if (this.handleDayClickType !== item.type) {
if (item.month === 12) {
this.selectedYear = year
this.selectedMonth = 12
this.actMonth = 12
} else {
this.selectedMonth = item.month
this.actMonth = this.selectedMonth
}
this.handleDayClickStatus = true
}
}
let arr = _.cloneDeep(this.days)
for (const v of arr) {
for (const k of v) {
if (k.content === item.content && k.type === 'normal') {
k.isClick = true
// k.className = item.className
} else {
k.isClick = false
}
}
}
this.days = arr
this.daysItem = this.days[this.weeksNum]
this.handleDayClickType = item.type
if (this.isActiveClick) item.isActiveClick = true
if (!externalTrigger) this.$emit('handleDayClick', item)
this.initMultiWeek(item);
},
initMultiWeek(item){
if(this.multiSelect){ //多选 展示
this.multiSelectArr=this.getAllWeekToday(item.year+'-'+item.month+"-"+item.content);
console.log('this.multiSelectArr',this.multiSelectArr)
this.$emit('selectWeekFn',this.multiSelectArr)
}
},
next() {
this.type === 'week' ? this.handleNextWeek() : this.handleNextMonth(true)
},
pre() {
this.type === 'week' ? this.handlePreWeek() : this.handlePreMonth(undefined, true)
},
handleNextWeek() {
if (this.weeksNum === this.days.length - 1) {
this.handleNextMonth()
} else {
this.daysItem = this.days[this.weeksNum + 1]
this.weeksNum++
}
},
handlePreWeek() {
if (this.weeksNum === 0) {
this.handlePreMonth(true, undefined)
} else {
this.daysItem = this.days[this.weeksNum - 1]
this.weeksNum--
}
},
handlePreMonth(flag, _flag) {
this.handleDayClickType = 'normal'
if (this.handleDayClickStatus === false || _flag) {
if (this.minDate) {
if (`${this.selectedYear}-${addZero(this.selectedMonth)}` === moment(this.minDate).format('YYYY-MM')) {
return this.$message.error('超过最大期限了哦~')
}
}
if (+this.selectedMonth === 1) {
this.selectedYear = +this.selectedYear - 1
this.selectedMonth = 12
if (this.type === 'week') {
this.selectedDate = 31
} else {
this.selectedDate = 1
}
} else {
this.selectedMonth = --this.selectedMonth
if (this.type === 'week') {
this.selectedDate = this.mGetDate(this.selectedYear, this.selectedMonth - 1)
} else {
this.selectedDate = 1
}
}
} else {
this.handleDayClickStatus = false
}
if (this.type === 'week') {
this.toggle(true, true)
}
},
mGetDate(year, month) {
let d = new Date(year, month, 0)
return d.getDate()
},
handleNextMonth(flag) {
if (this.handleDayClickStatus === false || flag) {
if (this.maxDate) {
if (`${this.selectedYear}-${addZero(this.selectedMonth)}` === moment(this.maxDate).format('YYYY-MM')) {
return this.$message.error('超过最大期限了哦~')
}
}
if (+this.selectedMonth === 12) {
this.selectedYear = +this.selectedYear + 1
this.selectedMonth = 1
this.selectedDate = 1
} else {
this.selectedMonth = +this.selectedMonth + 1
this.selectedDate = 1
}
} else {
this.handleDayClickStatus = false
}
this.weeksNum = this.getMonthWeek(this.selectedYear, +this.selectedMonth, +this.selectedDate) - 1
// this.getMonthRecord(this.selectedYear, this.selectedMonth)
this.toggle()
},
isAddClass(day, month, year) {
if (!this.moreDataList.length) return
for (const v of this.moreDataList) {
if (+v.date.slice(8, 10) === +day && +v.date.slice(5, 7) === +month && +v.date.slice(0, 4) === +year) {
return v.className || ''
}
}
return ''
}
}
}
</script>
<style lang="scss" scoped>
.day-select-week{
background-color: rgba(88, 137, 251, 0.486274509803922);
height: 38px !important;
line-height: 38px !important;
// width: 12% !important;
p{
position: relative;
width: 32px !important;
height: 32px !important;
border-radius: 50%;
color: #fff !important;
text-align: center;
line-height: 32px;
}
}
.day-select-week1{
border-top-left-radius:20px;
border-bottom-left-radius:20px;
}
.day-select-week8{
border-top-right-radius:20px;
border-bottom-right-radius:20px
}
.calendar-container {
display: flex;
width: 340px;
flex-direction: column;
border-radius: 12px;
padding: 15px;
background-color: #fff;
margin-bottom: 10px;
.first-select{
border-top-left-radius:22px;
border-bottom-left-radius:22px;
}
.last-select{
border-top-right-radius:22px;
border-bottom-right-radius:22px;
}
.line {
margin-top: 10px;
margin-bottom: 0;
}
.calendar__header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0px 10px;
.toggle {
display: flex;
align-items: center;
.header__next {
transform: rotate(180deg);
margin-left: 15px;
}
.toggle-btn {
background-image: url("~assets/img/studyCenter/studyPlan/arrow.png");
background-repeat: no-repeat;
background-position: center center;
cursor: pointer;
width: 17px;
height: 28px;
border-radius: 0px 5px 5px 0px;
&:hover {
background: #F9F9F9;
}
}
}
.header__title {
p {
color: #2B2B2B;
margin: 0;
}
p:first-child {
font-size: 12px;
font-weight: 500;
span:first-child {
font-size: 38px;
letter-spacing: -5px;
}
span:last-child {
margin-left: 5px;
}
}
p:last-child {
font-size: 16px;
font-weight: 500;
span {
font-size: 14px;
color: #2B2B2B;
font-weight: normal;
}
}
}
/*
*/
}
.pre-shadow {
position: absolute;
left: 22px;
top: 0;
height: 100%;
width: 33px;
}
.next-shadow {
position: absolute;
right: 22px;
top: 0;
height: 100%;
width: 33px;
transform: rotate(180deg);
}
.calendar__main {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
position: relative;
.main__block {
width: 14.27%;
display: flex;
align-items: center;
//min-height: 44px;
height:44px;
justify-content: center;
color: #666666;
flex-shrink: 0;
position: relative;
cursor: pointer;
.dateNum {
color: #2B2B2B;
font-weight: 500;
}
}
.main__block-not {
.dateNum {
color: #B9C0C9;
}
}
.day-select {
/*background-color: #cce4ff;*/
}
.main__block-head {
width: 14.2%;
margin-top: 15px;
display: flex;
font-size: 12px;
color: #B7B7B7;
font-weight: 500;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
}
.toggle-calendar {
width: 138px;
display: flex;
justify-content: center;
margin-top: 50px;
color: #3A74FF;
font-size: 14px;
height: 30px;
cursor: pointer;
img {
width: 10px;
height: 10px;
margin-left: 3px;
position: relative;
top: 5px;
}
}
}
</style>
<style lang="scss">
.calendar-container {
}
</style>
<style>
</style>
</code></pre>
<pre><code class="language-markdown"> <Calendar
v-show="selectType=='day'"
id="calendar"
ref="calendar"
key="calendar1"
@handleDayClick="$emit('handleDayClick',$event)"
@changeDay="$emit('changeDay',$event)"
:maxDate="planMonthCalendarInfo.endMonth"
:minDate="planMonthCalendarInfo.startMonth"
:moreDataList="moreDataList"
:isActiveClick="true"
:selectDay="selectDay"
:notToggle="true"
>
<slot name="dayInfo">
</slot>
</Calendar></code></pre>