实现的日历效果图
话不多说,上代码!
<template>
<view class="page">
<safe-area></safe-area>
<view class="calendar-wrapper">
<view class="calendar-toolbar">
<text class="prev" onclick="prevMonth">〈</text>
<text class="current">{{currentDateStr}}</text>
<text class="next" onclick="nextMonth">〉</text>
</view>
<view class="calendar-week">
<text class="week-item" v-for="item of weekList" :key="item">{{item}}</text>
</view>
<view class="calendar-inner">
<text class="calendar-item" v-for="(item, index) of calendarList" :key="index" :class="this.changestyle(item.disable,item.value)"
onclick="selDate" :data-val="item.value" :data-status="item.disable" :data-num="item.date">{{item.date}}</text>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'calendar',
installed(){this.setCurrent();
this.calendarCreator();},
data() {
return{current:{},
weekList:['周日','周一','周二','周三','周四','周五','周六'],
shareDate: new Date(),
calendarList: [],
seldate:'点击抉择日期',
selweek:'待定',
}
},
computed: {
// 显示以后工夫
currentDateStr() {let { year, month} = this.current;
return `${year} 年 ${this.pad(month + 1)} 月 `;
}
},
methods: {selDate (e){// console.log(JSON.stringify(e.currentTarget.dataset.val));
let status = e.currentTarget.dataset.status;
let num = e.currentTarget.dataset.num;
if(status){
this.data.seldate = e.currentTarget.dataset.val;
this.getWeek();
if(num>7){this.prevMonth();
}
else{this.nextMonth();
}
}
else{
this.data.seldate = e.currentTarget.dataset.val;
this.getWeek();
// 从新加载一次日历 扭转款式
this.calendarCreator();}
this.fire('clickDate', this.data.seldate);
},
changestyle(status,date){if(status){return 'calendar-item-disabled';}
else{if(date == this.data.seldate){return 'calendar-item-checked';}
else{return 'calendar-item';}
}
},
// 判断以后月有多少天
getDaysByMonth(year, month) {// console.log("本月多少天:"+new Date(year, month + 1, 0).getDate());
return new Date(year, month + 1, 0).getDate();},
getFirstDayByMonths(year, month) {// console.log("本月第一天周几:"+new Date(year, month, 1).getDay());
return new Date(year, month, 1).getDay();},
getLastDayByMonth(year, month) {// console.log("本月最初一天周几:"+new Date(year, month + 1, 0).getDay());
return new Date(year, month + 1, 0).getDay();},
// 对小于 10 的数字,后面补 0
pad(str) {return str < 10 ? `0${str}` : str;
},
// 点击上一月
prevMonth() {
this.current.month--;
// 因为 month 的变动 会超出 0-11 的范畴,所以须要从新计算
this.correctCurrent();
// 生成新日期
this.calendarCreator();},
// 点击下一月
nextMonth() {
this.current.month++;
// 因为 month 的变动 会超出 0-11 的范畴,所以须要从新计算
this.correctCurrent();
// 生成新日期
this.calendarCreator();},
// 格式化工夫,与主逻辑无关
stringify(year, month, date) {let str = [year, this.pad(month + 1), this.pad(date)].join('-');
return str;
},
// 设置或初始化 current
setCurrent(d = new Date()) {let year = d.getFullYear();
let month = d.getMonth();
let date = d.getDate();
this.current = {
year,
month,
date
}
},
// 修改 current
correctCurrent() {let { year, month, date} = this.data.current;
let maxDate = this.getDaysByMonth(year, month);
// 预防其余月跳转到 2 月,2 月最多只有 29 天,没有 30-31
date = Math.min(maxDate, date);
let instance = new Date(year, month, date);
this.setCurrent(instance);
},
// 生成日期
calendarCreator() {
// 一天有多少毫秒
const oneDayMS = 24 * 60 * 60 * 1000;
let list = [];
let {year, month} = this.data.current;
// 以后月份第一天是星期几, 0-6
let firstDay = this.getFirstDayByMonths(year, month);
// 填充多少天
let prefixDaysLen = firstDay === 0 ? 7 : firstDay;
// 毫秒数
let begin = new Date(year, month, 1).getTime() - oneDayMS * prefixDaysLen;
// 以后月份最初一天是星期几, 0-6
let lastDay = this.getLastDayByMonth(year, month);
// 填充多少天,和星期的排放程序无关
let suffixDaysLen = lastDay === 0 ? 6 : 6 - lastDay;
// 毫秒数
let end = new Date(year, month + 1, 0).getTime() + oneDayMS * suffixDaysLen;
while (begin <= end) {
// 享元模式,防止反复 new Date
this.data.shareDate.setTime(begin);
let year = this.data.shareDate.getFullYear();
let curMonth = this.data.shareDate.getMonth();
let date = this.data.shareDate.getDate();
list.push({
year: year,
month: curMonth,
date: date,
disable: curMonth !== month,
value: this.stringify(year, curMonth, date)
});
begin += oneDayMS;
}
this.data.calendarList = list;
// console.log(JSON.stringify(this.data.calendarList));
},
// 获取选中日期的周几
getWeek(){let index =new Date(this.data.seldate).getDay();
let weekArr = ['星期天', '星期一', '星期二', '星期三', '星期四', '星期五','星期六'];
let week = weekArr[index];
this.data.selweek = week;
},
}
}
</script>
<style>
.page {height: 100%;}
.calendar-wrapper {
margin: 10px 10px 0 10px;
background-color:#3c40c6;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
max-height: 400px;
}
.calendar-toolbar {
padding: 10px 10px;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #fff;
}
.prev{
flex: 1;
text-align: center;
color: #fff;
}
.current {
flex: 1;
text-align: center;
color: #fff;
}
.next{
flex: 1;
text-align: center;
color: #fff;
}
.calendar-week {
padding: 5px 10px;
flex-flow: row nowrap;
justify-content: space-around;
align-items: center;
}
.week-item {
padding: 5px;
font-weight: bolder;
font-size: 12px;
color: #fff;
}
.calendar-inner{
padding: 10px 10px;
flex-flow: row wrap;
justify-content: space-around;
align-items: center;
}
.calendar-item {
width:14%;
font-weight: bolder;
text-align: center;
font-size: 15px;
color: #fff;
padding: 5px;
background-color: #3c40c6;
}
.calendar-item-disabled {
width:14%;
font-weight: bolder;
text-align: center;
font-size: 15px;
color: #999;
}
.calendar-item-checked {
width:14%;
font-weight: bolder;
text-align: center;
font-size: 15px;
color: #000000;
background-color: #ffffff;
border-radius: 5px;
}
</style>
其余页面援用
<template>
<view class="page">
<calendar onclickDate="getSelDate"></calendar>
<view>
<text> 以后日期是 </text>
<text>{today}</text>
</view>
</view>
</template>
<script>
import '../../components/calendar.stml'
export default {
name: 'test',
apiready(){},
data() {
return{today:''}
},
methods: {getSelDate(e){console.log(JSON.stringify(e));
this.data.today = e.detail;
api.toast({msg:'以后选中日期是:'+e.detail})
}
}
}
</script>
<style>
.page {height: 100%;}
</style>