前端最终规范


日历

<pre><code class="language-markdown"> &lt;template&gt; &lt;div class="calendar-container"&gt; &lt;div class="calendar__header"&gt; &lt;div class="header__title"&gt; &lt;p&gt; {{ selectedYear }}年&lt;/p&gt; &lt;p&gt;{{selectedMonth}}月{{actDate}}日 &lt;span&gt;星期{{calendarHeader[this.getDayIndex]}}&lt;/span&gt;&lt;/p&gt; &lt;/div&gt; &lt;div class="toggle"&gt; &lt;div class="header__pre toggle-btn" @click="pre"&gt;&lt;/div&gt; &lt;div class="header__next toggle-btn" @click="next"&gt;&lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;div class="line"/&gt; &lt;div class="calendar__main"&gt; &lt;div class="main__block-head" v-for="(item, index) in calendarHeader" :key="index" &gt; {{ item }} &lt;/div&gt; &lt;template v-if="type === 'month' "&gt; &lt;div :class=" `main__block ${ item.type === 'pre' || item.type === 'next' ? 'main__block-not' : '' } ${isAct(item) ? 'day-select':''} ${multiSelect &amp;&amp; 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}`" &gt; &lt;p class="dateNum"&gt;{{ setContent(item.month, item.content) }}&lt;/p&gt; &lt;/div&gt; &lt;/template&gt; &lt;template v-else&gt; &lt;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}`" &gt; &lt;p class="dateNum"&gt;{{ setContent(item.month, item.content) }}&lt;/p&gt; &lt;/div&gt; &lt;/template&gt; &lt;/div&gt; &lt;slot&gt; &lt;/slot&gt; &lt;/div&gt; &lt;/template&gt; &lt;script&gt; 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: () =&gt; [] }, 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 &lt; 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 &lt; len; i += 7) { this.days.push(this.monthDays.slice(i, i + 7)) } let actIndex = null this.days[this.days.length - 1].forEach((item, index) =&gt; { if (item.type === 'next' &amp;&amp; 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(() =&gt; { 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) =&gt; item.date === date ) if(index &lt; 0) return; if (this.moreDataList[index].className &amp;&amp; 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(() =&gt; { 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 &amp;&amp; item.type === 'normal' &amp;&amp; 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 &lt; 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 &lt; 10 ? '0' + currentMon : currentMon // 获取当前月份的日期,不足10补0 //d = getDate &lt; 10 ? '0' + getDate : getDate // 获取当前几号,不足10补0 } return y + '-' + m + '-' + d }, findPreMonthDay() { this.$nextTick(() =&gt; { let actIndex = null this.days[this.days.length - 1].forEach((item, index) =&gt; { if (item.type === 'next' &amp;&amp; actIndex == null) { actIndex = index - 1 } }) if (actIndex == null) actIndex = 6 this.handleDayClick(this.days[this.days.length - 1][actIndex]) }) }, findNextMonthDay() { this.$nextTick(() =&gt; { let actIndex = null this.days[0].forEach((item, index) =&gt; { if (item.type === 'normal' &amp;&amp; actIndex == null) { actIndex = index } }) if (actIndex == null) actIndex = 0 this.handleDayClick(this.days[0][actIndex]) }) }, preDay() { const index = this.daysItem.findIndex(item =&gt; 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) =&gt; { item.forEach((v, i) =&gt; { if (v.isClick &amp;&amp; actIndex == null) { actDayIndex = i actDay = v.content actIndex = index } }) }) if (+actDay === 1 &amp;&amp; +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 =&gt; 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) =&gt; { item.forEach((v, i) =&gt; { if (v.isClick &amp;&amp; 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 &lt; 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 &lt; 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 &amp;&amp; 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) =&gt; { 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) =&gt; { let addDays = addDaysFromPreMonth[monthIndex] + 1, daysCount = daysInMonth[monthIndex], daysCountPre = daysPreMonth[monthIndex], monthDate = [] if (addDays &gt;= 7) { addDays = addDays - 7 } let __month let __year = year monthIndex === 0 ? __month = 13 : __month = monthIndex + 1 monthIndex === 0 ? __year = --__year : __year for (; addDays &gt; 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 &lt; daysCount;) { let day = ++i let obj = { content: day, type: 'normal', isClick: (day === this.actDate &amp;&amp; this.actMonth === monthIndex + 1), className: this.isAddClass(day, monthIndex + 1, year), month: monthIndex + 1, year: year } monthDate.push(obj) } if (monthDate.length &gt; 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 &lt; 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 &lt; 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(_=&gt;_.day == obj.content &amp;&amp; _.year == obj.year &amp;&amp; _.month == obj.month); if(index &gt; -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 &lt; 7; i++) { dateList.push(new Date(startDate.getTime() + oneDayTime * i)); } return dateList.map(_=&gt;({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 &amp;&amp; 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 &amp;&amp; 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 &amp;&amp; +v.date.slice(5, 7) === +month &amp;&amp; +v.date.slice(0, 4) === +year) { return v.className || '' } } return '' } } } &lt;/script&gt; &lt;style lang="scss" scoped&gt; .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; &amp;: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; } } } &lt;/style&gt; &lt;style lang="scss"&gt; .calendar-container { } &lt;/style&gt; &lt;style&gt; &lt;/style&gt; </code></pre> <pre><code class="language-markdown"> &lt;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" &gt; &lt;slot name="dayInfo"&gt; &lt;/slot&gt; &lt;/Calendar&gt;</code></pre>

页面列表

ITEM_HTML