实现的日历效果图
话不多说,上代码!
<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>
现在,APICloud 官方正在举办 AVM 组件的征集大赛,通过审核就能获得一定的奖金,大家感兴趣的也可以去围观一下。传送门:https://www.apicloud.com/activity2205